Skip to content

feat: add UTC timestamps to all console log entries - #3709

Open
Jerry Nixon (JerryNixon) with Copilot wants to merge 17 commits into
mainfrom
copilot/add-timestamp-to-logs
Open

Jerry Nixon (JerryNixon) with Copilot wants to merge 17 commits into
mainfrom
copilot/add-timestamp-to-logs

Conversation

Copilot AI commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Why make this change?

Console log output lacks timestamps, making it difficult to correlate events or determine when entries occurred — especially under high request volume.

What is this change?

Prepends an ISO 8601 UTC timestamp with millisecond precision to every console log entry:

2026-07-07T14:01:01.344Z info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost:5000/graphql - - -
2026-07-07T14:01:01.345Z dbug: Azure.DataApiBuilder.Core.AuthenticationHelpers.ClientRoleHeaderAuthenticationMiddleware[0]
      bfa3a6ee AuthN state: Anonymous. Role: Anonymous.
  • src/Service/Program.cs — Replaces AddConsole() with AddSimpleConsole(TimestampFormat, UseUtcTimestamp) in both GetLoggerFactoryForLogLevel (startup logger) and CreateHostBuilder.ConfigureLogging (web host logger). MCP stdio path additionally uses Services.Configure<ConsoleLoggerOptions> for stderr routing, keeping a single registered provider.
  • src/Cli/CustomLoggerProvider.cs — Prepends DateTime.UtcNow.ToString(UtcTimestampFormat) before the abbreviated level label in the CLI's custom console logger (both standard and MCP stdio paths). Timestamp format extracted to a named constant.
  • src/Cli.Tests/CustomLoggerTests.cs — Updates LogOutput_UsesAbbreviatedLogLevelLabels assertion from StartsWith to Contains since the timestamp now precedes the level label.

How was this tested?

  • Integration Tests
  • Unit Tests

Sample Request(s)

No REST/GraphQL/CLI request changes — output-only behavioral change visible when running dab start.

Copilot AI changed the title [WIP] Add timestamp to logs for better tracking feat: add UTC timestamps to all console log entries Jul 8, 2026
@JerryNixon
Jerry Nixon (JerryNixon) marked this pull request as ready for review July 8, 2026 17:54
Copilot AI review requested due to automatic review settings July 8, 2026 17:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to make console logs easier to correlate by prepending an ISO 8601 UTC timestamp (millisecond precision) to console output emitted by both the Service host and the CLI custom logger.

Changes:

  • Updated Service logging to use the console “simple” formatter with UTC timestamp settings (including MCP stdio stderr routing for the startup logger factory).
  • Updated the CLI custom console logger to prepend a UTC timestamp before the abbreviated log level label.
  • Adjusted CLI unit tests for the new timestamp-prefixed output (but the updated assertion is now too permissive).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/Service/Program.cs Switches console logging to include UTC timestamps; MCP stdio path continues to keep stdout clean.
src/Cli/CustomLoggerProvider.cs Prepends UTC timestamps to CLI log prefixes for both standard and MCP stdio modes.
src/Cli.Tests/CustomLoggerTests.cs Updates assertions to account for timestamps in log output.

Comment thread src/Cli/CustomLoggerProvider.cs Outdated
// Apply colors so the abbreviation matches the visual style of engine logs.
// try/finally guarantees the original colors are restored even if Write throws,
// otherwise the console would be left tinted (e.g. red on error) for subsequent output.
string mcpTimestamp = DateTime.UtcNow.ToString(UtcTimestampFormat);
Comment thread src/Cli/CustomLoggerProvider.cs Outdated
}

TextWriter writer = logLevel >= LogLevel.Error ? Console.Error : Console.Out;
string timestamp = DateTime.UtcNow.ToString(UtcTimestampFormat);
Comment thread src/Cli.Tests/CustomLoggerTests.cs Outdated
Comment on lines +80 to +81
Assert.IsTrue(actual.Contains(expectedPrefix),
$"Expected output to contain '{expectedPrefix}' but got: '{actual}'");
Comment thread src/Service/Program.cs Outdated
Comment on lines +198 to +202
logging.AddSimpleConsole(options =>
{
options.TimestampFormat = "yyyy-MM-dd'T'HH:mm:ss.fff'Z' ";
options.UseUtcTimestamp = true;
});

@aaronburtle aaronburtle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

