Reporting Metrics To Prometheus In ASP.NET Core

This short article shows how to use prometheus-net to create counters and save custom metrics from our ASP.NET Core application.

Background

 
While our applications are running, we should have some monitoring of metrics for both system and business levels, so that we can easily measure the usage and performance, and diagnose any problems.
 
In this article, we will discuss how to monitor ASP.NET Core Apps using Prometheus.
 

What is Prometheus?

 
Prometheus is an open source monitoring platform. It provides multiple functionalities to store, manipulate, and monitor metrics from our applications.
 
The following diagram illustrates the architecture of Prometheus and some of its ecosystem components.
 
Reporting Metrics To Prometheus In ASP.NET Core

Metrics

 
For Prometheus metrics in ASP NET Core, we will be using prometheus-net.
 
Let us start by installing it from NuGet.
  1. dotnet add package prometheus-net.AspNetCore  
Next, we need to register it on the Application Builder. 
  1. public class Startup  
  2. {  
  3.     // others ...  
  4.       
  5.     public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  6.     {  
  7.         // others ...  
  8.   
  9.         app.UseMetricServer();  
  10.     }  
  11. }  
When we run the application and navigate to /metrics, we will get some default metrics set up by prometheus-net.
 
Reporting Metrics To Prometheus In ASP.NET Core
 
We can customize our own metrics based on the above illustration. For example, we want to be able to measure the requests for each endpoint, method and their status code (200 for succeed and 500 for error).
 
Here, we will use a middleware to record the metrics with counter, one of the metric types provide by Prometheus.
  1. public class RequestMiddleware  
  2. {  
  3.     private readonly RequestDelegate _next;  
  4.     private readonly ILogger _logger;  
  5.   
  6.     public RequestMiddleware(  
  7.         RequestDelegate next  
  8.         , ILoggerFactory loggerFactory  
  9.         )  
  10.     {  
  11.         this._next = next;  
  12.         this._logger = loggerFactory.CreateLogger<RequestMiddleware>();  
  13.     }  
  14.       
  15.     public async Task Invoke(HttpContext httpContext)  
  16.     {  
  17.         var path = httpContext.Request.Path.Value;  
  18.         var method = httpContext.Request.Method;  
  19.   
  20.         var counter = Metrics.CreateCounter("prometheus_demo_request_total""HTTP Requests Total"new CounterConfiguration  
  21.         {  
  22.             LabelNames = new[] { "path""method""status" }  
  23.         });  
  24.   
  25.         var statusCode = 200;  
  26.   
  27.         try  
  28.         {  
  29.             await _next.Invoke(httpContext);  
  30.         }  
  31.         catch (Exception)  
  32.         {  
  33.             statusCode = 500;  
  34.             counter.Labels(path, method, statusCode.ToString()).Inc();  
  35.   
  36.             throw;  
  37.         }  
  38.           
  39.         if (path != "/metrics")  
  40.         {  
  41.             statusCode = httpContext.Response.StatusCode;  
  42.             counter.Labels(path, method, statusCode.ToString()).Inc();  
  43.         }  
  44.     }  
  45. }  
  46.   
  47. public static class RequestMiddlewareExtensions  
  48. {          
  49.     public static IApplicationBuilder UseRequestMiddleware(this IApplicationBuilder builder)  
  50.     {  
  51.         return builder.UseMiddleware<RequestMiddleware>();  
  52.     }  
  53. }  
Then, we should add this middleware on application builder so that we get our custom metrics.
  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  2. {  
  3.     // others ...  
  4.   
  5.     app.UseMetricServer();  
  6.   
  7.     app.UseRequestMiddleware();  
  8. }  
We also have to make some changes on the controller so, that we can record 500 status code.
  1. [HttpGet]  
  2. public ActionResult<IEnumerable<string>> Get()  
  3. {  
  4.     if(new System.Random().NextDouble() > 0.5)  
  5.     {  
  6.         throw new System.Exception("test exception");  
  7.     }  
  8.   
  9.     return new string[] { "value1""value2" };  
  10. }  
After re-running this application and visiting some endpoints, we will find out the metrics were recorded.
 
Reporting Metrics To Prometheus In ASP.NET Core

Setup And Run Prometheus

We will use docker to set up prometheus. 

  1. FROM prom/prometheus  
  2. ADD Prometheus/prometheus.yml /etc/prometheus/  
prometheus.yml is the configuration file that configures how prometheus collects the metrics.
 
The following configuration specifies that prometheus will collect metrics via scraping.
  1. scrape_configs:  
  2. - job_name: mydemo  
  3.   scrape_interval: 15s  
  4.   scrape_timeout: 10s  
  5.   metrics_path: /metrics  
  6.   scheme: http  
  7.   static_configs:  
  8.   - targets:  
  9.     - localhost:5000   
Now, let's take a look at the metrics via Prometheus Web UI.
 
Reporting Metrics To Prometheus In ASP.NET Core
 
We also can combine Prometheus and Grafana to make a more pretty visualization.
 
And in this sample, we just used Counter, one of the metric types of Prometheus. There are three other main metric types available in prometheus.
  • Gauge
  • Summary
  • Histogram
The choice of selecting the type depends on your data and reporting needs. Just avoid forcing data into one type, without investigating if another type is a better fit. 
 

Summary

 
This short article showed how to use Prometheus-net to create counters and save custom mertrics from our ASP.NET Core application.
I hope this article can help you!