Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/Build.UnitTests/BackEnd/LoggingServicesLogMethod_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Logging;
using Shouldly;
using Xunit;
using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
Expand Down Expand Up @@ -1046,6 +1047,51 @@ public void LogBuildFinished()
buildEvent = new BuildFinishedEventArgs(string.Empty, null /* no help keyword */, true, service.ProcessedBuildEvent.Timestamp);
Assert.True(((BuildFinishedEventArgs)service.ProcessedBuildEvent).IsEquivalent(buildEvent));
}
[Fact]
public void LogBuildStartedLoggerNames()
{
ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1);
ConsoleLogger consoleLogger = new ConsoleLogger();
service.RegisterLogger(consoleLogger);

service.LogBuildStarted();
var enabledLogsEvent = service.AllProcessedBuildEvents
.OfType<BuildMessageEventArgs>()
.FirstOrDefault(e => e.Message?.Contains("ConsoleLogger") == true);
enabledLogsEvent.ShouldNotBeNull();
}
Comment thread
AlesProkop marked this conversation as resolved.

[Fact]
public void LogFilePathsPresentInFileLog()
{
using var env = TestEnvironment.Create();
var logFilePath = env.ExpectFile(".log").Path;

var fileLogger = new FileLogger { Parameters = "logfile=" + logFilePath };
var mockLogger = new MockLogger();

using (var collection = new ProjectCollection())
{
var project = ObjectModelHelpers.CreateInMemoryProject(collection, @"
<Project>
<Target Name=""Build"" />
</Project>");
project.Build(new ILogger[] { fileLogger, mockLogger }).ShouldBeTrue();
}

// Check that MockLogger captured a LoggerRegisteredEventArgs containing the file logger path
var registeredEvent = mockLogger.AllBuildEvents
.OfType<LoggerRegisteredEventArgs>()
.FirstOrDefault(e => e.Loggers.Any(l => l.LoggerName == nameof(FileLogger)));
registeredEvent.ShouldNotBeNull();
var fileLoggerDesc = registeredEvent.Loggers.First(l => l.LoggerName == nameof(FileLogger));
var expectedPath = Path.GetFullPath(logFilePath);
fileLoggerDesc.OutputFilePaths.ShouldContain(expectedPath);

// Check the file log itself contains the exact path
var fileLogContents = File.ReadAllText(logFilePath);
fileLogContents.ShouldContain(expectedPath);
}

[Fact]
public void LogBuildCanceled()
Expand Down Expand Up @@ -1795,6 +1841,11 @@ internal sealed class ProcessBuildEventHelper : LoggingService
/// to verify that a buildEvent was sent to ProcessLoggingEvent.
/// </summary>
private BuildEventArgs _processedBuildEvent;

/// <summary>
/// All events processed by ProcessLoggingEvent.
/// </summary>
internal List<BuildEventArgs> AllProcessedBuildEvents { get; } = new();
#endregion
#region Constructor
/// <summary>
Expand Down Expand Up @@ -1857,6 +1908,7 @@ protected internal override void ProcessLoggingEvent(object buildEvent)
if (buildEvent is BuildEventArgs buildEventArgs)
{
_processedBuildEvent = buildEventArgs;
AllProcessedBuildEvents.Add(buildEventArgs);
}
else if (buildEvent is KeyValuePair<int, BuildEventArgs> kvp)
{
Expand Down
7 changes: 7 additions & 0 deletions src/Build.UnitTests/BackEnd/NodePackets_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void VerifyEventType()
BuildCheckTracingEventArgs buildCheckTracing = new();
BuildCanceledEventArgs buildCanceled = new("message", DateTime.UtcNow);
WorkerNodeTelemetryEventArgs workerNodeTelemetry = new();
LoggerRegisteredEventArgs loggerRegistered = new(new List<RegisteredLoggerInfo> { new RegisteredLoggerInfo("FileLogger", new[] { @"C:\logs\build.log" }) });

VerifyLoggingPacket(buildFinished, LoggingEventType.BuildFinishedEvent);
VerifyLoggingPacket(buildStarted, LoggingEventType.BuildStartedEvent);
Expand Down Expand Up @@ -119,6 +120,7 @@ public void VerifyEventType()
VerifyLoggingPacket(buildCheckTracing, LoggingEventType.BuildCheckTracingEvent);
VerifyLoggingPacket(buildCanceled, LoggingEventType.BuildCanceledEvent);
VerifyLoggingPacket(workerNodeTelemetry, LoggingEventType.WorkerNodeTelemetryEvent);
VerifyLoggingPacket(loggerRegistered, LoggingEventType.LoggerRegisteredEvent);
}

private static BuildEventContext CreateBuildEventContext()
Expand Down Expand Up @@ -321,6 +323,11 @@ public void TestTranslation()
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
},
new GeneratedFileUsedEventArgs("path", "some content"),
new LoggerRegisteredEventArgs(new List<RegisteredLoggerInfo>
{
new RegisteredLoggerInfo("FileLogger", new[] { @"C:\logs\build.log" }),
new RegisteredLoggerInfo("BinaryLogger"),
}),
};
foreach (BuildEventArgs arg in testArgs)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Build.UnitTests/Graph/ResultCacheBasedBuilds_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void InvalidCacheFilesShouldLogError(byte[] cacheContents)
result.OverallResult.ShouldBe(BuildResultCode.Failure);

