Skip to content

Conversation

@YuliiaKovalova
Copy link
Member

@YuliiaKovalova YuliiaKovalova commented Jan 9, 2026

Fixes #12804

Summary

This PR implements the MSBUILD_LOGGING_ARGS environment variable feature as described in the design spec (#12805). This allows enabling binary logging collection in CI/CD pipelines without modifying project files or build scripts.

Motivation

In CI/CD environments, it's often desirable to enable diagnostic logging (binary logs) for all builds without:

Modifying project files or .rsp files on disk
Changing build scripts
Affecting local developer builds
This feature enables centralized build diagnostics configuration through environment variables.

Testing

Add comprehensive UT coverage .

connected to #12706

YuliiaKovalova and others added 5 commits January 9, 2026 11:00
Document the process for enabling binary logging in CI/CD pipelines
using environment variables, including supported arguments, argument
processing order, and implementation flow.

Fixes  #12804
@YuliiaKovalova YuliiaKovalova self-assigned this Jan 9, 2026
@YuliiaKovalova YuliiaKovalova marked this pull request as ready for review January 9, 2026 14:07
/// <summary>
/// Name of environment variable for logging level (warning or message).
/// </summary>
public const string MSBuildLoggingArgsLevelEnvVarName = "MSBUILD_LOGGING_ARGS_LEVEL";
Copy link
Member

@baronfel baronfel Jan 9, 2026

Choose a reason for hiding this comment

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

When we document MSBUILD_LOGGING_ARGS_LEVEL we need to be very clear on its use - this flag only controls the level of the diagnostic messages emitted when processing these envvar log arguments. That wasn't immediately clear to me just based on reading.

return IsBinaryLoggerSwitch(switchName) || string.Equals(switchName, "check", StringComparison.OrdinalIgnoreCase);
}

private static bool IsBinaryLoggerSwitch(string switchName) => string.Equals(switchName, "bl", StringComparison.OrdinalIgnoreCase) || string.Equals(switchName, "binarylogger", StringComparison.OrdinalIgnoreCase);
Copy link
Member

Choose a reason for hiding this comment

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

nit - instead of the string constants here we should be able to use the constants from the binlog command line switch definition itself?

int colonIndex = switchPart.IndexOf(':');
string switchName = colonIndex >= 0 ? switchPart.Substring(0, colonIndex) : switchPart;

return IsBinaryLoggerSwitch(switchName) || string.Equals(switchName, "check", StringComparison.OrdinalIgnoreCase);
Copy link
Member

Choose a reason for hiding this comment

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

and same for the 'check' switch.

<!-- **** MSBUILD_LOGGING_ARGS strings **** -->
<data name="LoggingArgsEnvVarUsing" xml:space="preserve">
<value>Using arguments from MSBUILD_LOGGING_ARGS environment variable: {0}</value>
<comment>LOCALIZATION: "MSBUILD_LOGGING_ARGS" should not be localized. {0} is the arguments from the environment variable.</comment>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<comment>LOCALIZATION: "MSBUILD_LOGGING_ARGS" should not be localized. {0} is the arguments from the environment variable.</comment>
<comment>LOCALIZATION: "MSBUILD_LOGGING_ARGS" should not be localized. {0} is a string with the command-line arguments from the environment variable.</comment>

/// <summary>
/// Value of the MSBUILD_LOGGING_ARGS_LEVEL environment variable.
/// </summary>
public static string? MSBuildLoggingArgsLevel => Environment.GetEnvironmentVariable(MSBuildLoggingArgsLevelEnvVarName);
Copy link
Member

Choose a reason for hiding this comment

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

I'd rather this return an enum (or even a bool) and put the string->logical-meaning logic here rather than at the consumer (xmake).

Comment on lines +2128 to +2134
string switchPart = arg.Substring(GetLengthOfSwitchIndicator(arg));

// Extract switch name (before any ':' parameter indicator)
int colonIndex = switchPart.IndexOf(':');
string switchName = colonIndex >= 0 ? switchPart.Substring(0, colonIndex) : switchPart;

return IsBinaryLoggerSwitch(switchName) || string.Equals(switchName, "check", StringComparison.OrdinalIgnoreCase);
Copy link
Member

Choose a reason for hiding this comment

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

change this to avoid allocating the substrings, by using Span<char> instead.

}
catch (Exception ex)
{
LogLoggingArgsMessage(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("LoggingArgsEnvVarError", ex.Message), emitAsMessage);
Copy link
Member

Choose a reason for hiding this comment

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

ex.Message is a bit of a smell--it drops stack info.

Do we know of anything that could happen in "normal operation" that would cause this? If so, it might be a better UX to have a terse error message. But if this is a last-chance no-idea-how-it-could-happen thing, we should probably log the stack so if it ever happens we can figure it out.

<comment>{StrBegin="MSBUILD : warning MSB1070: "}LOCALIZATION: "MSBUILD_LOGGING_ARGS" should not be localized. {0} is the unsupported argument.</comment>
</data>
<data name="LoggingArgsEnvVarError" xml:space="preserve">
<value>MSBUILD : error MSB1071: Error processing MSBUILD_LOGGING_ARGS environment variable: {0}</value>
Copy link
Member

Choose a reason for hiding this comment

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

do these codes actually get emitted in the warning case? I'm confused by the stripping call at the place they get logged.

baronfel
baronfel previously approved these changes Jan 9, 2026
@baronfel baronfel dismissed their stale review January 9, 2026 16:33

Should have just commented

@baronfel
Copy link
Member

baronfel commented Jan 9, 2026

Worth noting that the branch protections preventing merge aren't active on this branch due to the naming - if we're going to use the servicing/XXX pattern more should we go ahead and enable those protections for it?

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.

4 participants