Aracılığıyla paylaş


Ölçümleri toplama

Bu makale şunlar için geçerlidir: ✔️ .NET Core 3.1 ve üzeri✔️ .NET Framework 4.6.1 ve üzeri

İzlenen kod sayısal ölçümleri kaydedebilir, ancak izleme için yararlı ölçümler oluşturmak için genellikle ölçümlerin toplanması, iletilmesi ve depolanması gerekir. Verileri toplama, iletme ve depolama işlemine toplama adı verilir. Bu öğreticide ölçümleri toplamaya yönelik birkaç örnek gösterilmektedir:

  • OpenTelemetry ve Prometheus ile Grafana'da ölçümleri doldurma.
  • ile ölçümleri gerçek zamanlı olarak görüntüleme dotnet-counters
  • Temel alınan .NET MeterListener API'sini kullanarak özel bir koleksiyon aracı oluşturma.

Özel ölçüm araçları ve seçenekleri hakkında daha fazla bilgi için bkz . Ölçüm API'lerini karşılaştırma.

Önkoşullar

Örnek uygulama oluşturma

Ölçümlerin toplanabilmesi için önce ölçümlerin üretilmesi gerekir. Bu öğretici, temel ölçüm araçlarına sahip bir uygulama oluşturur. .NET çalışma zamanı ayrıca yerleşik olarak çeşitli ölçümlere sahiptir. API kullanarak System.Diagnostics.Metrics.Meter yeni ölçümler oluşturma hakkında daha fazla bilgi için izleme öğreticisine bakın.

dotnet new console -o metric-instr
cd metric-instr
dotnet add package System.Diagnostics.DiagnosticSource

öğesinin içeriğini Program.cs aşağıdaki kodla değiştirin:

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>("hats-sold");

    static void Main(string[] args)
    {
        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));
        }
    }
}

Yukarıdaki kod, satış şapkalarını rastgele aralıklarla ve rastgele zamanlarda simüle eder.

Dotnet-counters ile ölçümleri görüntüleme

dotnet-counters , .NET Core uygulamalarının canlı ölçümlerini isteğe bağlı olarak görüntüleyebilen bir komut satırı aracıdır. Kurulum gerektirmez, geçici araştırmalarda veya ölçüm izlemenin çalıştığını doğrulamada yararlı olur. Hem tabanlı API'lerle hem de System.Diagnostics.Metrics EventCounters ile çalışır.

dotnet-counters aracı yüklü değilse aşağıdaki komutu çalıştırın:

dotnet tool update -g dotnet-counters

Örnek uygulama çalışırken dotnet-counters'ı başlatın. Aşağıdaki komut, ölçümdeki dotnet-counters tüm ölçümlerin izlenmesine HatCo.HatStore ilişkin bir örnek gösterir. Ölçüm adı büyük/küçük harfe duyarlıdır. Örnek uygulamamız metric-instr.exe'ydi, bunu örnek uygulamanızın adıyla değiştirin.

dotnet-counters monitor -n metric-instr HatCo.HatStore

Aşağıdakine benzer bir çıkış görüntülenir:

Press p to pause, r to resume, q to quit.
    Status: Running

[HatCo.HatStore]
    hats-sold (Count / 1 sec)                          4

dotnet-counters .NET çalışma zamanından bazı yerleşik izlemeleri görmek için farklı bir ölçüm kümesiyle çalıştırılabilir:

dotnet-counters monitor -n metric-instr

Aşağıdakine benzer bir çıkış görüntülenir:

Press p to pause, r to resume, q to quit.
    Status: Running

[System.Runtime]
    % Time in GC since last GC (%)                                 0
    Allocation Rate (B / 1 sec)                                8,168
    CPU Usage (%)                                                  0
    Exception Count (Count / 1 sec)                                0
    GC Heap Size (MB)                                              2
    Gen 0 GC Count (Count / 1 sec)                                 0
    Gen 0 Size (B)                                         2,216,256
    Gen 1 GC Count (Count / 1 sec)                                 0
    Gen 1 Size (B)                                           423,392
    Gen 2 GC Count (Count / 1 sec)                                 0
    Gen 2 Size (B)                                           203,248
    LOH Size (B)                                             933,216
    Monitor Lock Contention Count (Count / 1 sec)                  0
    Number of Active Timers                                        1
    Number of Assemblies Loaded                                   39
    ThreadPool Completed Work Item Count (Count / 1 sec)           0
    ThreadPool Queue Length                                        0
    ThreadPool Thread Count                                        3
    Working Set (MB)                                              30

Daha fazla bilgi için bkz . dotnet-counters. .NET'teki ölçümler hakkında daha fazla bilgi edinmek için bkz . yerleşik ölçümler.

OpenTelemetry ve Prometheus ile Grafana'da ölçümleri görüntüleme

Genel Bakış

OpenTelemetry:

