Skip to content

Instantly share code, notes, and snippets.

@CSTDev
Last active October 2, 2019 09:37
Show Gist options
  • Save CSTDev/f0d900c6fa0f78d102231ad28cf71e0c to your computer and use it in GitHub Desktop.
Save CSTDev/f0d900c6fa0f78d102231ad28cf71e0c to your computer and use it in GitHub Desktop.
.Net core middleware for Prometheus metrics on all HTTP requests

.NET Core Prometheus Metrics Middleware

Middleware and Extension classes to allow instrumentation of all http requests to a given URL path.

Info

The middleware intercepts all http requests made to an endpoint adds a timer and gauge showing the duration and number of currently in progress requests, writing these to the default Metrics Registry.

It uses the /api path to indicate that the endpoint is one belonging to the application that should have these metrics added.

Usage

Presuming you're using an application that are built with ASP.NET Core...

  1. Create the two classes
  2. Add the required NuGet package -> prometheus-net.AspNetCore
  3. In your startup class, in the Configure method add
  app.UseMetricServer(); //Enables Prometheus metric gathering and enpoint at /metrics see https://github.com/prometheus-net/prometheus-net#
  app.UseMetricsMiddleware(); // Uses the Middleware to wrap requets
using Microsoft.AspNetCore.Http;
using Prometheus;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace mynamespace
{
/// <summary>
/// Middleware component to add a histogram and gague for each HTTP request API endpoint
/// </summary>
public class MetricsMiddleware
{
private readonly RequestDelegate Next;
/// <summary>
/// Contructor taking all dependencies
/// </summary>
/// <param name="next">Next delegate in the chain, where the request will be passed to</param>
public MetricsMiddleware(RequestDelegate next)
{
this.Next = next;
}
/// <summary>
/// Method called when this middleware is invoked
/// </summary>
/// <param name="context">HTTP request/response context</param>
/// <returns></returns>
public async Task InvokeAsync(HttpContext context)
{
var method = context.Request.Method;
var pathRegex = new Regex("api/(.*?)(/|\\?|$)");
var matches = pathRegex.Match(context.Request.Path.ToString());
// Skip adding any metrics if the endpoint isn't a /api/ endpoint
if (matches.Length <= 0 || matches.Groups.Count <= 0)
{
await this.Next(context);
return;
}
var path = matches.Groups[1].ToString();
var histogram = Metrics.CreateHistogram($"{path}_{method}_duration", $"Histogram timer of {method} calls to {path}");
var gauge = Metrics.CreateGauge($"{path}_{method}_gague", $"Number of {method} requests to {path} currently in progress");
// Time all requests and increment/decrement the gague
using (histogram.NewTimer())
{
gauge.Inc();
await this.Next(context);
gauge.Dec();
}
}
}
}
using Microsoft.AspNetCore.Builder;
namespace mynamespace
{
/// <summary>
/// Extension class to add metrics middleware to application
/// </summary>
public static class MetricsMiddlewareExtensions
{
/// <summary>
/// Adds the Metrics Middleware to the provided application
/// </summary>
/// <param name="builder">Application builder that provides the mechanisms to configure an application's request</param>
/// <returns>The provided application builder with the additional middleware</returns>
public static IApplicationBuilder UseMetricsMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MetricsMiddleware>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment