Skip to content

Commit 563c7b0

Browse files
authored
Log TaskParameterEvent for scalar parameters (#9908)
Fixes #9827 ### Context `TaskParameterEvent` with `TaskParameterMessageKind.TaskInput` is currently used only for parameters that are lists. Parameters that are simple strings are logged as a specially formatted low-importance message. The binlog viewer contains logic to recognize this special message and recover the Name and Value to be rendered in the viewer UI. Since we will use this event for analyzers, it would be unfortunate to add one more place with this suboptimal processing. ### Changes Made Unified the logic in `TaskExecutionHost` to log all parameters as `TaskParameterEvent` with `TaskParameterMessageKind.TaskInput`. The change is under a change wave check. ### Testing - Added a new unit test. - Compared diagnostic-level output with task parameter logging enabled with and without the change. No differences were found when passing null, empty, false, true, numeric, string, or stringified item list parameters. - Compared the appearance in binlog for the same sample values as above. No differences were observed. - Compared OrchardCore binlogs with and without the change. They're the same size and the only difference I found was in rendering the `SolutionConfigurationContents` parameter which is a string but the content _looks_ formatted so it was rendered incorrectly as a list of items. ### Notes As @KirillOsenkov pointed out in the issue, we don't really depend on the textual messages so we don't have to do any double-logging. The viewer can remove parsing the textual messages on its own schedule.
1 parent 8fa24d9 commit 563c7b0

File tree

6 files changed

+71
-33
lines changed

6 files changed

+71
-33
lines changed

documentation/wiki/ChangeWaves.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t
2323

2424
## Current Rotation of Change Waves
2525

26+
### 17.12
27+
- [Log TaskParameterEvent for scalar parameters](https://github.com/dotnet/msbuild/pull/9908)
28+
2629
### 17.10
2730
- [AppDomain configuration is serialized without using BinFmt](https://github.com/dotnet/msbuild/pull/9320) - feature can be opted out only if [BinaryFormatter](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) is allowed at runtime by editing `MSBuild.runtimeconfig.json`
2831
- [Warning on serialization custom events by default in .NET framework](https://github.com/dotnet/msbuild/pull/9318)
@@ -37,14 +40,12 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t
3740
- [Keep the encoding of standard output & error consistent with the console code page for ToolTask](https://github.com/dotnet/msbuild/pull/9539)
3841
- [Convert.ToString during a property evaluation uses the InvariantCulture for all types](https://github.com/dotnet/msbuild/pull/9874)
3942

40-
4143
### 17.8
4244
- [[RAR] Don't do I/O on SDK-provided references](https://github.com/dotnet/msbuild/pull/8688)
4345
- [Delete destination file before copy](https://github.com/dotnet/msbuild/pull/8685)
4446
- [Moving from SHA1 to SHA256 for Hash task](https://github.com/dotnet/msbuild/pull/8812)
4547
- [Deprecating custom derived BuildEventArgs](https://github.com/dotnet/msbuild/pull/8917) - feature can be opted out only if [BinaryFormatter](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) is allowed at runtime by editing `MSBuild.runtimeconfig.json`
4648

47-
4849
### 17.6
4950
- [Parse invalid property under target](https://github.com/dotnet/msbuild/pull/8190)
5051
- [Eliminate project string cache](https://github.com/dotnet/msbuild/pull/7965)

src/Build.UnitTests/BackEnd/TaskExecutionHost_Tests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Microsoft.Build.Execution;
1919
using Microsoft.Build.Framework;
2020
using Microsoft.Build.Shared;
21+
using Shouldly;
2122
using Xunit;
2223
using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
2324
using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;
@@ -1048,6 +1049,36 @@ public void TestTaskDictionaryOutputItems()
10481049
""");
10491050
ml.AssertLogContains("a=b");
10501051
}
1052+
1053+
[Fact]
1054+
public void TestTaskParameterLogging()
1055+
{
1056+
string customTaskPath = Assembly.GetExecutingAssembly().Location;
1057+
MockLogger ml = ObjectModelHelpers.BuildProjectExpectSuccess($"""
1058+
<Project>
1059+
<UsingTask TaskName=`TaskThatReturnsDictionaryTaskItem` AssemblyFile=`{customTaskPath}`/>
1060+
<ItemGroup>
1061+
<MyItem Include="item1"/>
1062+
<MyItem Include="item2"/>
1063+
</ItemGroup>
1064+
<Target Name=`Build`>
1065+
<TaskThatReturnsDictionaryTaskItem Key="a" Value="b" AdditionalParameters="@(MyItem)" />
1066+
</Target>
1067+
</Project>
1068+
""");
1069+
1070+
// Each parameter should be logged as TaskParameterEvent.
1071+
ml.TaskParameterEvents.Count.ShouldBe(3);
1072+
IList<string> messages = ml.TaskParameterEvents.Select(e => e.Message).ToList();
1073+
messages.ShouldContain($"{ItemGroupLoggingHelper.TaskParameterPrefix}Key=a");
1074+
messages.ShouldContain($"{ItemGroupLoggingHelper.TaskParameterPrefix}Value=b");
1075+
messages.ShouldContain($"{ItemGroupLoggingHelper.TaskParameterPrefix}\n AdditionalParameters=\n item1\n item2");
1076+
1077+
// Parameters should not be logged as messages.
1078+
messages = ml.BuildMessageEvents.Select(e => e.Message).ToList();
1079+
messages.ShouldNotContain(m => m.StartsWith(ItemGroupLoggingHelper.TaskParameterPrefix));
1080+
}
1081+
10511082
#endregion
10521083

10531084
#region ITestTaskHost Members

src/Build.UnitTests/BackEnd/TaskThatReturnsDictionaryTaskItem.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public sealed class TaskThatReturnsDictionaryTaskItem : Utilities.Task
1717
public string Key { get; set; }
1818
public string Value { get; set; }
1919

20+
public ITaskItem[] AdditionalParameters { get; set; }
21+
2022
public override bool Execute()
2123
{
2224
var metaValue = new MinimalDictionary<string, string>

src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,30 +1266,6 @@ private bool InitializeTaskVectorParameter(
12661266
return success;
12671267
}
12681268

1269-
/// <summary>
1270-
/// Variation to handle arrays, to help with logging the parameters.
1271-
/// </summary>
1272-
/// <remarks>
1273-
/// Logging currently enabled only by an env var.
1274-
/// </remarks>
1275-
private bool InternalSetTaskParameter(TaskPropertyInfo parameter, IList parameterValue)
1276-
{
1277-
if (LogTaskInputs &&
1278-
!_taskLoggingContext.LoggingService.OnlyLogCriticalEvents &&
1279-
parameterValue.Count > 0 &&
1280-
parameter.Log)
1281-
{
1282-
ItemGroupLoggingHelper.LogTaskParameter(
1283-
_taskLoggingContext,
1284-
TaskParameterMessageKind.TaskInput,
1285-
parameter.Name,
1286-
parameterValue,
1287-
parameter.LogItemMetadata);
1288-
}
1289-
1290-
return InternalSetTaskParameter(parameter, (object)parameterValue);
1291-
}
1292-
12931269
private static readonly string TaskParameterFormatString = ItemGroupLoggingHelper.TaskParameterPrefix + "{0}={1}";
12941270

12951271
/// <summary>
@@ -1303,14 +1279,31 @@ private bool InternalSetTaskParameter(
13031279

13041280
if (LogTaskInputs && !_taskLoggingContext.LoggingService.OnlyLogCriticalEvents)
13051281
{
1306-
// If the type is a list, we already logged the parameters
1307-
if (!(parameterValue is IList))
1282+
IList parameterValueAsList = parameterValue as IList;
1283+
bool legacyBehavior = !ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_12);
1284+
1285+
// Legacy textual logging for parameters that are not lists.
1286+
if (legacyBehavior && parameterValueAsList == null)
13081287
{
13091288
_taskLoggingContext.LogCommentFromText(
1310-
MessageImportance.Low,
1311-
TaskParameterFormatString,
1312-
parameter.Name,
1313-
ItemGroupLoggingHelper.GetStringFromParameterValue(parameterValue));
1289+
MessageImportance.Low,
1290+
TaskParameterFormatString,
1291+
parameter.Name,
1292+
ItemGroupLoggingHelper.GetStringFromParameterValue(parameterValue));
1293+
}
1294+
1295+
if (parameter.Log)
1296+
{
1297+
// Structured logging for all parameters that have logging enabled and are not empty lists.
1298+
if (parameterValueAsList?.Count > 0 || (parameterValueAsList == null && !legacyBehavior))
1299+
{
1300+
ItemGroupLoggingHelper.LogTaskParameter(
1301+
_taskLoggingContext,
1302+
TaskParameterMessageKind.TaskInput,
1303+
parameter.Name,
1304+
parameterValueAsList ?? new object[] { parameterValue },
1305+
parameter.LogItemMetadata);
1306+
}
13141307
}
13151308
}
13161309

src/Framework/ChangeWaves.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ internal static class ChangeWaves
2929
internal static readonly Version Wave17_6 = new Version(17, 6);
3030
internal static readonly Version Wave17_8 = new Version(17, 8);
3131
internal static readonly Version Wave17_10 = new Version(17, 10);
32-
internal static readonly Version[] AllWaves = { Wave17_4, Wave17_6, Wave17_8, Wave17_10 };
32+
internal static readonly Version Wave17_12 = new Version(17, 12);
33+
internal static readonly Version[] AllWaves = { Wave17_4, Wave17_6, Wave17_8, Wave17_10, Wave17_12 };
3334

3435
/// <summary>
3536
/// Special value indicating that all features behind all Change Waves should be enabled.

src/UnitTests.Shared/MockLogger.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ public sealed class MockLogger : ILogger
123123
/// </summary>
124124
public List<TaskFinishedEventArgs> TaskFinishedEvents { get; } = new List<TaskFinishedEventArgs>();
125125

126+
/// <summary>
127+
/// List of TaskParameter events
128+
/// </summary>
129+
public List<TaskParameterEventArgs> TaskParameterEvents { get; } = new List<TaskParameterEventArgs>();
130+
126131
/// <summary>
127132
/// List of BuildMessage events
128133
/// </summary>
@@ -362,6 +367,11 @@ public void LoggerEventHandler(object sender, BuildEventArgs eventArgs)
362367
TaskFinishedEvents.Add(taskFinishedEventArgs);
363368
break;
364369
}
370+
case TaskParameterEventArgs taskParameterEventArgs:
371+
{
372+
TaskParameterEvents.Add(taskParameterEventArgs);
373+
break;
374+
}
365375
case BuildMessageEventArgs buildMessageEventArgs:
366376
{
367377
BuildMessageEvents.Add(buildMessageEventArgs);

0 commit comments

Comments
 (0)