Skip to content

Correlate .NET logger trace id with active span (th-de3805)#170

Open
brentrager wants to merge 1 commit into
mainfrom
dotnet-log-trace-correlation
Open

Correlate .NET logger trace id with active span (th-de3805)#170
brentrager wants to merge 1 commit into
mainfrom
dotnet-log-trace-correlation

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

The .NET logger seeded traceId with a fabricated uuid (equal to correlationId) at construction. When a log is emitted inside an active distributed trace, the JSON logs (CloudWatch) did not carry the real trace id, so they couldn't be correlated to the trace.

Solution

At emit time, when an active W3C System.Diagnostics.Activity is in scope, stamp the entry's traceId (and a new spanId) with the span's real W3C ids. Captured at emit time, not construction — the span is live at the log call, not necessarily when the logger was created. Falls back to the prior behavior (fabricated uuid traceId, no spanId) when no W3C activity is active.

  • SmooLogger.Emit: override traceId + add spanId from Activity.Current (W3C format only).
  • New ContextKey.SpanId ("spanId").
  • Depends only on the BCL diagnostics API (Activity) — not on @smooai/observability (that would be circular). Logger lines already flow through the ForwardTo ILogger the obs provider hooks, so when the observability OTel logging provider is active a logger line becomes an OTLP log record carrying the same ids.

Verification

Log_Within_Active_Activity_Carries_Real_TraceAndSpanId starts a real ActivitySource span, logs, parses the JSON output, and asserts traceId/spanId equal activity.TraceId/SpanId hex. Log_Without_Activity_Falls_Back_To_Correlation_Uuid asserts the fallback (traceId == correlationId, no spanId).

dotnet build (net8/9/10, warnings-as-errors), dotnet test (35 passed, 2 new), and dotnet format --verify-no-changes all green in Release.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S2bM94GAnVjYSSv1x7HKRB

The .NET logger seeded traceId with a fabricated uuid (== correlationId) at
construction. When a log is emitted inside an active distributed trace, stamp
the real W3C trace/span id from System.Diagnostics.Activity.Current instead, so
CloudWatch JSON logs correlate to the trace. Captured at emit time — the span is
live at the log call, not necessarily when the logger was created. Falls back to
the prior traceId (fabricated uuid, no spanId) when no W3C activity is in scope.

- SmooLogger.Emit: override traceId + add spanId from Activity.Current (W3C only).
- New ContextKey.SpanId ("spanId").
- Depends only on the BCL diagnostics API (Activity) — no @smooai/observability
  dependency (would be circular). Logger lines already flow through the ForwardTo
  ILogger the obs provider hooks, so an active obs provider turns them into OTLP
  log records with matching ids.

Tests prove a log inside an active Activity carries the span's trace/span id, and
that it falls back to the correlation uuid with no activity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S2bM94GAnVjYSSv1x7HKRB
@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c89e100

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

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