@RubenCerna2079

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).

@RubenCerna2079

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).

@aaronburtle

Copy link
Copy Markdown
Contributor

Copilot

Please update the existing hot-reload integration tests to account for this logging migration.

These tests replace Console.Out after the host and console logger are constructed. The console provider retains its original writer, so switching the failure diagnostic from Console.WriteLine to the injected ILogger means the tests no longer capture that message and time out.

A local probe invoking the actual PR handler confirmed that the warning reaches the original writer, not the test’s replacement writer. The PR’s SQL integration check reports the same four failures:

  • HotReloadConfigConnectionString
  • HotReloadConfigDatabaseType
  • HotReloadValidationFail
  • HotReloadParsingFail

The corresponding base check passed 1,604 tests with zero failures; this PR passed 1,600 with four failures.

Prefer capturing logs through a test ILoggerProvider rather than synchronizing tests on global console output. Alternatively, establish console capture before constructing the host/logger, and restore the original streams in finally.

The production migration to ILogger is appropriate; the tests need to be adapted rather than reverting that change.

@aaronburtle

Copy link
Copy Markdown
Contributor

Copilot

Please preserve explicitly configured console formats rather than unconditionally assigning ConsoleLoggerOptions.FormatterName = "dab-utc-simple".

The normal host path always invokes this registration, overriding an existing Logging:Console:FormatterName setting.

A local probe through the actual host-logging configuration confirmed:

  • FormatterName=json produces valid JSON on the base revision, but plain text on this PR.
  • FormatterName=systemd produces systemd priority-prefixed records on the base revision, but plain text on this PR.

This is more than adding timestamps: it changes the output contract for deployments using structured-log collectors or systemd severity extraction.

Use the custom formatter for the default/simple path while respecting explicitly selected formats. Handle the UTC timestamp requirement appropriately within each supported format, rather than replacing all formats with plain text.

Please add configuration-based regression tests for JSON and systemd selection. The current default-registration tests do not catch this compatibility regression.

…constructed

Co-authored-by: aaronburtle <93220300+aaronburtle@users.noreply.github.com>

Copilot AI commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Copilot

Please update the existing hot-reload integration tests to account for this logging migration.
...

Fixed in 2cecd44.

Your diagnosis was right, and investigating it turned up an extra wrinkle worth flagging: the capturing-ILoggerProvider route you listed as the preferred option doesn't actually work here. I implemented it first, then found that ILogger<FileSystemRuntimeConfigLoader> is not resolved from the host's DI logging pipeline at all — Startup registers it through CreateLoggerFactoryForHostedAndNonHostedScenario, which calls Program.GetLoggerFactoryForLogLevel(...), and that builds a standalone LoggerFactory.Create(...) with its own AddConsole(). A provider added via ConfigureLogging is never consulted by that factory. Separately, the success message comes from BootstrapLogger, which writes to Console directly and so is invisible to any ILoggerProvider. A logger-provider sink would therefore have captured neither message.

So I took your second option, which covers both sinks uniformly. ClassInitializeAsync now calls StartCapturingConsole() before new TestServer(...), and ClassCleanup restores the original stream in a finally. The per-test arrange blocks changed from _writer = new StringWriter(); Console.SetOut(_writer); to ClearCapturedLogs() — the writer instance is created once and only its buffer is cleared, because replacing it would strand the console provider on the previous writer and reintroduce exactly this bug. The helpers are renamed accordingly (WriterContains → CapturedLogsContain), and _writer is now only touched inside them.

The capture writer tees to the original stream rather than swallowing it, so server-initialization and polling diagnostics still show up in CI output — with a plain StringWriter the redirect would have hidden them for the whole class.

No database in my sandbox, so I verified the mechanism with two probes instead of the integration tests:

  1. Reproduced the failure — host/console-logger constructed first, then Console.SetOut, then a warning through the injected ILogger: the replacement writer saw nothing while the message went to the original stdout.
  2. Verified the fix against the real shape (LoggerFactory.Create + AddConsole, capture established first, buffer cleared per test): both the injected-ILogger failure message and the direct-console success message were captured.

Since the four failures are DB-backed, the SQL integration run is the real confirmation — worth watching that check on this commit.

Co-authored-by: aaronburtle <93220300+aaronburtle@users.noreply.github.com>

Copilot AI commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Copilot

