Freigeben über


Buildprotokollierungen

Mithilfe von Protokollierungen können Sie die Buildausgabe anpassen und Meldungen, Fehler oder Warnungen als Antwort auf bestimmte Buildereignisse anzeigen lassen. Jede Protokollierung wird als .NET-Klasse implementiert, durch die die in der Assembly Microsoft.Build.Framework.dll definierte ILogger-Schnittstelle eingerichtet wird.

Eine Protokollierung kann auf zwei Weisen implementiert werden:

  • Direktes Implementieren der ILogger-Schnittstelle

  • Ableiten der Klasse von der Logger-Hilfsklasse, die in der Assembly Microsoft.Build.Utilities.dll definiert ist. Logger implementiert ILogger und stellt Standardimplementierungen einiger ILogger-Member bereit.

In diesem Thema wird erläutert, wie Sie eine einfache Protokollierung schreiben, die von Logger abgeleitet wird und Konsolenmeldungen als Antwort auf bestimmte Buildereignisse anzeigt.

Registrieren für Ereignisse

Der Zweck einer Protokollierung besteht darin, Informationen zum Fortschritt des Buildvorgangs – so wie sie vom Buildmodul übermittelt werden – zu sammeln und diese Informationen in verständlicher Form mitzuteilen. Alle Protokollierungen müssen die Initialize-Methode überschreiben, in der die Protokollierung für Ereignisse registriert wird. In diesem Beispiel wird die Protokollierung für die Ereignisse TargetStarted, ProjectStarted und ProjectFinished registriert.

    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);
        }

Reagieren auf Ereignisse

Nachdem die Protokollierung für bestimmte Ereignisse registriert wurde, muss sie diese Ereignisse bei deren Auftreten verarbeiten. Bei dem ProjectStarted-Ereignis und dem ProjectFinished-Ereignis wird von der Protokollierung einfach ein kurzer Satz und der Name der mit dem Ereignis verknüpften Projektdatei geschrieben. Alle von der Protokollierung ausgegebenen Meldungen werden in das Konsolenfenster geschrieben.


        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);
        }

Werte für den Ausführlichkeitsgrad der Protokollierung, ab denen reagiert wird

In einigen Fällen möchten Sie vielleicht nur Informationen aus einem Ereignis protokollieren, wenn der Schalter /verbosity von MSBuild.exe einen bestimmten Wert enthält. In diesem Beispiel wird eine Meldung vom TargetStarted-Ereignishandler nur protokolliert, wenn die Verbosity-Eigenschaft, die mit dem /verbosity-Schalter festgelegt wird, gleich LoggerVerbosity Detailed ist.

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

Festlegen einer Protokollierung

Nachdem die Protokollierung in eine Assembly kompiliert wurde, müssen Sie MSBuild anweisen, diese Protokollierung während der Buildvorgänge zu verwenden. Dies geschieht mit dem /logger-Schalter von MSBuild.exe. Weitere Informationen zu den verfügbaren Schaltern für MSBuild.exe finden Sie unter MSBuild-Befehlszeilenreferenz.

Durch die folgende Befehlszeile wird das Projekt MyProject.csproj erstellt und die in SimpleLogger.dll implementierte Protokollierungsklasse verwendet. Durch den /nologo-Schalter werden Banner und Copyrightmeldungen ausgeblendet, und durch den /noconsolelogger-Schalter wird die Protokollierung der MSBuild-Standardkonsole deaktiviert.

MSBuild /nologo /noconsolelogger /logger:SimpleLogger.dll

Durch die folgende Befehlszeile wird das Projekt mit derselben Protokollierung, jedoch mit dem Verbosity-Grad Detailed erstellt.

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

Beispiel

Beschreibung

Das folgende Beispiel enthält den vollständigen Code für die Protokollierung.

Code

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);
            }
        }
    }
}

Beispiel

Description

Im folgenden Beispiel wird die Implementierung einer Protokollierung veranschaulicht, durch die das Protokoll in eine Datei geschrieben und nicht im Konsolenfenster angezeigt wird.

Code

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;
    }
}

Siehe auch

Konzepte

Übersicht über die Protokollierung in MSBuild

Weitere Ressourcen

MSBuild Concepts