Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale şunlar için geçerlidir: ✔️ .NET 6.0 ve üzeri ✔️ .NET Framework 4.6.1 ve üzeri
Enstrümante edilmiş kod sayısal ölçümleri kaydedebilir, ancak izleme için kullanışlı metrikler oluşturmak amacıyla genellikle bu ö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:
- Grafana için OpenTelemetry ve Prometheus ile metrikleri doldurma.
- ile ölçümleri gerçek zamanlı olarak görüntüleme
dotnet-counters
- Temel alınan .NET MeterListener API'sini kullanarak özel bir veri toplama 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
- .NET 6.0 SDK veya üzeri
Örnek uygulama oluşturma
Ölçümlerin toplanabilmesi için önce ölçümlerin üretilmesi gerekir. Bu eğitim, temel metrik enstrümantasyonuna sahip bir uygulama oluşturur. .NET çalışma zamanı ayrıca yerleşik olarak çeşitli ölçümlere sahiptir. API kullanarak yeni ölçümler oluşturma hakkında daha fazla bilgi için System.Diagnostics.Metrics.Meter bakın.
dotnet new console -o metric-instr
cd metric-instr
dotnet add package System.Diagnostics.DiagnosticSource
Program.cs
içeriğini 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));
}
}
}
Önceki kod, şapka satışı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 System.Diagnostics.Metrics tabanlı API'lerle hem de 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, dotnet-counters
sayaçtan HatCo.HatStore
tüm metrikleri izleyen bir örnek gösterir. Ölçer adı büyük/küçük harfe duyarlıdır. Örnek uygulamamız metric-instr.exe, 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ı tarafından sağlanan bazı yerleşik özellikleri görmek için farklı bir dizi ölçümle ç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ış
- Cloud Native Computing Foundation tarafından desteklenen, satıcıdan bağımsız bir açık kaynak projesidir.
- Bulutta yerel yazılımlar için telemetri oluşturmayı ve toplamayı standartlaştırır.
- .NET ölçüm API'lerini kullanarak .NET ile çalışır.
- Azure İzleyici ve birçok APM satıcısı tarafından onaylanır.
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ışı:
.NET ölçüm API'leri örnek uygulamadaki ölçümleri kaydeder.
Uygulamada çalıştırılan OpenTelemetry kitaplığı ölçümleri toplar.
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 iletmeyi sağlayan kütüphanelere verdiği addır.
Prometheus sunucusu:
- Metrik 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
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 İhracatçısına bir referans ekleyin:
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
Uyarı
Bu öğreticide, yazma sırasında sağlanan OpenTelemetry Prometheus desteğinin yayın öncesi derlemesi kullanılmaktadır.
OpenTelemetry yapılandırmasını güncelleştir: 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 Sayaç tarafından toplanan tüm metrikleri iletmek için OpenTelemetry'yi yapılandırır. -
AddPrometheusHttpListener
OpenTelemetry'yi şu şekilde yapılandırıyor:- Prometheus'un metrik uç noktasını portta kullanıma açma
9184
- HttpListener'ı kullanın.
- Prometheus'un metrik uç noktasını portta kullanıma açma
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çümler 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
Yapılandırmayı yeniden yükleyin veya Prometheus sunucusunu yeniden başlatın.
OpenTelemetryTest'in Prometheus web portalının Durum>Hedefleri sayfasında UP durumunda olduğunu onaylayın.
Prometheus web portalının Graf sayfasında, ifade metin kutusuna
hats
girin vehats_sold_Hats
seçin. Grafik sekmesinde, Prometheus, örnek uygulama tarafından yayımlanan "hats-sold" Sayacının artan değerini gösterir.
Önceki görüntüde, grafik süresi 5 dakika olan 5m olarak ayarlanmıştır.
Prometheus sunucusu çok uzun süredir örnek uygulamadan veri toplamıyorsa, verilerin birikmesini beklemeniz gerekebilir.
Grafana panosunda ölçümleri gösterme
Grafana'yı yüklemek ve prometheus veri kaynağına bağlamak için standart yönergeleri izleyin.
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]) yazın:
Yeni panoyu kaydetmek ve görüntülemek için Uygula'ya tıklayın.
]
.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.
Program.cs
kodunu MeterListener kullanmak için 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}");
}
}
Uygulamanın ölçüm başına özel geri çağrı işlevi ile çıktısını gösteren aşağıdaki çıktıdır:
> 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 MeterListener öğesinden bir örnek oluşturulur.
using
anahtar sözcüğü, Dispose
kapsam dışına çıktığında meterListener
çağrılmasına neden olur.
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 enstrümanlardan ölçümler 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ı, Sayaç veya başka bir genel özelliği denetleyebilir. EnableMeasurementEvents belirtilen aletten ölçüm almayı etkinleştirir. Başka bir yaklaşımla bir enstrümana referans edinen kod:
- Genellikle yapılmaz.
- Referansla istediğiniz zaman
EnableMeasurementEvents()
çağırabilirsiniz.
Bir araçtan ölçümler alındığında çağrılan temsilci, SetMeasurementEventCallback çağrılarak yapı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ğırım tarafından hangi veri türü ölçümünün alındığını denetler. Örneğin, bir Counter<int>
int
ölçümler oluşturur, Counter<double>
double
ölçümler oluşturur.
byte
, short
, int
, long
, float
, double
ve decimal
türleriyle araçlar oluş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ı jenerik argümanlarla SetMeasurementEventCallback
tekrarlanan çağrılar yapmak biraz olağan dışı görünebilir. API, MeterListener
'a düşük performans yüküyle, genellikle sadece birkaç nanosaniye alacak şekilde ölçümler almasına izin vermek için bu şekilde tasarlanmıştır.
Çağrıldığında, MeterListener.EnableMeasurementEvents
'nin bir parametresi olarak bir state
nesnesi 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 kontrol edin.
Dictionary
kullanmak, state
'den erişmeye göre çok daha yavaştır.
meterListener.Start();
Yukarıdaki kod, geri çağırmaları etkinleştiren öğesini MeterListener
başlatır. Süreçteki mevcut her bir Araç için InstrumentPublished
temsilci çağrılır. Yeni oluşturulan enstrüman nesneleri de InstrumentPublished
'nin çağrılması için tetikler.
using MeterListener meterListener = new MeterListener();
Uygulama dinleme işlemi tamamlandığında, dinleyicinin temizlenmesi geri çağrıların akışını durdurur ve dinleyici nesnesine yapılan iç referansları serbest bırakır. Bildirimde using
kullanıldığında meterListener
anahtar sözcüğü, değişken kapsam dışına çıktığında Dispose
çağrılmasına neden olur.
Dispose
'ın 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ı Dispose
döndürüldüğünde hala devam eden geri çağırmalar olabilir.
Geri aramadaki belirli bir kod bölgesinin şu anda yürütülmediğini ve gelecekte de yürütülmeyeceğini garanti etmek için iş parçacıklarının senkronizasyonu eklenmelidir.
Dispose
aşağıdakiler nedeniyle varsayılan olarak eşitleme içermez:
- Senkronizasyon, her ölçüm geri çağırmasında performans ek yükü oluşturur.
-
MeterListener
yüksek performans bilincine sahip bir API olarak tasarlanmıştır.