Please preserve explicitly configured console formats rather than unconditionally assigning ConsoleLoggerOptions.FormatterName = "dab-utc-simple".
...

Fixed in 81e99d5.

Reproduced first — with the unconditional assignment, both explicit selections were discarded:

requested json     -> effective FormatterName = dab-utc-simple
requested systemd  -> effective FormatterName = dab-utc-simple

AddUtcTimestampConsoleFormatter() now uses PostConfigure<ConsoleLoggerOptions> (which runs after the Logging:Console binding, so an explicitly configured value is visible) and only selects the DAB formatter when FormatterName is unset or simple:

requested <unset>  -> FormatterName=dab-utc-simple
requested simple   -> FormatterName=dab-utc-simple
requested json     -> FormatterName=json
requested systemd  -> FormatterName=systemd

For json/systemd the UTC timestamp is supplied through that format's own options (JsonConsoleFormatterOptions / ConsoleFormatterOptions), which the built-ins omit entirely unless TimestampFormat is set — so those formats keep their record shape and gain the timestamp. It reuses the same BootstrapLogger.UTC_TIMESTAMP_FORMAT constant. Neither shares an options type with SimpleConsoleFormatterOptions, so there is no cross-talk with the DAB formatter. It is applied only when no TimestampFormat was configured, so a deployment's own format wins — same "respect explicit configuration" principle as the fix itself.

The stdio factory and GetLoggerFactoryForLogLevel build standalone LoggerFactory.Create(...) pipelines with no configuration binding, so FormatterName is null there and the DAB formatter is still selected; MCP stdout isolation and single-provider registration are unchanged (ConfigureHostLogging_NormalMode_RegistersSingleConsoleProvider and the emit-exactly-once test stay green).

Tests in ConsoleLogTimestampTests, driven through configuration rather than by setting options directly:

  • ConfigureHostLogging_ExplicitJsonFormatter_EmitsTimestampedJsonRecord — parses the emitted line with JsonDocument and asserts LogLevel/Category/Message plus a Timestamp that passes the existing UTC assertion.
  • ConfigureHostLogging_ExplicitSystemdFormatter_EmitsTimestampedSystemdRecord — asserts the <6> syslog priority prefix survives and the timestamp that follows it is valid UTC.
  • ConfigureHostLogging_DefaultFormatter_SelectsUtcTimestampFormatter — unset / simple / Simple.
  • ConfigureHostLogging_ExplicitTimestampFormat_IsPreserved.

Mutation-checked both halves: restoring the unconditional assignment fails the json and systemd tests, and removing the TimestampFormat post-configuration fails the same two.

One caveat worth calling out. While testing this I found the json and systemd formatters have the same CurrentCulture bug that motivated UtcTimestampConsoleFormatter — they also render TimestampFormat via DateTimeOffset.ToString(format). Under th-TH:

json    : {"Timestamp":"2569-09-21T18:28:36.694Z",...}
systemd : <6>2569-09-21T18:28:37.332ZCat[0] hello

So those two formats are UTC and millisecond-precise but not calendar-invariant on a non-Gregorian host. Making them invariant would mean reimplementing both formatters (including JSON state/scope serialization), which seemed disproportionate for opt-in formats whose output contract belongs to the collector consuming them — and they were untimestamped entirely before this PR, so this is not a regression. I documented it in the ApplyUtcTimestampFormat remarks rather than silently leaving it. The default console path, the CLI logger, and BootstrapLogger remain fully invariant and are covered by the ar-SA/th-TH rows. Happy to implement invariant json/systemd variants if you'd rather close that gap.

Solution builds with 0 warnings, dotnet format --verify-no-changes is clean, 35 ConsoleLogTimestampTests/BootstrapLoggerTests and 8 CustomLoggerTests pass.

@aaronburtle

Copy link
Copy Markdown
Contributor

Copilot

The class-level capture change introduces another regression under the actual MSTest lifecycle.

MSTest replaces Console.Out between ClassInitialize and each test. The injected console logger retains the writer installed during class initialization, but BootstrapLogger writes through the current Console.Out. Consequently, injected warnings reach the capture while bootstrap success messages bypass it.

ClearCapturedLogs() only clears the buffer; it does not reattach the capture writer after MSTest replaces Console.Out.

