justeattakeaway / JustEat.StatsD

Our library for publishing metrics to statsd
Apache License 2.0
27 stars 6 forks source link

Provide Integration with `System.Diagnostics.Metrics` #341

Open slang25 opened 3 years ago

slang25 commented 3 years ago

Microsoft are introducing a new set of metrics APIs, which could potentially be used as an alternative abstraction to use our library with (the same way M.E.L.A is to SeriLog), but probably more interestingly, we'd be able to send lots of Microsoft internal metrics (from ASP.NET Core for example) to StatsD to be able to graph on, which would be super cool.

I'm not completely sure what is required, here is the listener part of the design we'd probably want to integrate with: https://github.com/dotnet/designs/blob/main/accepted/2021/System.Diagnostics/Metrics-Design.md#listening-example

We might have an extension method on MeterListener (InstrumentListener in the design above, I think it's changed) which registers the various SetMeasurementEventCallback<T> callbacks for each supported primitive type.

I'm thinking a light library named JustEat.Diagnostics.Metrics.StatsD.

martincostello commented 3 years ago

I had a very quick look at this and ended up with this Console app using 6.0 RC1 to handle counters using the design doc as a guide.

using System.Diagnostics.Metrics;
using JustEat.StatsD;

var publisher = new StatsDPublisher(new()
{
    Host = "localhost",
    Port = 8125,
    Prefix = "myservice",
});

var listener = new MeterListener();
listener.InstrumentPublished = (instrument, meterListener) =>
{
    if (instrument.Name == "Requests" && instrument.Meter.Name == "io.opentelemetry.contrib.mongodb")
    {
        meterListener.EnableMeasurementEvents(instrument, null);
    }
};

listener.SetMeasurementEventCallback<int>((instrument, measurement, tags, state) =>
{
    Dictionary<string, string?>? stringTags = null;

    if (!tags.IsEmpty)
    {
        stringTags = new Dictionary<string, string?>();

        foreach (var tag in tags)
        {
            stringTags[tag.Key] = tag.Value?.ToString();
        }
    }

    publisher.Increment(measurement, instrument.Meter.Name + "." + instrument.Name, stringTags);
});

listener.Start();

using var meter = new Meter("io.opentelemetry.contrib.mongodb", "v1.0");
var counter = meter.CreateCounter<int>("Requests");
counter.Add(1);
counter.Add(1, KeyValuePair.Create<string, object?>("request", "read"));