Vlad
Vlad

Reputation: 842

How to report Prometheus-net metrics in ASP.NET 4.7.1

How can I use prometheus-net in a regular ASP.NET 4.7.1 application ? In .Net Core is quite easy, but I cannot find a nice way of reporting the metrics to Grafana in 4.7.1

The ideal would be to have path /metrics where the metrics are reported.

I tried to create a rough test controller to run the MetricServer but I get an error.

// horrible test code
[RoutePrefix("metrics")]
public class MetricsController : ApiController
{
    static readonly MetricServer _server = new MetricServer(7777);

    static MetricsController()
    {
        _server.Start();
    }

    [Route("")]
    public async Task<IHttpActionResult> Get()
    {
        using (var client = new HttpClient())
        {
            var metrics = await client.GetAsync("http://localhost:7777/metrics");
            return Content(HttpStatusCode.OK, await metrics.Content.ReadAsStringAsync(),null, metrics.Content.Headers.ContentType.ToString());
        }
    }
}

System.Net.HttpListenerException: 'Access is denied'

Upvotes: 7

Views: 9407

Answers (3)

Appetere
Appetere

Reputation: 6261

With ASP.NET Framework, you can also create a stand-alone HttpHandler to provide your metrics endpoint.

First create the handler (typically store in App_Code directory):

/// <summary>
/// Prometheus metrics scraping endpoint.
/// </summary>
public class MetricsHandler : HttpTaskAsyncHandler
{
    public override async Task ProcessRequestAsync(HttpContext context)
    {
        // Uses pattern from Prometheus.MetricServer
        var response = context.Response;
        try
        {
            try
            {
                await Metrics.DefaultRegistry.CollectAndExportAsTextAsync(context.Response.OutputStream);
            }
            catch (ScrapeFailedException ex)
            {
                response.StatusCode = 503;
                if (!string.IsNullOrWhiteSpace(ex.Message))
                {
                    using (var streamWriter = new StreamWriter(response.OutputStream))
                    {
                        streamWriter.Write(ex.Message);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (!(ex is OperationCanceledException))
            {
                try
                {
                    response.StatusCode = 500;
                }
                catch
                {
                }
            }
        }
    }
}

Then register your handler in web.config:

<system.webServer>
<handlers>
  <add name="MetricsHandler" verb="*" path="metrics" type="<your-namespace>.MetricsHandler, <your-assembly-name>" resourceType="Unspecified" />
</handlers>
</system.webServer>

To get my handler code I looked at the Prometheus MetricServer implementation, combined with Rocklan's answer.

Upvotes: 1

Rocklan
Rocklan

Reputation: 8130

There is another way to do this. Instead of creating a new MetricServer at startup and calling it, you can just collect the metrics yourself by calling CollectAndExportAsTextAsync.

Just create a WebApi controller that looks something like this:

public class MetricsController : ApiController
{
    [Route("metrics")]
    [HttpGet]
    public async Task<HttpResponseMessage> AppMetrics()
    {
        using (MemoryStream ms = new MemoryStream())
        {
            await Metrics.DefaultRegistry.CollectAndExportAsTextAsync(ms);
            ms.Position = 0;

            using (StreamReader sr = new StreamReader(ms))
            {
                var allmetrics = await sr.ReadToEndAsync();

                return new HttpResponseMessage()
                {
                    Content = new StringContent(allmetrics, Encoding.UTF8, "text/plain")
                };
            }
        }
    }
}

Or you can just use my NuGet package that also gives you HTTP metrics and some SQL ones too - https://www.nuget.org/packages/prometheus-net.AspNet/

Upvotes: 6

phnx47
phnx47

Reputation: 635

MetricServer.Start() may throw an access denied exception on Windows if your user does not have the right to open a web server on the specified port. You can use the netsh command to grant yourself the required permissions:

netsh http add urlacl url=http://+:7777/metrics user=DOMAIN\user

Upvotes: 3

Related Questions