Running the actual hot-reload integration class against an isolated SQL Server LocalDB instance produced 8 failures, 2 passes, and 3 skips. The parsing and validation failure tests now pass, but the eight tests requiring a success message time out.

To verify the cause, a temporary harness invoked the same ten original test methods, reattaching the same capture writer before each test and restoring the runner's writer afterward. All ten passed without changing product code or the original test methods.

Please preserve the provider-bound writer, reattach that same writer during TestInitialize, and restore the runner's per-test writer during TestCleanup. Do not create a replacement capture writer per test, since the provider would still hold the previous one.

Please validate the correction through the actual MSTest integration class, not just a standalone logging probe.

@aaronburtle

Copy link
Copy Markdown
Contributor

Copilot

The JSON/systemd format-selection fix works, but the newly supplied timestamps still do not satisfy the invariant ISO-8601 UTC requirement.

To distinguish this from a pre-existing issue: the built-in formatters' CurrentCulture behavior already existed. However, with only FormatterName=json or systemd configured, the base revision did not automatically add a timestamp. This PR now supplies the timestamp format, so this is a correctness defect in newly added behavior rather than a regression of previously correct timestamps.

With no user-supplied TimestampFormat, the updated PR emits:

  • th-TH: year 2569 instead of 2026.
  • ar-SA: year 1448 and a different calendar date.
  • fi-FI: time such as 07.14.23.155Z instead of the required colon-separated ISO time.

The Finnish case also shows that this is not limited to non-Gregorian calendars.

Please make DAB-generated timestamps invariant UTC with millisecond precision while preserving JSON/systemd record structure and intentional user-supplied timestamp overrides. Add coverage for these cultures on both formatters.

Documenting this behavior in implementation comments does not make the DAB-generated values satisfy the stated timestamp contract.

@aaronburtle

Copy link
Copy Markdown
Contributor

Copilot

The formatter-selection fix still breaks supported legacy console settings.

A null FormatterName does not necessarily mean that no console format was configured. The older ConsoleLoggerOptions settings still work in .NET 10 and worked in the PR base.

Verified differences:

  • Logging:Console:Format=Systemd previously produced systemd priority-prefixed records. This PR replaces them with the DAB text format.
  • Logging:Console:IncludeScopes=true previously included scopes. This PR omits them.

This compatibility regression was already present in the previous PR head, b2dfb45, and remains in 81e99d5. It is not a pre-existing bug on the base branch.

Please account for legacy settings when selecting and configuring the replacement formatter, preserving their behavior or mapping them to the equivalent formatter options. Add configuration-based tests for legacy Systemd selection and IncludeScopes.

Although these APIs are deprecated, that alone does not justify silently changing settings that the current runtime still supports.

Co-authored-by: aaronburtle <93220300+aaronburtle@users.noreply.github.com>

Copilot AI commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Copilot

The class-level capture change introduces another regression under the actual MSTest lifecycle.
...

Fixed in 2105d2a, and this time verified against the actual integration class rather than a probe — I got a SQL Server 2022/2025 container running in the sandbox, loaded DatabaseSchema-MsSql.sql, and ran ConfigurationHotReloadTests end to end.

Your diagnosis was exactly right. Console.SetOut also wraps the writer in a synchronized decorator, so detecting the runner's replacement needs the installed wrapper recorded rather than a reference comparison against the capture writer — that's what InstallCaptureWriter() does now.

Implemented as you specified: TestInitialize reattaches the same provider-bound instance (never a replacement, so the provider keeps feeding the buffer this class reads) and TestCleanup restores the runner's per-test writer. I also made the tee target mutable and pointed it at the runner's per-test writer for the duration of the test, so console output stays attributed to the running test instead of being diverted to the stream captured at class initialization; cleanup points it back at the class-level stream. Forwarding swallows ObjectDisposedException because the console logger writes from a background thread and can race the runner disposing its per-test writer — the buffer is already updated at that point, so a late tee write must not fail the test.

Results on the real class:

failed passed skipped
your run 8 2 3
this commit 1 9 3

Mutation check: reducing AttachCapturingConsole to a no-op makes HotReloadLogLevel time out at 120s again, and restoring it passes in 4s.

The one remaining failure is environmental, not a capture problem. HotReloadConfigDataSource appends Trusted_Connection=True; to the connection string, which requests Windows integrated auth:

OPEN OK   : base connection string
OPEN FAILS: with Trusted_Connection=True -> SqlException: The target principal name is incorrect. Cannot generate SSPI context.

