Skip to content
Open
Show file tree
Hide file tree
Changes from 14 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
54 changes: 54 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,53 @@ 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 LoggersRegisteredEventArgs containing the file logger path
var registeredEvent = mockLogger.AllBuildEvents
.OfType<LoggersRegisteredEventArgs>()
.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);
fileLoggerDesc.LoggerTypeFullName.ShouldBe(typeof(FileLogger).FullName);
fileLoggerDesc.Parameters.ShouldBe(fileLogger.Parameters);

// 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 +1843,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 +1910,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();
LoggersRegisteredEventArgs loggersRegistered = 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(loggersRegistered, LoggingEventType.LoggersRegisteredEvent);
}

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 LoggersRegisteredEventArgs(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
75 changes: 74 additions & 1 deletion src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
Expand All @@ -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();
Comment thread
JanProvaznik marked this conversation as resolved.
Outdated
}
}

/// <summary>
Expand Down Expand Up @@ -391,6 +399,71 @@ 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);
Type loggerType = actualLogger.GetType();
listOfLoggers.Add(loggerType.FullName ?? loggerType.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);
Type loggerType = actualLogger.GetType();

var outputFilePaths = new List<string>();
if (actualLogger is IFileOutputLogger fileLogger)
{
foreach (string outputFilePath in fileLogger.OutputFilePaths)
{
if (!string.IsNullOrEmpty(outputFilePath))
{
outputFilePaths.Add(outputFilePath);
}
}
}

loggerDescriptions.Add(new RegisteredLoggerInfo(
loggerName: loggerType.Name,
outputFilePaths: outputFilePaths.Count > 0 ? outputFilePaths : null,
verbosity: actualLogger.Verbosity,
loggerTypeFullName: loggerType.FullName,
parameters: actualLogger.Parameters));
}

if (loggerDescriptions.Count > 0)
{
var registerEvent = new LoggersRegisteredEventArgs(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
3 changes: 2 additions & 1 deletion src/Build/Logging/BinaryLogger/BinaryLogRecordKind.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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
Expand Down Expand Up @@ -45,5 +45,6 @@ public enum BinaryLogRecordKind
BuildCheckAcquisition,
BuildSubmissionStarted,
BuildCanceled,
LoggersRegistered,
}
}
20 changes: 18 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,22 @@ private static bool TryParsePathParameter(string parameter, out string filePath)

internal string FilePath { get; private set; }

/// <inheritdoc/>
System.Collections.Generic.IReadOnlyList<string> IFileOutputLogger.OutputFilePaths
{
get
{
if (AdditionalFilePaths == null || AdditionalFilePaths.Count == 0)
{
return new[] { FilePath };
}

var outputFilePaths = new List<string>(AdditionalFilePaths.Count + 1) { FilePath };
outputFilePaths.AddRange(AdditionalFilePaths);
return outputFilePaths;
Comment thread
AlesProkop marked this conversation as resolved.
Outdated
}
}

/// <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
34 changes: 34 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.LoggersRegistered => ReadLoggersRegisteredEventArgs(),
_ => null
};

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

private BuildEventArgs ReadLoggersRegisteredEventArgs()
{
var fields = ReadBuildEventArgsFields();
int count = ReadInt32();
var loggers = new List<RegisteredLoggerInfo>(count);
for (int i = 0; i < count; i++)
{
string loggerName = ReadDeduplicatedString()!;
string loggerTypeFullName = ReadDeduplicatedString()!;
string parameters = 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, loggerTypeFullName, parameters));
}

var e = new LoggersRegisteredEventArgs(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
26 changes: 26 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 LoggersRegisteredEventArgs loggersRegistered: return Write(loggersRegistered);
default:
// convert all unrecognized objects to message
// and just preserve the message
Expand Down Expand Up @@ -316,6 +317,31 @@ private BinaryLogRecordKind Write(BuildCanceledEventArgs e)
return BinaryLogRecordKind.BuildCanceled;
}

private BinaryLogRecordKind Write(LoggersRegisteredEventArgs e)
{
WriteBuildEventArgsFields(e);
Write(e.Loggers.Count);
foreach (var logger in e.Loggers)
{
WriteDeduplicatedString(logger.LoggerName);
WriteDeduplicatedString(logger.LoggerTypeFullName);
WriteDeduplicatedString(logger.Parameters);
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.LoggersRegistered;
}

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/>
System.Collections.Generic.IReadOnlyList<string> IFileOutputLogger.OutputFilePaths => new[] { FilePath };

/// <summary>
/// fileWriter is the stream that has been opened on our log file.
/// </summary>
Expand Down
Loading
Loading