Journaux de génération
Les journaux vous offrent un moyen de personnaliser la sortie de votre génération et d'afficher des messages, erreurs ou avertissements en réponse à des événements de build spécifiques. Chaque journal est implémenté comme une classe .NET qui implémente l'interface ILogger qui est définie dans l'assembly Microsoft.Build.Framework.dll.
Vous pouvez suivre deux approches pour implémenter un journal :
Implémentez l'interface ILogger directement.
Dérivez votre classe de la classe d'assistance, Logger, qui est définie dans l'assembly Microsoft.Build.Utilities.dll. Logger implémente ILogger et fournit des implémentations par défaut de certains membres ILogger.
Cette rubrique explique comment écrire un journal simple qui dérive de Logger et affiche des messages dans la console en réponse à certains événements de build.
Inscription aux événements
Le but d'un journal est de rassembler des informations sur la progression de la génération telle qu'elle est rapportée par le moteur de génération, puis de rapporter ces informations de manière utile. Tous les journaux doivent substituer la méthode Initialize, qui correspond à l'endroit où le journal s'inscrit aux événements. Dans cet exemple, le journal s'inscrit aux événements TargetStarted, ProjectStarted et 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);
}
Réponse aux événements
À présent que le journal est inscrit pour des événements spécifiques, il doit gérer ces événements lorsqu'ils se produisent. Pour les événements ProjectStarted et ProjectFinished, le journal écrit simplement une courte expression et le nom du fichier projet impliqué dans l'événement. Tous les messages du journal sont écrits dans la fenêtre de la 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);
}
Réponse aux valeurs de commentaires du journal
Dans certains cas, vous pouvez souhaiter n'enregistrer que des informations d'un événement si le commutateur /verbosity de MSBuild.exe contient une certaine valeur. Dans cet exemple, le gestionnaire d'événements TargetStarted enregistre uniquement un message si la propriété Verbosity, qui est définie par le commutateur /verbosity, est égale à LoggerVerbosity Detailed.
void eventSource_TargetStarted(object sender, TargetStartedEventArgs e)
{
if (Verbosity == LoggerVerbosity.Detailed)
{
Console.WriteLine("Target Started: " + e.TargetName);
}
}
Spécification d'un journal.
Une fois que le journal est compilé dans un assembly, vous devez indiquer à MSBuild d'utiliser ce journal pendant les générations. Pour ce faire, utilisez le commutateur /logger avec MSBuild.exe. Pour plus d'informations sur les commutateurs disponibles pour MSBuild.exe, consultez Référence de la ligne de commande MSBuild.
La ligne de commande suivante génère le projet MyProject.csproj et utilise la classe de journalisation implémentée dans SimpleLogger.dll. Le commutateur /nologo masque la bannière et le message de copyright et le commutateur /noconsolelogger désactive le journal de console MSBuild par défaut.
MSBuild /nologo /noconsolelogger /logger:SimpleLogger.dll
La ligne de commande suivante génère le projet avec le même journal, mais avec le niveau de Verbosity Detailed.
MSBuild /nologo /noconsolelogger /logger:SimpleLogger.dll /verbosity:Detailed
Exemple
Description
L'exemple suivant contient le code complet pour le journal.
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);
}
}
}
}
Exemple
Description
L'exemple suivant indique comment implémenter un journal qui écrit le journal dans un fichier plutôt que de l'afficher dans la fenêtre de console.
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;
}
}
Voir aussi
Concepts
Obtention de journaux de génération avec MSBuild