Bu öğreticide, OSS Prometheus ve Grafana projelerini kullanarak OpenTelemetry ölçümleri için kullanılabilen tümleştirmelerden biri gösterilmektedir. Ölçüm veri akışı:

  1. .NET ölçüm API'leri örnek uygulamadaki ölçümleri kaydeder.

  2. Uygulamada çalıştırılan OpenTelemetry kitaplığı ölçümleri toplar.

  3. Prometheus dışarı aktarma kitaplığı, toplanan verileri bir HTTP ölçüm uç noktası aracılığıyla kullanılabilir hale getirir. 'Exporter', OpenTelemetry'nin telemetri verilerini satıcıya özgü arka uçlara ileten kitaplıkları çağıran şeydir.

  4. Prometheus sunucusu:

    • Ölçüm uç noktasını yoklar
    • Verileri okur
    • Verileri uzun süreli kalıcılık için bir veritabanında depolar. Prometheus, verileri okuma ve depolamayı bir uç noktayı kazıma olarak ifade eder.
    • Farklı bir makinede çalışabilir
  5. Grafana sunucusu:

    • Prometheus'ta depolanan verileri sorgular ve web tabanlı bir izleme panosunda görüntüler.
    • Farklı bir makinede çalıştırılabilir.

Örnek uygulamayı OpenTelemetry'nin Prometheus dışarı aktarmasını kullanacak şekilde yapılandırma

Örnek uygulamaya OpenTelemetry Prometheus verenine bir başvuru ekleyin:

dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease

Dekont

Bu öğreticide, yazma sırasında sağlanan OpenTelemetry Prometheus desteğinin yayın öncesi derlemesi kullanılmaktadır.

OpenTelemetry yapılandırmasıyla güncelleştirme Program.cs :

using OpenTelemetry;
using OpenTelemetry.Metrics;
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 MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder()
                .AddMeter("HatCo.HatStore")
                .AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { "http://localhost:9184/" })
                .Build();

        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));
        }
    }
}

Önceki kodda:

  • AddMeter("HatCo.HatStore") , Uygulamada tanımlanan Ölçüm tarafından toplanan tüm ölçümleri iletmek için OpenTelemetry'yi yapılandırıyor.
  • AddPrometheusHttpListener OpenTelemetry'yi şu şekilde yapılandırıyor:
    • Prometheus'un ölçüm uç noktasını bağlantı noktasında kullanıma sunma 9184
    • HttpListener'ı kullanın.

OpenTelemetry yapılandırma seçenekleri hakkında daha fazla bilgi için OpenTelemetry belgelerine bakın. OpenTelemetry belgelerinde ASP.NET uygulamaları için barındırma seçenekleri gösterilir.

Ölçümlerin toplanabilmesi için uygulamayı çalıştırın ve çalışır durumda bırakın:

dotnet run

Prometheus'ı ayarlama ve yapılandırma

Prometheus sunucusunu ayarlamak için Prometheus ilk adımlarını izleyin ve çalıştığını doğrulayın.

Prometheus.yml yapılandırma dosyasını, Prometheus'un örnek uygulamanın sergilediğini ölçüm uç noktasını kazıması için değiştirin. Bölümüne aşağıdaki vurgulanmış metni scrape_configs ekleyin:

# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]

  - job_name: 'OpenTelemetryTest'
    scrape_interval: 1s # poll very quickly for a more responsive demo
    static_configs:
      - targets: ['localhost:9184']

Prometheus'ı başlatma

  1. Yapılandırmayı yeniden yükleyin veya Prometheus sunucusunu yeniden başlatın.

  2. OpenTelemetryTest'in Prometheus web portalının Durum>Hedefleri sayfasında UP durumunda olduğunu onaylayın. Prometheus status

  3. Prometheus web portalının Grafik sayfasında, ifade metin kutusuna girin hats ve hats_sold_Hatshat Grafik sekmesinde Prometheus, örnek uygulama tarafından yayılan "hats-sold" Sayacının artan değerini gösterir. Prometheus hats sold graph

Önceki görüntüde, grafik süresi 5 dakika olan 5m olarak ayarlanmıştır.

Prometheus sunucusu uzun süredir örnek uygulamayı kazımıyorsa verilerin birikmesini beklemeniz gerekebilir.

Grafana panosunda ölçümleri gösterme

  1. Grafana'yı yüklemek ve prometheus veri kaynağına bağlamak için standart yönergeleri izleyin.

  2. Grafana web portalında sol araç çubuğundaki + simgeye tıklayıp Pano'yu seçerek grafana panosu oluşturun. Görüntülenen pano düzenleyicisinde Başlık giriş kutusuna Hats Sold/Sec yazın ve PromQL ifade alanına rate(hats_sold[5m]) girin:

    Hats sold Grafana dashboard editor

  3. Yeni panoyu kaydetmek ve görüntülemek için Uygula'ya tıklayın.

    Hats sold Grafana dashboard]

.NET MeterListener API'sini kullanarak özel koleksiyon aracı oluşturma

.NET MeterListener API'si, tarafından System.Diagnostics.Metrics.Meterkaydedilen ölçümleri gözlemlemek için özel işlem içi mantık oluşturmanıza olanak tanır. Eski EventCounters araçlarıyla uyumlu özel mantık oluşturma yönergeleri için bkz . EventCounters.

