Sdílet prostřednictvím


Shromažďování metrik

Tento článek se vztahuje na: ✔️ .NET Core 3.1 a novější ✔️ .NET Framework 4.6.1 a novější

Instrumentovaný kód může zaznamenávat číselné měření, ale měření je obvykle potřeba agregovat, přenášet a ukládat, aby se vytvořily užitečné metriky pro monitorování. Proces agregace, přenosu a ukládání dat se nazývá shromažďování. Tento kurz ukazuje několik příkladů shromažďování metrik:

Další informace o vlastní instrumentaci a možnostech metrik najdete v tématu Porovnání rozhraní API metrik.

Požadavky

Vytvoření ukázkové aplikace

Než je možné shromažďovat metriky, musí se vytvořit měření. Tento kurz vytvoří aplikaci, která má základní instrumentaci metrik. Modul runtime .NET má také integrované různé metriky. Další informace o vytváření nových metrik pomocí System.Diagnostics.Metrics.Meter rozhraní API najdete v kurzu instrumentace.

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

Program.cs Obsah nahraďte následujícím kódem:

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

Předchozí kód simuluje prodej klobouků v náhodných intervalech a náhodných časech.

Zobrazení metrik pomocí čítačů dotnet

dotnet-counters je nástroj příkazového řádku, který může zobrazit živé metriky pro aplikace .NET Core na vyžádání. Nevyžaduje nastavení, což je užitečné pro ad hoc šetření nebo ověření, že instrumentace metrik funguje. Funguje s rozhraními API založenými System.Diagnostics.Metrics na rozhraních API a EventCounters.

Pokud nástroj dotnet-counters není nainstalovaný, spusťte následující příkaz:

dotnet tool update -g dotnet-counters

Zatímco je ukázková aplikace spuštěná, spusťte dotnet-counters. Následující příkaz ukazuje příklad dotnet-counters monitorování všech metrik z měřiče HatCo.HatStore . V názvu měřiče se rozlišují malá a velká písmena. Naše ukázková aplikace byla metric-instr.exe, nahraďte ji názvem vaší ukázkové aplikace.

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

Zobrazí se výstup podobný následujícímu:

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

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

dotnet-counters můžete spustit s jinou sadou metrik, abyste viděli některé integrované instrumentace z modulu runtime .NET:

dotnet-counters monitor -n metric-instr

Zobrazí se výstup podobný následujícímu:

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

Další informace najdete v tématu dotnet-counters. Další informace o metrikách v .NET najdete v předdefinovaných metrikách.

Zobrazení metrik v Grafana pomocí OpenTelemetry a Prometheus

Přehled

OpenTelemetry:

Tento kurz ukazuje jednu z integrací dostupných pro metriky OpenTelemetry pomocí projektů OSS Prometheus a Grafana . Tok dat metrik:

  1. Rozhraní API metrik .NET zaznamenávají měření z ukázkové aplikace.

  2. Knihovna OpenTelemetry spuštěná v aplikaci agreguje měření.

  3. Knihovna exportéru Prometheus zpřístupňuje agregovaná data prostřednictvím koncového bodu metrik HTTP. "Exportér" označuje, co OpenTelemetry volá knihovny, které přenášejí telemetrii do back-endů specifických pro dodavatele.

  4. Server Prometheus:

    • Dotazuje koncový bod metrik.
    • Čte data.
    • Ukládá data do databáze pro dlouhodobou trvalost. Prometheus označuje čtení a ukládání dat jako škrábání koncového bodu.
    • Může běžet na jiném počítači.
  5. Server Grafana:

    • Dotazuje data uložená v systému Prometheus a zobrazí je na webovém řídicím panelu monitorování.
    • Může běžet na jiném počítači.

Konfigurace ukázkové aplikace tak, aby používala exportér OpenTelemetry Prometheus

Do ukázkové aplikace přidejte odkaz na vývozce OpenTelemetry Prometheus:

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

Poznámka:

V tomto kurzu se používá předběžné sestavení podpory Prometheus openTelemetry dostupné v době psaní.

Aktualizace Program.cs s využitím konfigurace OpenTelemetry:

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

V předchozím kódu:

  • AddMeter("HatCo.HatStore") nakonfiguruje OpenTelemetry tak, aby přenášela všechny metriky shromážděné měřičem definovaným v aplikaci.
  • AddPrometheusHttpListener Nakonfiguruje OpenTelemetry na:
    • Zveřejnění koncového bodu metriky Prometheus na portu 9184
    • Použijte httpListener.

Další informace o možnostech konfigurace OpenTelemetry najdete v dokumentaci k OpenTelemetry. Dokumentace k OpenTelemetry ukazuje možnosti hostování ASP.NET aplikací.

Spusťte aplikaci a nechte ji spuštěnou, aby bylo možné shromažďovat měření:

dotnet run

Nastavení a konfigurace prometheus

Podle prvních kroků prometheus nastavte server Prometheus a ověřte, že funguje.

Upravte konfigurační soubor prometheus.yml tak, aby Nástroj Prometheus škrábl koncový bod metrik, který ukázková aplikace vystavuje. Do oddílu scrape_configs přidejte následující zvýrazněný text:

# 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']

Spustit Prometheus

  1. Znovu načtěte konfiguraci nebo restartujte server Prometheus.

  2. Ověřte, že openTelemetryTest je ve stavu UP na stránce Cíle stavu>webového portálu Prometheus. Prometheus status

  3. Na stránce Graf webového portálu Prometheus zadejte hats do textového pole výrazu a na kartě grafu vyberte hats_sold_Hatshat Prometheus zvýšení hodnoty čítače "hats-sold", který je generován ukázkovou aplikací. Prometheus hats sold graph

