< Summary - Heimdall API

Information
Class: ArturRios.Heimdall.WebApi.Metrics.MetricsConfiguration
Assembly: ArturRios.Heimdall.WebApi
File(s): /home/runner/work/heimdall-api/heimdall-api/src/Presentation/ArturRios.Heimdall.WebApi/Metrics/MetricsConfiguration.cs
Line coverage
100%
Covered lines: 20
Uncovered lines: 0
Coverable lines: 20
Total lines: 89
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage
100%
Covered methods: 3
Fully covered methods: 3
Total methods: 3
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
AddHeimdallMetrics(...)100%22100%
UseHeimdallMetrics(...)100%22100%

File(s)

/home/runner/work/heimdall-api/heimdall-api/src/Presentation/ArturRios.Heimdall.WebApi/Metrics/MetricsConfiguration.cs

#LineLine coverage
 1using OpenTelemetry.Metrics;
 2using OpenTelemetry.Resources;
 3
 4namespace ArturRios.Heimdall.WebApi.Metrics;
 5
 6/// <summary>
 7///     Registers the OpenTelemetry metrics pipeline and mounts its Prometheus scrape endpoint. Both
 8///     halves live here rather than inline in <c>Startup</c> so the tests can build a host with
 9///     exactly this wiring and prove which requests reach the exporter — <c>Startup</c> itself
 10///     cannot be exercised on the metrics port, because the in-memory test server reports a local
 11///     port of <c>0</c> for every request.
 12/// </summary>
 13public static class MetricsConfiguration
 14{
 15    /// <summary>The <c>service.name</c> every series carries, so dashboards can tell this API apart.</summary>
 16    public const string ServiceName = "heimdall-api";
 17
 18    /// <summary>
 19    ///     Meters that ship inside the runtime and the frameworks the API already uses, subscribed to by
 20    ///     name. None of them costs a package: each is emitted whether or not anything listens, and
 21    ///     naming it here is what makes the exporter collect it.
 22    /// </summary>
 23    /// <remarks>
 24    ///     <list type="bullet">
 25    ///         <item>
 26    ///             <c>System.Runtime</c> — GC, heap, thread pool, exceptions, CPU. Built into .NET 9
 27    ///             and later, which is what replaces the OpenTelemetry.Instrumentation.Runtime package.
 28    ///         </item>
 29    ///         <item>
 30    ///             <c>Microsoft.AspNetCore.Server.Kestrel</c> — connections, queued requests, TLS
 31    ///             handshakes. <c>AddAspNetCoreInstrumentation</c> subscribes to it as well; it is named
 32    ///             again so removing that call would not quietly take the connection metrics with it.
 33    ///         </item>
 34    ///         <item>
 35    ///             <c>Microsoft.EntityFrameworkCore</c> — active contexts, queries, SaveChanges and
 36    ///             optimistic-concurrency failures (EF Core 9 and later).
 37    ///         </item>
 38    ///         <item>
 39    ///             <c>Npgsql</c> — connection pool usage, command duration and failures: the first
 40    ///             place a saturated or unreachable database shows.
 41    ///         </item>
 42    ///     </list>
 43    /// </remarks>
 244    private static readonly string[] BuiltInMeters =
 245    [
 246        "System.Runtime",
 247        "Microsoft.AspNetCore.Server.Kestrel",
 248        "Microsoft.EntityFrameworkCore",
 249        "Npgsql"
 250    ];
 51
 52    /// <summary>
 53    ///     Registers the metrics pipeline, or nothing at all when <paramref name="options" /> has
 54    ///     metrics switched off — no meter listener, no exporter, no collection cost.
 55    /// </summary>
 56    public static IServiceCollection AddHeimdallMetrics(this IServiceCollection services, MetricsOptions options)
 57    {
 90258        if (!options.Enabled)
 59        {
 160            return services;
 61        }
 62
 90163        services.AddOpenTelemetry()
 90164            .ConfigureResource(resource => resource.AddService(ServiceName))
 180265            .WithMetrics(metrics => metrics
 180266                .AddAspNetCoreInstrumentation()
 180267                .AddHttpClientInstrumentation()
 180268                .AddMeter(BuiltInMeters)
 180269                .AddPrometheusExporter());
 70
 90171        return services;
 72    }
 73
 74    /// <summary>
 75    ///     Mounts the scrape endpoint behind <see cref="MetricsOptions.IsScrapeRequest" />. It must be
 76    ///     called before anything else in the pipeline: the endpoint is a terminal branch, so a
 77    ///     request it takes never reaches CORS, rate limiting, authentication, authorization or MVC —
 78    ///     and, not being a controller action, it never appears in the OpenAPI document either.
 79    /// </summary>
 80    public static IApplicationBuilder UseHeimdallMetrics(this IApplicationBuilder app, MetricsOptions options)
 81    {
 90282        if (!options.Enabled)
 83        {
 184            return app;
 85        }
 86
 90187        return app.UseOpenTelemetryPrometheusScrapingEndpoint(options.IsScrapeRequest);
 88    }
 89}