So the reload genuinely fails validation in a Linux/SQL-auth sandbox and the test correctly waits for a success message that can never arrive. Notably the failure message was captured fine, which is itself evidence the capture path works — it's the product connection that can't succeed here. I'd expect this to pass on your LocalDB instance; worth confirming on your end since I can't reproduce Windows auth.

ConsoleLogTimestampTests/BootstrapLoggerTests (35) still pass, solution builds with 0 warnings, and dotnet format --verify-no-changes is clean.

…gacy ConsoleLoggerOptions support

Co-authored-by: aaronburtle <93220300+aaronburtle@users.noreply.github.com>

Copilot AI commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Copilot

The JSON/systemd format-selection fix works, but the newly supplied timestamps still do not satisfy the invariant ISO-8601 UTC requirement.
...

Fixed in d336455.

You were right that this is a defect in newly added behaviour, not a pre-existing one — the base revision emitted no timestamp at all for those formats, so the culture-dependent value only exists because this PR supplies it. Documenting it wasn't an acceptable resolution.

Reproduced through the real Program.ConfigureHostLogging before the fix:

json     th-TH : {"Timestamp":"2569-09-23T08:04:02.949Z", ...}
json     ar-SA : {"Timestamp":"1448-04-12T08:04:02.982Z", ...}
json     fi-FI : {"Timestamp":"2026-09-23T08.04.02.994Z", ...}
systemd  th-TH : <6>2569-09-23T08:04:03.027ZCat[0] hello
systemd  ar-SA : <6>1448-04-12T08:04:03.030ZCat[0] hello
systemd  fi-FI : <6>2026-09-23T08.04.03.036ZCat[0] hello

and after:

json     en-US/th-TH/ar-SA/fi-FI : {"Timestamp":"2026-09-23T08:14:47.7xxZ", ...}
systemd  en-US/th-TH/ar-SA/fi-FI : <6>2026-09-23T08:14:47.7xxZ Cat[0] hello

