Displaying Target Output Items Using The Console Logger

 In previous versions of MSBuild users could see the initial item and property values of projects in the build, this was useful to diagnose what values certain properties and items were set to. A requested addition to these items and properties was the ability to get view the values of the target output items on a target. This is useful because it allows the build author to view the state of the items being passed to the rest of the build from the target which has just completed. One of the features added in MSBuild 4.0 was the ability to retrieve the output items of a target when a target completes and display this information in a logger.

This post is intended for two audiences, first. If one wishes to enable the display of target output items in the default MSBuild console logger then the only action that is required is to set the environment variable MSBUILDTARGETOUTPUTLOGGINGto true .

 

Let us consider the following simple project which has a target that sets some outputs.

Note: In both cases we are using detailed logging

msbuild OutputLogging.proj /v:d

 

OutputLogging.proj

<?xml version="1.0" encoding="utf-8"?>

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Build" Outputs="@(TargetOutputs);$(AnotherOutput)">

    <ItemGroup>

      <TargetOutputs Include="TargetOutPut1"/>

      <TargetOutputs Include="TargetOutPut2"/>

      <TargetOutputs Include="TargetOutPut3">

        <Metadata1>Metadata1</Metadata1>

        <Metadata2>Metadata2</Metadata2>

        <Metadata3>Metadata3</Metadata3>

      </TargetOutputs>

    </ItemGroup>

    <PropertyGroup>

      <AnotherOutput>AnotherOutput</AnotherOutput>

    </PropertyGroup>

  </Target>

</Project>

Here is what the log looks like when target output logging is not enabled.

Project "C:\OutputLogging\OutputLogging.proj" on node 1 (default targets).
Building with tools version "4.0".
Target "Build" in project "C:\OutputLogging\OutputLogging.proj" (entry point):
Done building target "Build" in project "OutputLogging.proj".
Done Building Project "C:\OutputLogging\OutputLogging.proj" (default targets).

Here is the output with the target output logging enabled using the msbuild console logger.

Project "C:\OutputLogging\OutputLogging.proj" on node 1 (default targets).
Building with tools version "4.0".
Target "Build" in project "C:\OutputLogging\OutputLogging.proj" (entry point):
Target output items:
TargetOutPut1
TargetOutPut2
TargetOutPut3
Metadata1 = Metadata1
Metadata2 = Metadata2
Metadata3 = Metadata3
AnotherOutput
Done building target "Build" in project "OutputLogging.proj".
Done Building Project "C:\OutputLogging\OutputLogging.proj" (default targets).

As you can see we now see the output items when the target finished event is logged.

The second intended audience are authors of custom loggers. To get access to the target outputs in ones custom logger a new property on the TargetFinishedEventArgs has been added called TargetOutputs. This property is normally not set to anything, we chose not to enable the logging of the TargetOutputs by default because it does cause a performance hit due to additional object serialization during a multi-process build. When the environment variableMSBUILDTARGETOUTPUTLOGGING is set to true this field will be populated with a set of ITaskItems which are the output items for the target.

Custom loggers can get access to this event and use it as they see fit.

Though not the exact code in the logger, the algorithm to use the target output is as follows

In the event handler which is registered to receive the targetFinishedEventArgs in the custom logger.

targetOutputs = targetFinishedEvent.TargetOutputs;

foreach (ITaskItem item in targetOutputs)

{

    Console.Out.WriteLine(Item.ItemSpec);

}

One thing to note about this feature is when batching targets only the last target finished event for a given target will have the target outputs. For example if you have a target which that batches three times then you will get two target finished events where the targetOutputs is null and the last one will have the set out output items for ALL batches. The reason we only have the outputs on the last batch is because of the way the target outputs are gathered by the MSBuild engine. They are only gathered after all of the batches are completed. For this reason during the batch we do not have access to the final target outputs.