Condividi tramite


Logger di compilazione

I logger offrono un metodo per personalizzare l'output della compilazione e visualizzare messaggi, errori o avvisi in risposta a specifici eventi di compilazione. Ogni logger viene implementato come classe .NET che implementa l'interfaccia ILogger, definita nell'assembly Microsoft.Build.Framework.dll.

Per implementare un logger, è possibile utilizzare due diversi metodi:

  • Implementare direttamente l'interfaccia ILogger.

  • Derivare la classe dalla classe di supporto Logger, definita nell'assembly Microsoft.Build.Utilities.dll. L'oggetto Logger implementa ILogger e fornisce le implementazioni predefinite di alcuni membri di ILogger.

In questo argomento viene illustrato come scrivere un semplice logger che deriva dalla classe Logger e visualizza i messaggi sulla console come risposta a determinati eventi di compilazione.

Registrazione per gli eventi

Lo scopo di un logger è di raccogliere le informazioni sull'avanzamento della compilazione, come segnalato dal modulo di gestione della compilazione, e di riportare queste informazioni in maniera utile. Tutti i logger devono eseguire l'override del metodo Initialize, ovvero la posizione in cui il logger effettua la registrazione per gli eventi. Nell'esempio riportato di seguito il logger effettua la registrazione per gli eventi TargetStarted, ProjectStarted e ProjectFinished.

    public class MySimpleLogger : Logger
    {
        public override void Initialize(Microsoft.Build.Framework.IEventSource eventSource)
        {
            //Register for the ProjectStarted, TargetStarted, and ProjectFinished events
            eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
            eventSource.TargetStarted += new TargetStartedEventHandler(eventSource_TargetStarted);
            eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
        }

Risposta a eventi

Ora il logger è registrato per eventi specifici e dovrà gestire tali eventi quando questi si verificano. Per gli eventi ProjectStarted e ProjectFinished, il logger scrive semplicemente una breve frase e il nome del file di progetto implicato nell'evento. Tutti i messaggi provenienti dal logger vengono scritti nella finestra della console.

        void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
        {
            Console.WriteLine("Project Started: " + e.ProjectFile);         
        }

        void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
        {
            Console.WriteLine("Project Finished: " + e.ProjectFile);
        }

Risposta ai valori di dettaglio del logger

In alcuni casi può essere utile registrare le informazioni di un evento solo se l'opzione opzione /verbosity di MSBuild.exe contiene un determinato valore. In questo esempio il gestore dell'evento TargetStarted registra un messaggio solo se la proprietà Verbosity, impostata dall'opzione /verbosity, è uguale a LoggerVerbosity Detailed.

     void eventSource_TargetStarted(object sender, TargetStartedEventArgs e)
        {
            if (Verbosity == LoggerVerbosity.Detailed)
            {
                Console.WriteLine("Target Started: " + e.TargetName);
            }
        }

Specifica di un logger

Una volta compilato il logger in un assembly, è necessario specificare in MSBuild per utilizzare tale logger durante le compilazioni. Questa operazione viene eseguita utilizzando l'opzione /logger con MSBuild.exe. Per ulteriori informazioni sulle opzioni disponibili per MSBuild.exe, vedere Riferimenti alla riga di comando di MSBuild.

La seguente riga di comando compila il progetto MyProject.csproj e utilizza la classe logger implementata in SimpleLogger.dll. L'opzione /nologo nasconde l'intestazione e il messaggio del copyright, mentre l'opzione /noconsolelogger disattiva il logger di console predefinito di MSBuild.

MSBuild /nologo /noconsolelogger /logger:SimpleLogger.dll

La seguente riga di comando compila il progetto con lo stesso logger, ma con un livello di Verbosity specificato come Detailed.

MSBuild /nologo /noconsolelogger /logger:SimpleLogger.dll /verbosity:Detailed

Esempio

Descrizione

L'esempio riportato di seguito contiene il codice completo per il logger.

Codice

using System;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace SimpleLogger
{

    public class MySimpleLogger : Logger
    {
        public override void Initialize(Microsoft.Build.Framework.IEventSource eventSource)
        {
            //Register for the ProjectStarted, TargetStarted, and ProjectFinished events
            eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
            eventSource.TargetStarted += new TargetStartedEventHandler(eventSource_TargetStarted);
            eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
        }

        void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
        {
            Console.WriteLine("Project Started: " + e.ProjectFile);         
        }

        void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
        {
            Console.WriteLine("Project Finished: " + e.ProjectFile);
        }
        void eventSource_TargetStarted(object sender, TargetStartedEventArgs e)
        {
            if (Verbosity == LoggerVerbosity.Detailed)
            {
                Console.WriteLine("Target Started: " + e.TargetName);
            }
        }
    }
}

Esempio

Descrizione

Nell'esempio riportato di seguito viene illustrata l'implementazione di un logger che scrive il log in un file anziché visualizzarlo nella finestra di console.

Codice

using System;
using System.IO;
using System.Security;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace MyLoggers
{
    // This logger will derive from the Microsoft.Build.Utilities.Logger class, 
    // which provides it with getters and setters for Verbosity and Parameters, 
    // and a default empty Shutdown() implementation. 
    public class BasicFileLogger : Logger
    {
        /// <summary> 
        /// Initialize is guaranteed to be called by MSBuild at the start of the build 
        /// before any events are raised. 
        /// </summary> 
        public override void Initialize(IEventSource eventSource)
        {
            // The name of the log file should be passed as the first item in the 
            // "parameters" specification in the /logger switch.  It is required
            // to pass a log file to this logger. Other loggers may have zero or more than  
            // one parameters. 
            if (null == Parameters)
            {
                throw new LoggerException("Log file was not set.");
            }
            string[] parameters = Parameters.Split(';');
            
            string logFile = parameters[0];
            if (String.IsNullOrEmpty(logFile))
            {
                throw new LoggerException("Log file was not set.");
            }
            
            if (parameters.Length > 1)
            {
                throw new LoggerException("Too many parameters passed.");
            }
            
            try
            {
                // Open the file 
                this.streamWriter = new StreamWriter(logFile);
            }
            catch (Exception ex)
            {
                if
                (
                    ex is UnauthorizedAccessException
                    || ex is ArgumentNullException
                    || ex is PathTooLongException
                    || ex is DirectoryNotFoundException
                    || ex is NotSupportedException
                    || ex is ArgumentException
                    || ex is SecurityException
                    || ex is IOException
                )
                {
                    throw new LoggerException("Failed to create log file: " + ex.Message);
                }
                else
                {
                    // Unexpected failure 
                    throw;
                }
            }

            // For brevity, we'll only register for certain event types. Loggers can also 
            // register to handle TargetStarted/Finished and other events.
            eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
            eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
            eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
            eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
            eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
            eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
        }

        void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
        {
            // BuildErrorEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters 
            string line = String.Format(": ERROR {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
            WriteLineWithSenderAndMessage(line, e);
        }
        
        void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
        {
            // BuildWarningEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters 
            string line = String.Format(": Warning {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
            WriteLineWithSenderAndMessage(line, e);
        }

        void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
        {
            // BuildMessageEventArgs adds Importance to BuildEventArgs 
            // Let's take account of the verbosity setting we've been passed in deciding whether to log the message 
            if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal))
                || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal))
                || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))              
                )
            {
                WriteLineWithSenderAndMessage(String.Empty, e);
            }
        }

        void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
        {
            // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName 
            // To keep this log clean, this logger will ignore these events.
        }
        
        void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
        {
            // ProjectStartedEventArgs adds ProjectFile, TargetNames 
            // Just the regular message string is good enough here, so just display that.
            WriteLine(String.Empty, e);
            indent++;
        }

        void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
        {
            // The regular message string is good enough here too.
            indent--;
            WriteLine(String.Empty, e);
        }
        
        /// <summary> 
        /// Write a line to the log, adding the SenderName and Message 
        /// (these parameters are on all MSBuild event argument objects) 
        /// </summary> 
        private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
        {
            if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
            {
                // Well, if the sender name is MSBuild, let's leave it out for prettiness
                WriteLine(line, e);
            }
            else
            {
                WriteLine(e.SenderName + ": " + line, e);
            }
        }
        
        /// <summary> 
        /// Just write a line to the log 
        /// </summary> 
        private void WriteLine(string line, BuildEventArgs e)
        {
            for (int i = indent; i > 0; i--)
            {
                streamWriter.Write("\t");
            }
            streamWriter.WriteLine(line + e.Message);
        }
        
        /// <summary> 
        /// Shutdown() is guaranteed to be called by MSBuild at the end of the build, after all  
        /// events have been raised. 
        /// </summary> 
        public override void Shutdown()
        {
            // Done logging, let go of the file
            streamWriter.Close();
        }

        private StreamWriter streamWriter;
        private int indent;
    }
}

Vedere anche

Concetti

Recupero di log di compilazione con MSBuild

Altre risorse

Concetti relativi a MSBuild