Skip to content

Add structured task logging APIs - #14606

Draft
baronfel wants to merge 4 commits into
mainfrom
baronfel-structured-task-logging
Draft

Add structured task logging APIs#14606
baronfel wants to merge 4 commits into
mainfrom
baronfel-structured-task-logging

Conversation

@baronfel

@baronfel baronfel commented Aug 1, 2026

Copy link
Copy Markdown
Member

Context

TaskLoggingHelper supports lazy positional composite formats. However, C# interpolation evaluates and formats values before MSBuild can filter a message.

Interpolation also removes the source names that loggers can use for queries and groups.

This change follows the Microsoft.Extensions.Logging OriginalFormat model. It does not add a MEL package dependency or an EventId.

After recompilation, existing interpolated calls select the new handler overloads.

Public API

  • LogMessage, LogWarning, and LogError add interpolated string handler overloads.
  • The overloads support importance, codes, help links, and source locations.
  • LogStructuredMessage, LogStructuredWarning, and LogStructuredError support dynamic and non-C# callers.
  • TaskLoggingHelper.Named supplies a stable explicit hole name.
  • IStructuredBuildEventArgs exposes an invariant named template and ordered values with unique names.

Names and display text

Each event stores the named template as its display format.
The task formats each value one time with its current culture.
This operation makes the displayed message identical before and after transport.

The Message property creates the display text only when a consumer reads the property.
Reading Message does not remove the named template or its values.

Localized callers can supply an invariant template and an already-localized message.
The event stores an original-format override for this case.

The compiler supplies default names through CallerArgumentExpression.
The handler keeps identifiers and dotted paths.
It uses ValueN for other expressions.
It adds _2, _3, and subsequent suffixes to duplicate names.

Transport

The implementation uses dedicated structured message, warning, and error event types.
It does not add structured state to the existing extended event types.

Node packets serialize the original-format override and ordered name-value pairs directly.
Binary-log format version 28 adds three length-prefixed record kinds.
Each record stores names and values as separate string-table references.

This format preserves order and distinguishes a null value from an empty value.
It does not use JSON, dictionaries, synthetic keys, type tags, or copied value strings.

Central warning policy preserves structured state when it converts a warning to a message or an error.
This behavior covers NoWarn, MSBuildWarningsAsMessages, and warning-as-error settings.

Compatibility

  • Existing compiled tasks remain binary compatible.
  • Literal strings and preformatted variables keep their current overloads.
  • Positional composite-format calls keep their current overloads.
  • Code that uses a new overload requires the corresponding new Utilities assembly at runtime.
  • No new warnings or errors are introduced.
  • Codes, help links, source locations, warning suppression, and warning-as-error behavior remain unchanged.

Forward-compatible readers older than version 28 skip the new records.
These readers cannot display the skipped events.

Change Wave 18.11 controls the dedicated event types.
Set MSBUILDDISABLEFEATURESFROMVERSION=18.11 when a consumer requires an older reader.
This setting restores ordinary message, warning, and error event types.

Measurements

The measurements use BenchmarkDotNet ShortRun on .NET 11 arm64 with MemoryDiagnoser.

Scenario Existing behavior Dedicated structured event
Two-hole capture 45 ns / 184 B 104 ns / 344 B
Disabled interpolation 6.2 ns / 40 B 5.8 ns / 0 B
Capture and Message access 108 ns / 312 B 182 ns / 472 B
Event creation 31 ns / 184 B 31 ns / 168 B
Node serialization Not applicable 144 ns / 0 B
Node deserialization Not applicable 202 ns / 560 B

The original PR implementation allocated 2,160 B for a two-hole capture.
The dedicated implementation allocates 344 B.

The binary-log test writes 500 equivalent repeated events.

Representation Serialized bytes
Existing lazy composite 20,022
Dedicated structured record 20,561
Previous extended metadata 24,490

The dedicated record is 2.7% larger than existing lazy composite logging.
The extended-metadata design was 22.3% larger.

Structured logging improves queries and filtered-message allocation.
It is not a general binary-log size optimization.
It can reduce size when it replaces a fully formatted message or supports event aggregation.

An inventory found 807 built-in task logging call sites.
Only interpolated or preformatted call sites can benefit from automatic capture or source migration.

The 823.6 MiB reference binary log contains many lazy composite and resource messages.
The size estimate does not apply the microbenchmark ratio to the complete file.

Validation

  • The Utilities project builds for all target frameworks without warnings.
  • The full repository build completes without warnings.
  • All 21 TaskLoggingHelperTests pass.
  • All 16 framework structured-event tests pass.
  • All 58 engine serialization and node tests pass.
  • The warning-to-message and warning-to-error conversion tests pass.
  • The bootstrap sample project builds successfully.
  • Bootstrap MSBuild --help completes successfully.
  • git diff --check reports no errors.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 8c28147a-fe7a-4b4b-91f5-c436d1930d38
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 8c28147a-fe7a-4b4b-91f5-c436d1930d38
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 8c28147a-fe7a-4b4b-91f5-c436d1930d38
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 8c28147a-fe7a-4b4b-91f5-c436d1930d38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant