Files
TakeoutSaaS.AdminApi/src/Core/TakeoutSaaS.Shared.Web/Middleware/CorrelationIdMiddleware.cs

103 lines
2.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Shared.Abstractions.Diagnostics;
using TakeoutSaaS.Shared.Abstractions.Ids;
namespace TakeoutSaaS.Shared.Web.Middleware;
/// <summary>
/// 统一 TraceId/CorrelationId贯穿日志与响应。
/// </summary>
public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<CorrelationIdMiddleware> logger, IIdGenerator idGenerator)
{
private const string TraceHeader = "X-Trace-Id";
private const string SpanHeader = "X-Span-Id";
private const string RequestHeader = "X-Request-Id";
public async Task InvokeAsync(HttpContext context)
{
var ownsActivity = Activity.Current is null;
var activity = Activity.Current ?? new Activity("TakeoutSaaS.Request");
if (activity.Id is null)
{
activity.SetIdFormat(ActivityIdFormat.W3C);
activity.Start();
}
var traceId = activity.TraceId.ToString();
var spanId = activity.SpanId.ToString();
if (string.IsNullOrWhiteSpace(traceId))
{
traceId = ResolveTraceId(context);
}
context.TraceIdentifier = traceId;
TraceContext.TraceId = traceId;
TraceContext.SpanId = spanId;
context.Response.OnStarting(() =>
{
context.Response.Headers[TraceHeader] = traceId;
context.Response.Headers[SpanHeader] = spanId;
return Task.CompletedTask;
});
using (logger.BeginScope(new Dictionary<string, object>
{
["TraceId"] = traceId,
["SpanId"] = spanId
}))
{
try
{
await next(context);
}
finally
{
TraceContext.Clear();
if (ownsActivity)
{
activity.Stop();
}
}
}
}
private string ResolveTraceId(HttpContext context)
{
if (TryGetHeader(context, TraceHeader, out var traceId))
{
return traceId;
}
if (TryGetHeader(context, RequestHeader, out var requestId))
{
return requestId;
}
return idGenerator.NextId().ToString();
}
private static bool TryGetHeader(HttpContext context, string headerName, out string value)
{
if (context.Request.Headers.TryGetValue(headerName, out var values))
{
var headerValue = values.ToString();
if (!string.IsNullOrWhiteSpace(headerValue))
{
value = headerValue;
return true;
}
}
value = string.Empty;
return false;
}
}