빌드 로거Build Loggers

로거는 빌드 출력을 사용자 지정하고 특정 빌드 이벤트에 대한 응답에 메시지, 오류 또는 경고를 표시하는 방법을 제공합니다.Loggers provide a way for you to customize the output of your build and display messages, errors, or warnings in response to specific build events. 각 로거는 ILogger 인터페이스를 구현하는 .NET 클래스로 구현됩니다. 이 인터페이스는 Microsoft.Build.Framework.dll 어셈블리에서 정의됩니다.Each logger is implemented as a .NET class that implements the ILogger interface, which is defined in the Microsoft.Build.Framework.dll assembly.

로거를 구현할 때 다음 두 가지 방법을 사용할 수 있습니다.There are two approaches you can use when implementing a logger:

  • ILogger 인터페이스를 직접 구현합니다.Implement the ILogger interface directly.

  • 도우미 클래스 Logger에서 클래스를 파생합니다. 이 클래스는 Microsoft.Build.Utilities.dll 어셈블리에서 정의됩니다.Derive your class from the helper class, Logger, which is defined in the Microsoft.Build.Utilities.dll assembly. LoggerILogger를 구현하고 일부 ILogger 멤버의 기본 구현을 제공합니다.Logger implements ILogger and provides default implementations of some ILogger members.

    이 항목에서는 Logger에서 파생되는 단순 로거를 작성하는 방법을 설명하고 특정 빌드 이벤트에 대한 응답으로 콘솔에 메시지를 표시합니다.This topic will explain how to write a simple logger that derives from Logger, and displays messages on the console in response to certain build events.

이벤트 등록Registering for Events

로거의 목적은 빌드 엔진에 의해 보고되는 빌드 진행률에 대한 정보를 수집한 후 해당 정보를 유용한 방식으로 보고하는 것입니다.The purpose of a logger is to gather information on build progress as it is reported by the build engine, and then report that information in a useful way. 모든 로거는 로거가 이벤트를 등록하는 위치에 해당하는 Initialize 메서드를 재정의해야 합니다.All loggers must override the Initialize method, which is where the logger registers for events. 이 예제에서는 로거가 TargetStarted, ProjectStartedProjectFinished 이벤트를 등록합니다.In this example, the logger registers for the TargetStarted, ProjectStarted, and ProjectFinished events.

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

이벤트에 응답Responding to Events

로거를 특정 이벤트에 등록했으므로 이제 이벤트가 발생할 때 해당 이벤트를 처리해야 합니다.Now that the logger is registered for specific events, it needs to handle those events when they occur. ProjectStartedProjectFinished 이벤트에 대해 로거는 이벤트와 관련된 프로젝트 파일의 이름과 짧은 구를 간단히 씁니다.For the ProjectStarted, and ProjectFinished events, the logger simply writes a short phrase and the name of the project file involved in the event. 로거에서 발생한 모든 메시지는 콘솔 창에 기록됩니다.All messages from the logger are written to the console window.


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

로거 자세한 정도 값에 대한 응답Responding to Logger Verbosity Values

일부 경우에 MSBuild.exe /verbosity 스위치에 특정 값이 포함되어 있을 때만 이벤트의 정보를 로깅하려고 할 수 있습니다.In some cases, you may want to only log information from an event if the MSBuild.exe /verbosity switch contains a certain value. 이 예제에서 TargetStarted 이벤트 처리기는 /verbosity 스위치에 의해 설정된 Verbosity 속성이 LoggerVerbosityDetailed인 경우에만 메시지를 로깅합니다.In this example, the TargetStarted event handler only logs a message if the Verbosity property, which is set by the /verbosity switch, is equal to LoggerVerbosityDetailed.

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

로거 지정Specifying a Logger

로거가 어셈블리로 컴파일되면 빌드하는 동안 MSBuildMSBuild에 해당 로거를 사용하도록 지시해야 합니다.Once the logger is compiled into an assembly, you need to tell MSBuildMSBuild to use that logger during builds. 이 작업은 MSBuild.exe와 함께 /logger 스위치를 사용하여 수행합니다.This is done using the /logger switch with MSBuild.exe. MSBuild.exe에 대해 사용할 수 있는 스위치에 대한 자세한 내용은 명령줄 참조를 참조하세요.For more information on the switches available for MSBuild.exe, see Command-Line Reference.

다음 명령줄은 프로젝트 MyProject.csproj를 빌드하고 SimpleLogger.dll에서 구현된 로거 클래스를 사용합니다.The following command line builds the project MyProject.csproj and uses the logger class implemented in SimpleLogger.dll. /nologo 스위치는 배너 및 저작권 메시지를 숨기고 /noconsolelogger 스위치는 기본 MSBuildMSBuild 콘솔 로거를 사용하지 않도록 설정합니다.The /nologo switch hides the banner and copyright message and the /noconsolelogger switch disables the default MSBuildMSBuild console logger.

MSBuild /nologo /noconsolelogger /logger:SimpleLogger.dll  

다음 명령줄은 동일한 로거를 사용하지만 Verbosity 수준 Detailed를 사용하여 프로젝트를 빌드합니다.The following command line builds the project with the same logger, but with a Verbosity level of Detailed.

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

예제Example

설명Description

다음 예제에서는 로거에 대한 전체 코드를 보여 줍니다.The following example contains the complete code for the logger.

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

설명Comments

예제Example

설명Description

다음 예제에서는 로그를 콘솔 창에 표시하지 않고 파일에 쓰는 로거를 구현하는 방법을 보여 줍니다.The following example shows how to implement a logger that writes the log to a file rather than displaying it in the console window.

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

설명Comments

참고 항목See Also

빌드 로그 가져오기 Obtaining Build Logs
MSBuild 개념MSBuild Concepts