Na předchozím obrázku je čas grafu nastavený na 5 min, což je 5 minut.

Pokud server Prometheus dlouho nešrotoval ukázkové aplikace, možná budete muset počkat, až se data nahromáždí.

Zobrazení metrik na řídicím panelu Grafana

  1. Podle standardních pokynů nainstalujte Grafana a připojte ho ke zdroji dat Prometheus.

  2. Vytvořte řídicí panel Grafana kliknutím + na ikonu na levém panelu nástrojů na webovém portálu Grafana a pak vyberte Řídicí panel. V zobrazeném editoru řídicího panelu zadejte do vstupního pole nadpisu a sazby (hats_sold[5 min]) do pole výrazu PromQL:

    Hats sold Grafana dashboard editor

  3. Kliknutím na Použít uložíte a zobrazíte nový řídicí panel.

    Hats sold Grafana dashboard]

Vytvoření vlastního nástroje pro kolekci pomocí rozhraní API meterListener .NET

Rozhraní .NET MeterListener API umožňuje vytvořit vlastní logiku procesu pro sledování měření, která System.Diagnostics.Metrics.Meterse zaznamenávají . Pokyny k vytvoření vlastní logiky kompatibilní se starší instrumentací EventCounters najdete v tématu EventCounters.

Upravte kód Program.cs , který chcete použít MeterListener:

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

Následující výstup ukazuje výstup aplikace s vlastním zpětným voláním pro každé měření:

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

Vysvětlení vzorového kódu

Fragmenty kódu v této části pocházejí z předchozí ukázky.

V následujícím zvýrazněném kódu se vytvoří instance objektu MeterListener pro příjem měření. Klíčové using slovo Dispose může být volána, když meterListener přejde mimo rozsah.

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

Následující zvýrazněný kód konfiguruje, které nástroje naslouchací proces přijímá měření. InstrumentPublished je delegát, který se vyvolá při vytvoření nového nástroje v aplikaci.

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

Delegát může nástroj prozkoumat a rozhodnout, jestli se má přihlásit k odběru. Delegát může například zkontrolovat jméno, měřič nebo jakoukoli jinou veřejnou vlastnost. EnableMeasurementEvents umožňuje přijímat měření ze zadaného přístroje. Kód, který získá odkaz na nástroj jiným přístupem:

  • Obvykle to není hotové.
  • Může se kdykoli vyvolat EnableMeasurementEvents() pomocí odkazu.

Delegát, který je vyvolán při přijetí měření z nástroje je nakonfigurován voláním SetMeasurementEventCallback:

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

Obecný parametr určuje, jaký datový typ měření přijímá zpětné volání. Například vygeneruje Counter<int> int měření, Counter<double> generuje double měření. Nástroje lze vytvářet pomocí byte, , short, intlongfloat, , , double, a decimal typů. Doporučujeme zaregistrovat zpětné volání pro každý datový typ, pokud nemáte znalosti specifické pro konkrétní scénář, které nejsou potřeba pro všechny datové typy. Opakované volání SetMeasurementEventCallback s různými obecnými argumenty se může zdát trochu neobvyklé. Toto rozhraní API bylo navržené tak, aby umožňovalo MeterListener přijímat měření s nízkou režií na výkon, obvykle jen pár nanosekund.

Při MeterListener.EnableMeasurementEvents zavolání state lze objekt poskytnout jako jeden z parametrů. Objekt state je libovolný. Pokud v daném volání zadáte objekt stavu, uloží se s tímto nástrojem a vrátí se vám jako state parametr v zpětném volání. To je určeno jak jako pohodlí, tak jako optimalizace výkonu. Často naslouchací procesy potřebují:

  • Vytvořte objekt pro každý nástroj, který ukládá měření do paměti.
  • Mít kód, který má provádět výpočty s těmito měřeními.

Případně můžete vytvořit Dictionary mapování z nástroje na objekt úložiště a vyhledat ho při každém měření. Použití je Dictionary mnohem pomalejší než přístup z state.

meterListener.Start();

Předchozí kód spustí MeterListener , který umožňuje zpětné volání. Delegát InstrumentPublished se vyvolá pro každý předem existující nástroj v procesu. Nově vytvořené objekty instrumentu se také aktivují InstrumentPublished , které se mají vyvolat.

using MeterListener meterListener = new MeterListener();

Po dokončení naslouchání aplikace zastaví naslouchací proces tok zpětných volání a uvolní všechny interní odkazy na objekt naslouchacího procesu. Klíčové using slovo použité při deklarování meterListener příčin Dispose , které se mají volat, když proměnná přejde mimo rozsah. Všimněte si, že Dispose je to jen slibné, že nespustí nové zpětná volání. Vzhledem k tomu, že zpětná volání probíhají v různých vláknech, můžou po návratu volání stále probíhat Dispose zpětná volání.

Aby se zajistilo, že se v budoucnu nespustí určitá oblast kódu v zpětném volání, je potřeba přidat synchronizaci vláken. Dispose nezahrnuje synchronizaci ve výchozím nastavení, protože:

  • Synchronizace zvyšuje režii na výkon při každém zpětném volání měření.
  • MeterListener je navržen jako vysoce výkonné rozhraní API.