Mengumpulkan metrik
Artikel ini berlaku untuk: ✔️ .NET Core 3.1 dan yang lebih baru ✔️ .NET Framework 4.6.1 dan yang lebih baru
Kode berinstrumen dapat merekam pengukuran numerik, tetapi pengukuran biasanya perlu dikumpulkan, ditransmisikan, dan disimpan untuk membuat metrik yang berguna untuk pemantauan. Proses agregasi, transmisi, dan penyimpanan data disebut pengumpulan. Tutorial ini menunjukkan beberapa contoh pengumpulan metrik:
- Mengisi metrik di Grafana dengan OpenTelemetry dan Prometheus.
- Menampilkan metrik secara real time dengan
dotnet-counters
- Membuat alat koleksi kustom menggunakan .NET MeterListener API yang mendasar.
Untuk informasi selengkapnya tentang instrumentasi dan opsi metrik kustom, lihat Membandingkan API metrik.
Prasyarat
- .NET Core 3.1 SDK atau yang lebih baru
Membuat aplikasi contoh
Sebelum metrik dapat dikumpulkan, pengukuran harus diproduksi. Tutorial ini membuat aplikasi yang memiliki instrumentasi metrik dasar. Runtime .NET juga memiliki berbagai metrik bawaan. Untuk informasi selengkapnya tentang membuat metrik baru menggunakan System.Diagnostics.Metrics.Meter API, lihat tutorial instrumentasi.
dotnet new console -o metric-instr
cd metric-instr
dotnet add package System.Diagnostics.DiagnosticSource
Ganti isi Program.cs
dengan kode berikut:
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));
}
}
}
Kode sebelumnya mensimulasikan penjualan topi secara acak dan waktu acak.
Melihat metrik dengan penghitung dotnet
dotnet-counters adalah alat baris perintah yang dapat melihat metrik langsung untuk aplikasi .NET Core sesuai permintaan. Ini tidak memerlukan penyiapan, membuatnya berguna untuk investigasi ad-hoc atau memverifikasi bahwa instrumentasi metrik berfungsi. Ini berfungsi dengan System.Diagnostics.Metrics API berbasis dan EventCounters.
Jika alat penghitung dotnet tidak diinstal, jalankan perintah berikut:
dotnet tool update -g dotnet-counters
Saat aplikasi contoh berjalan, luncurkan penghitung dotnet. Perintah berikut menunjukkan contoh dotnet-counters
pemantauan semua metrik dari meteran HatCo.HatStore
. Nama meter peka huruf besar/kecil. Aplikasi sampel kami adalah metric-instr.exe, ganti ini dengan nama aplikasi sampel Anda.
dotnet-counters monitor -n metric-instr HatCo.HatStore
Output yang mirip dengan berikut ini ditampilkan:
Press p to pause, r to resume, q to quit.
Status: Running
[HatCo.HatStore]
hats-sold (Count / 1 sec) 4
dotnet-counters
dapat dijalankan dengan serangkaian metrik yang berbeda untuk melihat beberapa instrumentasi bawaan dari runtime .NET:
dotnet-counters monitor -n metric-instr
Output yang mirip dengan berikut ini ditampilkan:
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
Untuk informasi selengkapnya, lihat penghitung dotnet. Untuk mempelajari selengkapnya tentang metrik di .NET, lihat metrik bawaan.
Melihat metrik di Grafana dengan OpenTelemetry dan Prometheus
Gambaran Umum
- Adalah proyek sumber terbuka vendor netral yang didukung oleh Cloud Native Computing Foundation.
- Menstandarkan pembuatan dan pengumpulan telemetri untuk perangkat lunak cloud-native.
- Bekerja dengan .NET menggunakan API metrik .NET.
- Didukung oleh Azure Monitor dan banyak vendor APM.
Tutorial ini menunjukkan salah satu integrasi yang tersedia untuk metrik OpenTelemetry menggunakan proyek OSS Prometheus dan Grafana . Aliran data metrik:
API metrik .NET merekam pengukuran dari aplikasi contoh.
Pustaka OpenTelemetry yang berjalan di aplikasi menggabungkan pengukuran.
Pustaka pengekspor Prometheus membuat data agregat tersedia melalui titik akhir metrik HTTP. 'Pengekspor' adalah apa yang disebut OpenTelemetry pustaka yang mengirimkan telemetri ke backend khusus vendor.
Server Prometheus:
- Polling titik akhir metrik
- Membaca data
- Menyimpan data dalam database untuk persistensi jangka panjang. Prometheus mengacu pada membaca dan menyimpan data sebagai mengikis titik akhir.
- Dapat berjalan pada komputer yang berbeda
Server Grafana:
- Mengkueri data yang disimpan di Prometheus dan menampilkannya di dasbor pemantauan berbasis web.
- Dapat berjalan pada komputer yang berbeda.
Mengonfigurasi contoh aplikasi untuk menggunakan pengekspor Prometheus OpenTelemetry
Tambahkan referensi ke pengekspor OpenTelemetry Prometheus ke aplikasi contoh:
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
Catatan
Tutorial ini menggunakan build pra-rilis dukungan Prometheus OpenTelemetry yang tersedia pada saat penulisan.
Perbarui Program.cs
dengan konfigurasi 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));
}
}
}
Dalam kode sebelumnya:
AddMeter("HatCo.HatStore")
mengonfigurasi OpenTelemetry untuk mengirimkan semua metrik yang dikumpulkan oleh Meter yang ditentukan dalam aplikasi.AddPrometheusHttpListener
mengonfigurasi OpenTelemetry untuk:- Mengekspos titik akhir metrik Prometheus pada port
9184
- Gunakan HttpListener.
- Mengekspos titik akhir metrik Prometheus pada port
Lihat dokumentasi OpenTelemetry untuk informasi selengkapnya tentang opsi konfigurasi OpenTelemetry. Dokumentasi OpenTelemetry menunjukkan opsi hosting untuk aplikasi ASP.NET.
Jalankan aplikasi dan biarkan berjalan sehingga pengukuran dapat dikumpulkan:
dotnet run
Menyiapkan dan mengonfigurasi Prometheus
Ikuti langkah-langkah pertama Prometheus untuk menyiapkan server Prometheus dan mengonfirmasi bahwa prometheus berfungsi.
Ubah file konfigurasi prometheus.yml sehingga Prometheus mengikis titik akhir metrik yang diekspos aplikasi contoh. Tambahkan teks yang disorot berikut ini di bagian scrape_configs
:
# 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']
Mulai Prometheus
Muat ulang konfigurasi atau mulai ulang server Prometheus.
Konfirmasikan bahwa OpenTelemetryTest berada dalam status UP di halaman Target Status>portal web Prometheus.
Pada halaman Grafik portal web Prometheus, masukkan
hats
dalam kotak teks ekspresi dan pilihhats_sold_Hats
Di tab grafik, Prometheus menunjukkan peningkatan nilai Penghitung "topi dijual" yang sedang dipancarkan oleh aplikasi contoh.
Pada gambar sebelumnya, waktu grafik diatur ke 5m, yaitu 5 menit.
Jika server Prometheus belum lama mengekstrak aplikasi contoh, Anda mungkin perlu menunggu data terakumulasi.
Menampilkan metrik di dasbor Grafana
Ikuti instruksi standar untuk menginstal Grafana dan menyambungkannya ke sumber data Prometheus.
Buat dasbor Grafana dengan mengklik + ikon di toolbar kiri di portal web Grafana, lalu pilih Dasbor. Di editor dasbor yang muncul, masukkan Topi Terjual/Detik di kotak Input judul dan laju(hats_sold[5m]) di bidang ekspresi PromQL:
Klik Terapkan untuk menyimpan dan menampilkan dasbor baru.
]
Membuat alat koleksi kustom menggunakan .NET MeterListener API
.NET MeterListener API memungkinkan Anda membuat logika dalam proses kustom untuk mengamati pengukuran yang direkam oleh System.Diagnostics.Metrics.Meter. Untuk panduan tentang membuat logika kustom yang kompatibel dengan instrumentasi EventCounters yang lebih lama, lihat EventCounters.
Ubah kode untuk Program.cs
digunakan 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}");
}
}
Output berikut menunjukkan output aplikasi dengan panggilan balik kustom pada setiap pengukuran:
> 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
...
Menjelaskan kode sampel
Cuplikan kode di bagian ini berasal dari sampel sebelumnya.
Dalam kode yang disorot berikut, instans MeterListener dibuat untuk menerima pengukuran. Kata using
kunci menyebabkan Dispose
dipanggil ketika meterListener
keluar dari cakupan.
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
Kode yang disorot berikut mengonfigurasi instrumen mana yang menerima pengukuran dari listener. InstrumentPublished adalah delegasi yang dipanggil saat instrumen baru dibuat dalam aplikasi.
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
Delegasi dapat memeriksa instrumen untuk memutuskan apakah akan berlangganan. Misalnya, delegasi dapat memeriksa nama, Meter, atau properti publik lainnya. EnableMeasurementEvents memungkinkan penerimaan pengukuran dari instrumen yang ditentukan. Kode yang mendapatkan referensi ke instrumen dengan pendekatan lain:
- Biasanya tidak dilakukan.
- Dapat memanggil
EnableMeasurementEvents()
kapan saja dengan referensi.
Delegasi yang dipanggil ketika pengukuran diterima dari instrumen dikonfigurasi dengan memanggil 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}");
}
Parameter generik mengontrol jenis data pengukuran mana yang diterima oleh panggilan balik. Misalnya, menghasilkan Counter<int>
int
pengukuran, Counter<double>
menghasilkan double
pengukuran. Instrumen dapat dibuat dengan byte
jenis , , short
, int
long
, float
, double
, dan decimal
. Sebaiknya daftarkan panggilan balik untuk setiap jenis data kecuali Anda memiliki pengetahuan khusus skenario bahwa tidak semua jenis data diperlukan. Melakukan panggilan berulang ke SetMeasurementEventCallback
dengan argumen generik yang berbeda mungkin tampak sedikit tidak biasa. API dirancang dengan cara ini untuk memungkinkan MeterListener
untuk menerima pengukuran dengan overhead performa rendah, biasanya hanya beberapa nanodetik.
Ketika MeterListener.EnableMeasurementEvents
dipanggil, state
objek dapat disediakan sebagai salah satu parameter. Objek state
ini segan-segan. Jika Anda memberikan objek status dalam panggilan tersebut, maka objek tersebut disimpan dengan instrumen tersebut state
dan dikembalikan kepada Anda sebagai parameter dalam panggilan balik. Ini dimaksudkan baik sebagai kenyamanan maupun sebagai pengoptimalan performa. Seringkali pendengar perlu:
- Buat objek untuk setiap instrumen yang menyimpan pengukuran dalam memori.
- Memiliki kode untuk melakukan perhitungan pada pengukuran tersebut.
Atau, buat Dictionary
yang memetakan dari instrumen ke objek penyimpanan dan mencarinya di setiap pengukuran. Dictionary
Menggunakan jauh lebih lambat daripada mengaksesnya dari state
.
meterListener.Start();
Kode sebelumnya memulai MeterListener
yang memungkinkan panggilan balik. Delegasi InstrumentPublished
dipanggil untuk setiap Instrumen yang sudah ada sebelumnya dalam proses. Objek Instrumen yang baru dibuat juga memicu InstrumentPublished
untuk dipanggil.
using MeterListener meterListener = new MeterListener();
Ketika aplikasi selesai mendengarkan, membuang pendengar menghentikan alur panggilan balik dan merilis referensi internal apa pun ke objek pendengar. Kata kunci yang using
digunakan saat mendeklarasikan meterListener
penyebab Dispose
dipanggil ketika variabel keluar dari cakupan. Perhatikan bahwa Dispose
hanya menjanjikan bahwa ia tidak akan memulai panggilan balik baru. Karena panggilan balik terjadi pada utas yang berbeda, mungkin masih ada panggilan balik yang sedang berlangsung setelah panggilan untuk Dispose
kembali.
Untuk menjamin bahwa wilayah kode tertentu dalam panggilan balik saat ini tidak dijalankan dan tidak akan dijalankan di masa mendatang, sinkronisasi utas harus ditambahkan. Dispose
tidak menyertakan sinkronisasi secara default karena:
- Sinkronisasi menambahkan overhead performa di setiap panggilan balik pengukuran.
MeterListener
dirancang sebagai API sadar performa tinggi.