_logger.FullLog.ShouldContain("MSB4256:");
_logger.AllBuildEvents.Count.ShouldBe(6);
_logger.AllBuildEvents.Count.ShouldBe(8);
_logger.ErrorCount.ShouldBe(1);
}

Expand Down Expand Up @@ -564,8 +564,8 @@ public void NonExistingInputResultsCacheShouldLogError()

result.OverallResult.ShouldBe(BuildResultCode.Failure);

_logger.AllBuildEvents.Count.ShouldBe(6);
_logger.Errors.First().Message.ShouldContain("MSB4255:");
_logger.AllBuildEvents.Count.ShouldBe(8);
_logger.Errors.First().Message.ShouldContain("MSB4255:");
_logger.Errors.First().Message.ShouldContain("FileDoesNotExist1");
_logger.Errors.First().Message.ShouldContain("FileDoesNotExist2");
_logger.ErrorCount.ShouldBe(1);
Expand Down
68 changes: 68 additions & 0 deletions src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.Build.Experimental.BuildCheck.Infrastructure;
using Microsoft.Build.Framework;
using Microsoft.Build.Framework.Profiler;
using Microsoft.Build.Logging;
using Microsoft.Build.Shared;

using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
Expand Down Expand Up @@ -360,6 +361,13 @@ public void LogBuildStarted()

// Make sure we process this event before going any further
WaitForLoggingToProcessEvents();

// Register Loggers and print out all the enabled loggers.
if (!OnlyLogCriticalEvents)
{
LogEnabledLoggers();
RegisterLoggers();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It pains me to iterate the list twice. Could you collapse these to one method that emits both messages?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, will do.

}
}

/// <summary>
Expand Down Expand Up @@ -391,6 +399,66 @@ public void LogBuildFinished(bool success)
WaitForLoggingToProcessEvents();
}

/// <summary>
/// Logs the names of enabled logs (except for Forwarding logs).
/// </summary>
private void LogEnabledLoggers()
{
List<string> listOfLoggers = new();
foreach (ILogger logger in Loggers)
{
ILogger actualLogger = UnwrapLogger(logger);
listOfLoggers.Add(actualLogger.GetType().Name);
}
if (listOfLoggers.Count != 0)
{
var msgEvent = new BuildMessageEventArgs(
ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("LogEnabledLogs", string.Join(", ", listOfLoggers)),
null, null, MessageImportance.Low);
msgEvent.BuildEventContext = BuildEventContext.Invalid;
ProcessLoggingEvent(msgEvent);
}
}

