Files
git.stella-ops.org/src/Concelier/StellaOps.Excititor.WebService/Extensions/ObservabilityExtensions.cs

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;
}
}