在.NET中使用OpenTelemetry实现性能监控

.Net是用什么来收集指标数据的?

  • 使用Meter类来产生数据

    自.Net 6以后都是通过Meter这个类来实现的,System.Diagnostics.Metrics API 是最新的跨平台 API,是通过与 OpenTelemetry 项目的密切合作设计的。下面是这个Meter提供的指标与OpenTelemetry的指标的一个对应表格:

    OpenTelemetry Specification .NET Instrument Type
    Asynchronous Counter ObservableCounter
    Asynchronous Gauge ObservableGauge
    Asynchronous UpDownCounter ObservableUpDownCounter
    Counter Counter
    Gauge Gauge
    Histogram Histogram
    UpDownCounter UpDownCounter
  • 然后使用MeterListener来接收数据。下面举个例子来解释如何使用Meter和MeterListener:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    using System.Diagnostics.Metrics;

    class Program
    {
    static Meter s_meter = new("HatCo.HatStore", "1.0.0");
    static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(
    name: "hats-sold",
    unit: "Hats",
    description: "The number of hats sold in our store");

    static void Main(string[] args)
    {
    using MeterListener meterListener = new();
    meterListener.InstrumentPublished = (instrument, listener) =>
    {
    if (instrument.Meter.Name is "HatCo.HatStore")
    {
    listener.EnableMeasurementEvents(instrument);
    }
    };

    meterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);
    // Start the meterListener, enabling InstrumentPublished callbacks.
    meterListener.Start();

    var rand = Random.Shared;
    Console.WriteLine("Press any key to exit");
    while (!Console.KeyAvailable)
    {
    //// Simulate hat selling transactions.
    Thread.Sleep(rand.Next(100, 2500));
    s_hatsSold.Add(rand.Next(0, 1000));
    }
    }

    static void OnMeasurementRecorded<T>(
    Instrument instrument,
    T measurement,
    ReadOnlySpan<KeyValuePair<string, object?>> tags,
    object? state)
    {
    Console.WriteLine($"{instrument.Name} recorded measurement {measurement}");
    }
    }

    以下输出显示了应用的输出,并针对每个度量值使用自定义回调:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    > dotnet run
    Press any key to exit
    hats-sold recorded measurement 978
    hats-sold recorded measurement 775
    hats-sold recorded measurement 666
    hats-sold recorded measurement 66
    hats-sold recorded measurement 914
    hats-sold recorded measurement 912
    ...

    详细解释,请参看:收集指标 - .NET | Microsoft Learn。当然在OpenTelemetry中接收以后,当然不是简单的输出到控制台,而是通过Exporter发送到OpenTelemetry Collector或者特定的遥测数据服务器。监听的逻辑可以在这里找到:MeterProviderSdk

示例

  • 前置条件:你已经按照这篇文章,搭建好了本地环境。

  • 创建一个Asp.Net Core Web API项目,并且按照如下几个包:

    • OpenTelemetry.Exporter.OpenTelemetryProtocol
    • OpenTelemetry.Extensions.Hosting
    • OpenTelemetry.Instrumentation.AspNetCore
  • 在容器中注入必要的服务,大概类似这样:

    1
    2
    3
    4
    5
    services.AddOpenTelemetry()
    .ConfigureResource(b => b.AddService("OpenTelemetry.MetricsExample", serviceVersion: "1.0.0"))
    .WithMetrics(builder => builder
    .AddAspNetCoreInstrumentation()
    .AddOtlpExporter());
  • 打开grafana,创建Dashboard,通过导入这2个ID:19925,19924。来查看指标数据,这2个ID可以在这里找到:Grafana Dotnet Team 最后你就可以得到如下的图表:

Asp.Net Core在grafana中的Dashboard一

Asp.Net Core在grafana中的Dashboard二

Asp.Net Core在grafana中的Dashboard三