< Summary

Information
Class: ArturRios.Util.WebApi.Middleware.TraceActivityMiddleware
Assembly: ArturRios.Util.WebApi
File(s): D:\Repositories\dotnet-webapi-util\src\Middleware\TraceActivityMiddleware.cs
Line coverage
100%
Covered lines: 31
Uncovered lines: 0
Coverable lines: 31
Total lines: 65
Line coverage: 100%
Branch coverage
75%
Covered branches: 6
Total branches: 8
Branch coverage: 75%
Method coverage
100%
Covered methods: 3
Fully covered methods: 2
Total methods: 3
Method coverage: 100%
Full method coverage: 66.6%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.cctor()100%11100%
InvokeAsync()75%88100%

File(s)

D:\Repositories\dotnet-webapi-util\src\Middleware\TraceActivityMiddleware.cs

#LineLine coverage
 1using System.Diagnostics;
 2using Microsoft.AspNetCore.Http;
 3using Microsoft.Extensions.Logging;
 4
 5namespace ArturRios.Util.WebApi.Middleware;
 6
 7/// <summary>
 8/// Ensures every request is associated with a W3C-format <see cref="Activity"/>, propagating or creating one as
 9/// needed, and exposes its trace id on <see cref="HttpContext.TraceIdentifier"/>, <c>HttpContext.Items["TraceId"]</c>
 10/// and the response's <c>traceparent</c> header.
 11/// </summary>
 12/// <param name="next">The next middleware in the pipeline.</param>
 13/// <param name="logger">Used to log the start and end of each request's trace.</param>
 114public class TraceActivityMiddleware(RequestDelegate next, ILogger<TraceActivityMiddleware> logger) : WebApiMiddleware
 15{
 16    private const string TraceParentHeader = "traceparent";
 17
 18    static TraceActivityMiddleware()
 119    {
 120        Activity.DefaultIdFormat = ActivityIdFormat.W3C;
 121        Activity.ForceDefaultIdFormat = true;
 122    }
 23
 24    /// <summary>Attaches the current (or a newly created) trace activity to the context and response, then invokes the 
 25    /// <param name="context">The current HTTP context.</param>
 26    public async Task InvokeAsync(HttpContext context)
 127    {
 128        ArgumentNullException.ThrowIfNull(context);
 29
 130        var createdActivity = false;
 131        var activity = Activity.Current;
 32
 133        if (activity == null)
 134        {
 135            activity = new Activity("ServerReceive").SetIdFormat(ActivityIdFormat.W3C).Start();
 136            createdActivity = true;
 137        }
 38
 139        var traceId = activity.TraceId.ToString();
 40
 141        context.TraceIdentifier = traceId;
 142        context.Items["TraceId"] = traceId;
 43
 44
 145        var tp = $"00-{activity.TraceId}-{activity.SpanId}-{(activity.Recorded ? "01" : "00")}";
 46
 147        context.Response.Headers[TraceParentHeader] = tp;
 48
 149        logger.LogTrace("Started request with TraceId {TraceId}", traceId);
 50
 51        try
 152        {
 153            await next(context);
 154        }
 55        finally
 156        {
 157            logger.LogTrace("Ending request with TraceId {TraceId}", traceId);
 58
 159            if (createdActivity && Activity.Current == activity)
 160            {
 161                activity.Stop();
 162            }
 163        }
 164    }
 65}