Skip to content

Trace Correlation

thushxr edited this page Jun 27, 2026 · 1 revision

Trace Correlation

When one logical operation produces several log lines — an HTTP request, a Lambda invocation, a background job — you want to tie those lines together. Thushar.Logging does this with a trace id: a value that's automatically attached to every entry written within a scope.

Trace scopes

Wrap a unit of work in a using block. Every log inside it — text or JSON — carries the same traceId:

using (Log.BeginTraceScope())
{
    Log.Information("Processing started");
    DoWork();                              // any logs in here share the id too
    Log.Information("Processing finished");
}
2026-06-27 09:14:02.318 🟩 [INFO] [TraceId: 7f3c…a9] Processing started
2026-06-27 09:14:02.402 🟩 [INFO] [TraceId: 7f3c…a9] Processing finished
{"","traceId":"7f3c…a9","message":"Processing started"}
{"","traceId":"7f3c…a9","message":"Processing finished"}

When the block exits, the previous trace id is restored — so scopes nest correctly.

Bring your own id

BeginTraceScope() generates a new GUID by default, but you'll usually want to pass a meaningful id — a request id, a correlation header, a Lambda request id:

using (Log.BeginTraceScope(context.AwsRequestId))
{
    Log.Information("Handling event");
}

Setting the id without a scope

If you don't have a convenient using block (e.g. a Lambda handler that returns mid-method), set the id directly:

Log.SetTraceId(context.AwsRequestId);   // explicit id
Log.SetTraceId();                       // or a fresh GUID

Read the current id at any time:

string? current = Log.TraceId;          // null if none is set

How it flows across async/await

The trace id is stored in an AsyncLocal<string?>, so it follows the logical async flow. Code awaited inside a scope keeps the id; parallel, unrelated flows don't see each other's ids. This makes it safe in highly concurrent servers — two simultaneous requests each keep their own trace id.

using (Log.BeginTraceScope(requestId))
{
    await Step1Async();   // sees requestId
    await Step2Async();   // sees requestId
}

Showing / hiding the id

The traceId is only rendered when one is actually set, and only when the AddTraceId toggle is on (the default). Turn it off entirely with:

Log.Configure(o => o.AddTraceId(false));

Typical pattern: one scope per request/invocation

  • ASP.NET Core: open a scope in middleware around each request — see Integration Guides.
  • AWS Lambda: open a scope in the handler using context.AwsRequestId — see Integration Guides.

Clone this wiki locally