/// <summary>
/// Logs the file paths of enabled logs.
/// </summary>
private void RegisterLoggers()
{
var loggerDescriptions = new List<RegisteredLoggerInfo>();
foreach (ILogger logger in Loggers)
{
ILogger actualLogger = UnwrapLogger(logger);

var outputFilePaths = new List<string>();
if (actualLogger is IFileOutputLogger fileLogger && !string.IsNullOrEmpty(fileLogger.OutputFilePath))
{
outputFilePaths.Add(fileLogger.OutputFilePath);
}

if (actualLogger is BinaryLogger bl && bl.AdditionalFilePaths != null)
Comment thread
AlesProkop marked this conversation as resolved.
Outdated
{
outputFilePaths.AddRange(bl.AdditionalFilePaths);
}

loggerDescriptions.Add(new RegisteredLoggerInfo(
loggerName: actualLogger.GetType().Name,
Comment thread
AlesProkop marked this conversation as resolved.
Outdated
outputFilePaths: outputFilePaths.Count > 0 ? outputFilePaths : null,
verbosity: actualLogger.Verbosity));
}

if (loggerDescriptions.Count > 0)
{
var registerEvent = new LoggerRegisteredEventArgs(loggerDescriptions);
registerEvent.BuildEventContext = BuildEventContext.Invalid;
ProcessLoggingEvent(registerEvent);
}
}
private ILogger UnwrapLogger(ILogger logger)
{
return logger is ReusableLogger reusable ? reusable.OriginalLogger : logger;
}

/// <inheritdoc />
public void LogBuildCanceled()
{
Expand Down
1 change: 1 addition & 0 deletions src/Build/Logging/BinaryLogger/BinaryLogRecordKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ public enum BinaryLogRecordKind
BuildCheckAcquisition,
BuildSubmissionStarted,
BuildCanceled,
LoggerRegistered,
Comment thread
AlesProkop marked this conversation as resolved.
Outdated
}
}
7 changes: 5 additions & 2 deletions src/Build/Logging/BinaryLogger/BinaryLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public sealed class BinaryLoggerParameters
/// text logs that erase a lot of useful information.
/// </summary>
/// <remarks>The logger is public so that it can be instantiated from MSBuild.exe via command-line switch.</remarks>
public sealed class BinaryLogger : ILogger
public sealed class BinaryLogger : ILogger, IFileOutputLogger
{
// version 2:
// - new BuildEventContext.EvaluationId
Expand Down Expand Up @@ -119,7 +119,7 @@ public sealed class BinaryLogger : ILogger

// The current version of the binary log representation.
// Changes with each update of the binary log format.
internal const int FileFormatVersion = 25;
internal const int FileFormatVersion = 26;
Comment thread
AlesProkop marked this conversation as resolved.

// The minimum version of the binary log reader that can read log of above version.
// This should be changed only when the binary log format is changed in a way that would prevent it from being
Expand Down Expand Up @@ -297,6 +297,9 @@ private static bool TryParsePathParameter(string parameter, out string filePath)

internal string FilePath { get; private set; }

/// <inheritdoc/>
string IFileOutputLogger.OutputFilePath => FilePath;

/// <summary>
/// Gets or sets additional output file paths. When set, the binlog will be copied to all these paths
/// after the build completes. The primary FilePath will be used as the temporary write location.
Expand Down
32 changes: 32 additions & 0 deletions src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ void HandleError(FormatErrorMessage msgFactory, bool noThrow, ReaderErrorType re
BinaryLogRecordKind.BuildCheckTracing => ReadBuildCheckTracingEventArgs(),
BinaryLogRecordKind.BuildCheckAcquisition => ReadBuildCheckAcquisitionEventArgs(),
BinaryLogRecordKind.BuildCanceled => ReadBuildCanceledEventArgs(),
BinaryLogRecordKind.LoggerRegistered => ReadLoggerRegisteredEventArgs(),
_ => null
};

Expand Down Expand Up @@ -1287,6 +1288,37 @@ private BuildEventArgs ReadBuildCanceledEventArgs()
return e;
}