kullanmak MeterListeneriçin kodunu Program.cs değiştirin:

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}");
    }
}

Aşağıdaki çıkış, her ölçümde özel geri çağırma ile uygulamanın çıkışını gösterir:

> 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
...

Örnek kodu açıklama

Bu bölümdeki kod parçacıkları önceki örnekten gelir.

Aşağıdaki vurgulanmış kodda, ölçümleri almak için öğesinin MeterListener bir örneği oluşturulur. anahtar using sözcüğü, kapsamın dışına çıktığında meterListener çağrılmaya neden olurDispose.

using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
    if (instrument.Meter.Name is "HatCo.HatStore")
    {
        listener.EnableMeasurementEvents(instrument);
    }
};

Aşağıdaki vurgulanmış kod, dinleyicinin hangi ölçümlerden ölçüm alacağını yapılandırıyor. InstrumentPublished , uygulama içinde yeni bir araç oluşturulduğunda çağrılan bir temsilcidir.

using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
    if (instrument.Meter.Name is "HatCo.HatStore")
    {
        listener.EnableMeasurementEvents(instrument);
    }
};

Temsilci, abone olup olmayacağına karar vermek için aracı inceleyebilir. Örneğin, temsilci adı, Ölçüm'ünü veya başka bir ortak özelliği denetleyebilir. EnableMeasurementEvents belirtilen aletten ölçüm almayı etkinleştirir. Başka bir yaklaşım tarafından bir alete başvuru elde eden kod:

  • Genellikle yapılmaz.
  • Başvuruyla istediğiniz zaman çağırabilir EnableMeasurementEvents() .

Ölçümler bir araçtan alındığında çağrılan temsilci çağrılarak SetMeasurementEventCallbackyapılandırılır:

    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}");
}

Genel parametre, geri çağırma tarafından hangi veri türü ölçümünün alın aldığını denetler. Örneğin, bir Counter<int> ölçüm oluşturur int , Counter<double> ölçümler double oluşturur. araçlar , , short, , int, long, doublefloatve decimal türleriyle byteoluşturulabilir. Tüm veri türlerinin gerekli olmadığı senaryoya özgü bilginiz olmadığı sürece her veri türü için bir geri çağırma kaydetmenizi öneririz. Farklı genel bağımsız değişkenlerle tekrarlanan çağrılar SetMeasurementEventCallback yapmak biraz olağan dışı görünebilir. API, düşük performans yüküne sahip ölçümler (genellikle yalnızca birkaç nanosaniye) almak için bu şekilde MeterListener tasarlanmıştır.

Çağrıldığında MeterListener.EnableMeasurementEvents , parametrelerden biri olarak bir state nesne sağlanabilir. state Nesnesi rastgeledir. Bu çağrıda bir durum nesnesi sağlarsanız, bu aletle birlikte depolanır ve geri çağırmada parametre olarak state size döndürülür. Bu, hem kolaylık hem de performans iyileştirmesi olarak tasarlanmıştır. Dinleyicilerin genellikle şu özelliklere sahip olması gerekir:

  • Ölçümleri bellekte depolayan her alet için bir nesne oluşturun.
  • Bu ölçümler üzerinde hesaplamalar yapmak için koda sahip olun.

Alternatif olarak, aletten depolama nesnesine eşleyen bir Dictionary oluşturun ve her ölçümde arayın. kullanmak Dictionary , 'den stateerişmekten çok daha yavaştır.

meterListener.Start();

Yukarıdaki kod, geri çağırmaları etkinleştiren öğesini MeterListener başlatır. Temsilci InstrumentPublished , işlemdeki önceden var olan tüm Araçlar için çağrılır. Yeni oluşturulan instrument nesneleri de çağrılmak üzere tetikler InstrumentPublished .

using MeterListener meterListener = new MeterListener();

Uygulama dinlemeyi bitirdiğinde dinleyicinin yok olması geri çağırmaların akışını durdurur ve dinleyici nesnesine yapılan iç başvuruları serbest bırakır. Bildirimde using bulunurken meterListener kullanılan anahtar sözcük, değişken kapsam dışına çıktığında çağrılmaya neden olur Dispose . Dispose Bunun yalnızca yeni geri çağırmalar başlatmayacağından söz ettiğini unutmayın. Geri çağırmalar farklı iş parçacıklarında gerçekleştiğinden, çağrı döndürüldikten sonra hala devam eden geri çağırmalar Dispose olabilir.

Geri aramadaki belirli bir kod bölgesinin şu anda yürütülmeyeceğini ve gelecekte yürütülmeyeceğini garanti etmek için iş parçacığı eşitlemesi eklenmelidir. Dispose aşağıdakiler nedeniyle varsayılan olarak eşitleme içermez:

  • Eşitleme, her ölçüm geri çağırmasında performans ek yükü ekler.
  • MeterListener yüksek performans bilincine sahip bir API olarak tasarlanmıştır.