What changed. ApplyUtcTimestampFormat (which wrote TimestampFormat onto the built-in formatters' options) is gone. Instead there are now two more DAB formatters alongside the existing simple one — UtcTimestampJsonConsoleFormatter (dab-utc-json) and UtcTimestampSystemdConsoleFormatter (dab-utc-systemd) — which reproduce the built-in record structure (JSON object with Timestamp/EventId/LogLevel/Category/Message/Exception/State/Scopes; syslog priority prefix, single line, newline replacement) but render the timestamp themselves. AddUtcTimestampConsoleFormatter() maps simple→dab-utc-simple, json→dab-utc-json, systemd→dab-utc-systemd; a formatter name that isn't one of the three built-ins belongs to the deployment and is left alone.

All three share ConsoleFormatterShared.FormatTimestamp, so the timestamp contract is implemented once:

  • TimestampFormat unset → DAB supplies the value → stamp.UtcDateTime.ToString(BootstrapLogger.UTC_TIMESTAMP_FORMAT, CultureInfo.InvariantCulture).
  • TimestampFormat set → intentional override → built-in semantics preserved verbatim (current culture, and UseUtcTimestamp selects the zone). That also covers the separator: the DAB timestamp gets a space before the next field, a configured format does not, matching the built-in expectation that any trailing separator is part of the format string.

Process-wide culture is untouched, and the single-provider/MCP-stdout guarantees are unchanged (ConfigureHostLogging_NormalMode_RegistersSingleConsoleProvider and ConfigureHostLogging_StdioMode_WritesNothingToConsole stay green).

Coverage. ConfigureHostLogging_ExplicitJsonFormatter_EmitsTimestampedJsonRecord and ..._ExplicitSystemdFormatter_EmitsTimestampedSystemdRecord are now [DataRow]-driven over en-US, th-TH, ar-SA and fi-FI. I included fi-FI deliberately: it's Gregorian, so it proves the defect wasn't limited to alternative calendars. The existing globalization-invariant-mode guard was generalised accordingly (AssertCultureIsNonGregorian → AssertCultureAffectsTimestampRendering) so it fails loudly rather than passing vacuously on a culture whose difference is the separator. ConfigureHostLogging_ExplicitTimestampFormat_IsPreserved now also asserts on the emitted record, not just the bound option.

Mutation-checked: switching FormatTimestamp to CultureInfo.CurrentCulture fails exactly the th-TH/ar-SA/fi-FI rows on both formatters (and the pre-existing simple-format rows), and passes en-US — so the new rows are load-bearing.

44/44 in ConsoleLogTimestampTests + BootstrapLoggerTests, solution builds with 0 warnings, dotnet format --verify-no-changes clean.

Two notes worth your eye:

  • The JSON formatter uses the public ArrayBufferWriter<byte> rather than the runtime's internal PooledByteBufferWriter, so there's one extra buffer allocation per JSON record versus the built-in. JsonWriterOptions from JsonConsoleFormatterOptions is still honoured.
  • Utf8JsonWriter escapes control characters natively, so the JSON path needs no extra sanitisation; the systemd path replaces newlines first (as the built-in does) and then reuses the same SanitizeControlCharacters as the simple formatter.

Copilot

The formatter-selection fix still breaks supported legacy console settings.
...

Fixed in d336455.

Confirmed your reading of ConsoleLoggerProvider.ReloadLoggerOptions — a null FormatterName is load-bearing twice over: it selects the built-in formatter via the legacy Format member, and it gates UpdateFormatterOptions, which copies IncludeScopes/TimestampFormat/UseUtcTimestamp/DisableColors onto the selected formatter's options. Assigning a DAB formatter name disabled both. Reproduced through the real host logging path:

legacy Format=Systemd    : 2026-09-23T08:04:03.042Z info: Cat[0]
      hello                                                        <- DAB text, not <6> records
legacy IncludeScopes=true: 2026-09-23T08:04:03.053Z info: Cat[0]
      hello                                                        <- scope missing

After:

legacy Format=Systemd    : <6>2026-09-23T08:14:47.738Z Cat[0] hello
legacy IncludeScopes=true: 2026-09-23T08:14:47.739Z info: Cat[0]
      => MyScope
      hello

What changed. SelectUtcTimestampFormatter now resolves the requested format before overwriting it: when FormatterName is null/empty it derives the format from the legacy Format member (Systemd → systemd, otherwise simple) and records that the legacy path was in use, then maps the result onto the DAB formatter with the same record structure. Since selecting a DAB formatter suppresses the provider's own UpdateFormatterOptions, that copy is now performed explicitly by a post-configure on SimpleConsoleFormatterOptions, JsonConsoleFormatterOptions and ConsoleFormatterOptions — mapping IncludeScopes, TimestampFormat, UseUtcTimestamp, and DisableColors → ColorBehavior (Disabled : Default, matching the built-in, not Enabled). It applies only when the legacy path was taken, so a deployment configuring Logging:Console:FormatterOptions:* is unaffected. Obsolete member access is scoped with #pragma warning disable CS0618 since the repo builds warnings-as-errors.

Ordering is the one subtle part: the marker is populated by touching IOptionsMonitor<ConsoleLoggerOptions>.CurrentValue from inside the formatter-options post-configure, which runs the console options configure/post-configure chain synchronously. No cycle exists because nothing in the ConsoleLoggerOptions chain reads formatter options.

Coverage, all configuration-driven as you asked (through Logging:Console:*, not by setting options objects directly):

  • ConfigureHostLogging_LegacyFormatSystemd_EmitsTimestampedSystemdRecord — asserts both the selected formatter and that the emitted record is <6>-prefixed with a UTC timestamp.
  • ConfigureHostLogging_LegacyIncludeScopes_IncludesScopes — asserts the scope appears and that entries stay timestamped.
  • ConfigureHostLogging_LegacyTimestampFormat_IsPreserved — added because the same null-FormatterName gate covers the rest of the legacy members, not just the two you found; it would have regressed identically.

Mutation-checked individually: collapsing the legacy Format branch fails only the systemd selection test; forcing the marker to false fails the IncludeScopes and TimestampFormat tests. 44/44 green, 0 build warnings, dotnet format --verify-no-changes clean.

One judgement call to flag: legacy DisableColors is mapped but not covered by a test, because asserting on it requires driving Console.IsOutputRedirected (colours are already suppressed under test capture, so a test would pass for the wrong reason). Happy to add one behind an explicit ColorBehavior assertion on the bound options if you'd prefer it pinned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli telemetry feature requests/ bug reports related to telemetry

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Add timestamp to logs

5 participants