private BuildEventArgs ReadLoggerRegisteredEventArgs()
{
var fields = ReadBuildEventArgsFields();
int count = ReadInt32();
var loggers = new List<RegisteredLoggerInfo>(count);
for (int i = 0; i < count; i++)
{
string loggerName = ReadDeduplicatedString()!;

LoggerVerbosity? verbosity = null;
if (ReadBoolean())
{
verbosity = (LoggerVerbosity)ReadInt32();
}

int pathCount = ReadInt32();
var outputFilePaths = new string[pathCount];
for (int j = 0; j < pathCount; j++)
{
outputFilePaths[j] = ReadDeduplicatedString()!;
}

loggers.Add(new RegisteredLoggerInfo(loggerName, outputFilePaths, verbosity));
}

var e = new LoggerRegisteredEventArgs(loggers);
SetCommonFields(e, fields);

return e;
}

/// <summary>
/// For errors and warnings these 8 fields are written out explicitly
/// (their presence is not marked as a bit in the flags). So we have to
Expand Down
24 changes: 24 additions & 0 deletions src/Build/Logging/BinaryLogger/BuildEventArgsWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ private BinaryLogRecordKind WriteCore(BuildEventArgs e)
case ProjectEvaluationFinishedEventArgs projectEvaluationFinished: return Write(projectEvaluationFinished);
case BuildCheckTracingEventArgs buildCheckTracing: return Write(buildCheckTracing);
case BuildCheckAcquisitionEventArgs buildCheckAcquisition: return Write(buildCheckAcquisition);
case LoggerRegisteredEventArgs loggerRegistered: return Write(loggerRegistered);
default:
// convert all unrecognized objects to message
// and just preserve the message
Expand Down Expand Up @@ -316,6 +317,29 @@ private BinaryLogRecordKind Write(BuildCanceledEventArgs e)
return BinaryLogRecordKind.BuildCanceled;
}

private BinaryLogRecordKind Write(LoggerRegisteredEventArgs e)
{
WriteBuildEventArgsFields(e);
Write(e.Loggers.Count);
foreach (var logger in e.Loggers)
{
WriteDeduplicatedString(logger.LoggerName);
Write(logger.Verbosity.HasValue);
if (logger.Verbosity.HasValue)
{
Write((int)logger.Verbosity.Value);
}

Write(logger.OutputFilePaths.Count);
foreach (var path in logger.OutputFilePaths)
{
WriteDeduplicatedString(path);
}
}

return BinaryLogRecordKind.LoggerRegistered;
}

private BinaryLogRecordKind Write(ProjectEvaluationStartedEventArgs e)
{
WriteBuildEventArgsFields(e, writeMessage: false);
Expand Down
11 changes: 9 additions & 2 deletions src/Build/Logging/FileLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ namespace Microsoft.Build.Logging
/// complex -- for example, there is parameter parsing in this class, plus in BaseConsoleLogger. However we have
/// to derive FileLogger from ConsoleLogger because it shipped that way in Whidbey.
/// </remarks>
public class FileLogger : ConsoleLogger
public class FileLogger : ConsoleLogger, IFileOutputLogger
{
#region Constructors

/// <summary>
/// Default constructor.
/// </summary>
Expand Down Expand Up @@ -239,6 +238,14 @@ private void ApplyFileLoggerParameter(string parameterName, string parameterValu
/// </summary>
private string _logFileName = "msbuild.log";

/// <summary>
/// The path to the log file.
/// </summary>
internal string FilePath => Path.GetFullPath(_logFileName);

/// <inheritdoc/>
string IFileOutputLogger.OutputFilePath => FilePath;

/// <summary>
/// fileWriter is the stream that has been opened on our log file.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/Build/Logging/IFileOutputLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Build.Logging
{
internal interface IFileOutputLogger
{
string OutputFilePath { get; }
Comment thread
AlesProkop marked this conversation as resolved.
Outdated
}
}
Loading
Loading