78 lines
2.5 KiB
C#
78 lines
2.5 KiB
C#
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Primitives;
|
|
using System.Diagnostics;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace StellaOps.Excititor.WebService.Extensions;
|
|
|
|
internal static class ObservabilityExtensions
|
|
{
|
|
private const string TraceHeaderName = "X-Stella-TraceId";
|
|
private const string CorrelationHeaderName = "X-Stella-CorrelationId";
|
|
private const string LegacyCorrelationHeaderName = "X-Correlation-Id";
|
|
private const string CorrelationItemKey = "__stella.correlationId";
|
|
|
|
public static IApplicationBuilder UseObservabilityHeaders(this IApplicationBuilder app)
|
|
{
|
|
return app.Use((context, next) =>
|
|
{
|
|
var correlationId = ResolveCorrelationId(context);
|
|
context.Items[CorrelationItemKey] = correlationId;
|
|
|
|
context.Response.OnStarting(state =>
|
|
{
|
|
var httpContext = (HttpContext)state;
|
|
ApplyHeaders(httpContext);
|
|
return Task.CompletedTask;
|
|
}, context);
|
|
|
|
return next();
|
|
});
|
|
}
|
|
|
|
private static void ApplyHeaders(HttpContext context)
|
|
{
|
|
var traceId = Activity.Current?.TraceId.ToString() ?? context.TraceIdentifier;
|
|
if (!string.IsNullOrWhiteSpace(traceId))
|
|
{
|
|
context.Response.Headers[TraceHeaderName] = traceId;
|
|
}
|
|
|
|
var correlationId = ResolveCorrelationId(context);
|
|
if (!string.IsNullOrWhiteSpace(correlationId))
|
|
{
|
|
context.Response.Headers[CorrelationHeaderName] = correlationId!;
|
|
}
|
|
}
|
|
|
|
private static string ResolveCorrelationId(HttpContext context)
|
|
{
|
|
if (context.Items.TryGetValue(CorrelationItemKey, out var existing) && existing is string cached && !string.IsNullOrWhiteSpace(cached))
|
|
{
|
|
return cached;
|
|
}
|
|
|
|
if (TryReadHeader(context.Request.Headers, CorrelationHeaderName, out var headerValue) ||
|
|
TryReadHeader(context.Request.Headers, LegacyCorrelationHeaderName, out headerValue))
|
|
{
|
|
return headerValue!;
|
|
}
|
|
|
|
return context.TraceIdentifier;
|
|
}
|
|
|
|
private static bool TryReadHeader(IHeaderDictionary headers, string name, out string? value)
|
|
{
|
|
if (headers.TryGetValue(name, out StringValues header) && !StringValues.IsNullOrEmpty(header))
|
|
{
|
|
value = header.ToString();
|
|
return true;
|
|
}
|
|
|
|
value = null;
|
|
return false;
|
|
}
|
|
}
|