Ölçüm oluşturma
Bu makale şunlar için geçerlidir: ✔️ .NET Framework 4.6.1 ve sonraki sürümleri ✔️ .NET Core 6 ve sonraki sürümleri
.NET uygulamaları, önemli ölçümleri izlemek için System.Diagnostics.Metrics API'leri kullanılarak izlenebilir. Bazı ölçümler standart .NET kitaplıklarına dahil edilir, ancak uygulamalarınız ve kitaplıklarınız için uygun yeni özel ölçümler eklemek isteyebilirsiniz. Bu öğreticide yeni ölçümler ekleyecek ve kullanılabilir ölçüm türlerini anlayacaksınız.
Not
.NET'in burada ele alınmayan EventCounters ve System.Diagnostics.PerformanceCountergibi bazı eski ölçüm API'leri vardır. Bu alternatifler hakkında daha fazla bilgi edinmek için bkz. Ölçüm API'lerini karşılaştırma.
Özel ölçüm oluşturma
System.Diagnostics.DiagnosticSource NuGet paketine başvuran yeni bir konsol uygulaması oluşturun sürüm 8 veya üzeri. .NET 8+ hedefli uygulamalar varsayılan olarak bu başvuruya sahiptir. Ardından, Program.cs
kodu aşağıdakilerle eşleşecek şekilde güncelleştirin:
> dotnet new console
> dotnet add package System.Diagnostics.DiagnosticSource
using System;
using System.Diagnostics.Metrics;
using System.Threading;
class Program
{
static Meter s_meter = new Meter("HatCo.Store");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>("hatco.store.hats_sold");
static void Main(string[] args)
{
Console.WriteLine("Press any key to exit");
while(!Console.KeyAvailable)
{
// Pretend our store has a transaction each second that sells 4 hats
Thread.Sleep(1000);
s_hatsSold.Add(4);
}
}
}
System.Diagnostics.Metrics.Meter türü, adlandırılmış bir enstrüman grubu oluşturmak için bir kütüphanenin giriş noktasıdır. Aletler, metrikleri hesaplamak için gereken sayısal ölçümleri kaydeder. Burada CreateCounter kullanarak "hatco.store.hats_sold" adlı bir Sayaç enstrümanı oluşturduk. Her rol yapma işlemi sırasında kod, satılan şapkaların ölçümünün (bu durumda 4) kaydedilmesi için Add çağırır. "hatco.store.hats_sold" aracı, satılan toplam şapka sayısı veya satılan şapka/sn gibi bu ölçümlerden hesaplanabilecek bazı ölçümleri örtük olarak tanımlar. Sonuç olarak, hangi ölçümlerin hesaplanması ve bu hesaplamaların nasıl gerçekleştirileceğini belirlemek ölçüm toplama araçlarına bağlıdır, ancak her bir araçta geliştiricinin amacını belirten bazı varsayılan kurallar vardır. Sayaç araçları için kural, toplama araçlarının toplam sayıyı ve/veya sayımın artma hızını göstermesidir.
Counter<int>
ve CreateCounter<int>(...)
üzerinde int
genel parametresi, bu sayacın Int32.MaxValue'a kadar olan değerleri depolayabilmesi gerektiğini tanımlar. Depolamanız gereken verilerin boyutuna ve kesirli değerlerin gerekip gerekmediğine bağlı olarak byte
, short
, int
, long
, float
, double
veya decimal
kullanabilirsiniz.
Uygulamayı çalıştırın ve şimdilik böyle kalsın. Ölçümleri bir sonraki adımda görüntüleyeceğiz.
> dotnet run
Press any key to exit
En iyi yöntemler
Bağımlılık Enjeksiyonu (DI) kapsayıcısında kullanılmak üzere tasarlanmayan kodlar için Metre'yi bir kez oluşturmalı ve statik bir değişkende depolamalısınız. DI kullanan kitaplıklardaki kullanım için statik değişkenler bir anti-desen olarak kabul edilir ve aşağıdaki DI örneği daha idiomatic bir yaklaşım gösterir. Her kitaplık veya kitaplık alt bileşeni kendi Meteroluşturabilir (ve genellikle oluşturmalıdır). Uygulama geliştiricilerinin ölçüm gruplarını ayrı olarak kolayca etkinleştirip devre dışı bırakabilmeyi takdir edeceğini düşünüyorsanız mevcut ölçümlerden birini yeniden kullanmak yerine yeni bir Ölçüm oluşturmayı göz önünde bulundurun.
Meter oluşturucuya geçirilen ad, diğer Sayaçlardan ayırt edilebilmesi için benzersiz olmalıdır. noktalı hiyerarşik adlar kullanan OpenTelemetry adlandırma yönergelerini
öneririz. İzlenen kod için derleme adları veya ad alanı adları genellikle iyi bir seçimdir. Bir derleme, ikinci ve bağımsız bir derlemede kod izleme araçları eklerse, adın, kodu izlenen derlemeyi değil, Meter'ı tanımlayan derlemeye dayandırılması gerekir. .NET, Araçlar için herhangi bir adlandırma düzenini zorlamaz, ancak aynı öğedeki birden çok sözcük arasında ayırıcı olarak küçük harfli noktalı hiyerarşik adlar ve alt çizgi ('_') kullananOpenTelemetry adlandırma yönergelerini
izlemenizi öneririz. Tüm metrik araçları, nihai metrik adının bir parçası olarak Metre adını korumaz. Bu yüzden, aracın adını kendi başına küresel olarak benzersiz hale getirmek faydalı olur. Örnek araç adları:
contoso.ticket_queue.duration
contoso.reserved_tickets
contoso.purchased_tickets
Aletler oluşturmak ve ölçüm kaydetmek için API'ler iş parçacığı açısından güvenlidir. .NET kitaplıklarında çoğu örnek yöntemi, birden çok iş parçacığından aynı nesnede çağrıldığında eşitleme gerektirir, ancak bu durumda gerekli değildir.
Ölçümleri kaydetmek için alet API'leri (bu örnekteAdd) genellikle veri toplanmadığında <10 ns veya ölçümler yüksek performanslı bir koleksiyon kitaplığı veya aracı tarafından toplanırken onlarca ile yüzlerce nanosaniye arasında çalışır. Bu, bu API'lerin çoğu durumda liberal olarak kullanılmasını sağlar, ancak performansa son derece duyarlı olan kodlara dikkat edin.
Yeni ölçümü görüntüleme
Ölçümleri depolamak ve görüntülemek için birçok seçenek vardır. Bu eğitimde anlık analiz için yararlı olan dotnet-counters aracı kullanılır. Diğer seçenekler için ölçüm koleksiyonu öğreticisini için de görebilirsiniz. dotnet-counters aracı henüz yüklü değilse, yüklemek için SDK'yı kullanın:
> dotnet tool update -g dotnet-counters
You can invoke the tool using the following command: dotnet-counters
Tool 'dotnet-counters' (version '7.0.430602') was successfully installed.
Örnek uygulama çalışmaya devam ederken yeni sayacı izlemek için dotnet-counters kullanın:
> dotnet-counters monitor -n metric-demo.exe --counters HatCo.Store
Press p to pause, r to resume, q to quit.
Status: Running
[HatCo.Store]
hatco.store.hats_sold (Count / 1 sec) 4
Beklendiği gibi, HatCo mağazasının her saniye sürekli olarak 4 şapka sattığını görebilirsiniz.
Bağımlılık enjeksiyonu yoluyla Metre alma
Önceki örnekte Ölçüm, new
ile oluşturup statik bir alana atayarak elde edildi. Bağımlılık ekleme (DI) kullanılırken statiklerin bu şekilde kullanılması iyi bir yaklaşım değildir. ASP.NET Core gibi DI veya Genel Ana Bilgisayarolan uygulamalar gibi DI kullanan kodda, IMeterFactorykullanarak Meter nesnesini oluşturun. .NET 8'den itibaren, konaklar hizmet kapsayıcısında IMeterFactory'ı otomatik olarak kaydeder veya türü herhangi bir IServiceCollection içinde AddMetricsçağırarak elle kaydedebilirsiniz.
Ölçüm fabrikası ölçümleri DI ile tümleştirerek Aynı adı kullansalar bile Farklı hizmet koleksiyonlarındaki Ölçümleri birbirinden yalıtılmış halde tutar. Bu, paralel çalışan birden çok testin yalnızca aynı test çalışması içinden üretilen ölçümleri gözlemlemesi için test için özellikle yararlıdır.
DI için tasarlanmış bir türde Ölçüm elde etmek için oluşturucuya bir IMeterFactory parametresi ekleyin, ardından Createçağrısı yapın. Bu örnekte bir ASP.NET Core uygulamasında IMeterFactory kullanımı gösterilmektedir.
Araçları tutmak için bir tür tanımlayın:
public class HatCoMetrics
{
private readonly Counter<int> _hatsSold;
public HatCoMetrics(IMeterFactory meterFactory)
{
var meter = meterFactory.Create("HatCo.Store");
_hatsSold = meter.CreateCounter<int>("hatco.store.hats_sold");
}
public void HatsSold(int quantity)
{
_hatsSold.Add(quantity);
}
}
Türü, DI kapsayıcısı içinde Program.cs
'de kaydedin.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<HatCoMetrics>();
Ölçüm türünü ve kayıt değerlerini gerektiğinde ekleyin. Ölçüm türü DI'de kayıtlı olduğundan MVC denetleyicileri, minimum API'ler veya DI tarafından oluşturulan başka bir türle kullanılabilir:
app.MapPost("/complete-sale", ([FromBody] SaleModel model, HatCoMetrics metrics) =>
{
// ... business logic such as saving the sale to a database ...
metrics.HatsSold(model.QuantitySold);
});
En iyi yöntemler
-
System.Diagnostics.Metrics.Meter IDisposable uygular, ancak IMeterFactory oluşturduğu tüm
Meter
nesnelerin ömrünü otomatik olarak yönetir ve DI kapsayıcısı atıldığında bunları yok eder.Meter
Dispose()
çağırmak için ek kod eklemek gereksizdir ve hiçbir etkisi olmaz.
Alet türleri
Şu ana kadar yalnızca bir Counter<T> aracı gösterdik, ancak daha fazla araç türü mevcut. Araçlar iki şekilde farklılık gösterir:
- Varsayılan ölçüm hesaplamaları - Ölçüm ölçümlerini toplayan ve analiz eden araçlar, alete bağlı olarak farklı varsayılan ölçümleri hesaplar.
- Toplanan verilerin depolanması - En kullanışlı ölçümler, verilerin birçok ölçümden toplanması gerekir. Bir seçenek, çağıranın rastgele zamanlarda tek tek ölçümler sağlaması ve toplamayı koleksiyon aracının yönetmesidir. Alternatif olarak, arayan toplama ölçümlerini yönetebilir ve bir geri aramada isteğe bağlı olarak sağlayabilir.
Şu anda kullanılabilir araç türleri:
Sayacı (CreateCounter) - Bu araç zaman içinde artan bir değeri izler ve çağıran Addkullanarak artışları bildirir. Araçların çoğu toplamı ve toplamdaki değişiklik oranını hesaplar. Yalnızca bir şey gösteren araçlar için değişiklik oranı önerilir. Örneğin, çağıranın 1, 2, 4, 5, 4, 3 ardışık değerlerle her saniye
Add()
çağırdığını varsayalım. Toplama aracı her üç saniyede bir güncelleştirilirse, üç saniye sonra toplam 1+2+4=7 ve altı saniye sonra toplam 1+2+4+5+4+3=19 olur. Değişiklik oranı (current_total - previous_total) şeklindedir, bu nedenle araç üç saniyede 7-0=7 ve altı saniye sonra 19-7=12 değerini bildirir.UpDownCounter (CreateUpDownCounter) - Bu araç, zaman içinde artabilecek veya düşebilecek bir değeri izler. Çağıran, Addkullanarak artışları ve düşüşleri bildirir. Örneğin, çağıranın 1, 5, -2, 3, -1, -3 ardışık değerlerle her saniye
Add()
çağırdığını varsayalım. Toplama aracı her üç saniyede bir güncelleştirilirse, üç saniye sonra toplam 1+5-2=4 ve altı saniye sonra toplam 1+5-2+3-1-3=3 olur.ObservableCounter (CreateObservableCounter) - Bu araç Sayaç'a benzer, ancak çağıran artık toplamın korunmasından sorumludur. Arama yapan, ObservableCounter oluşturulduğunda bir geri çağırma temsilcisi sağlar ve araçlar geçerli toplamı gözlemleme ihtiyacı duyduğunda geri çağırma devreye alınır. Örneğin, bir koleksiyon aracı her üç saniyede bir güncelleştirilirse, geri çağırma işlevi de üç saniyede bir çağrılır. Çoğu araç, kullanılabilir toplamda hem toplam hem de değişiklik oranına sahip olur. Yalnızca bir tane gösterilebilirse, değişim hızı önerilir. Geri arama ilk çağrıda 0, üç saniye sonra yeniden çağrıldığında 7 ve altı saniye sonra çağrıldığında 19 döndürürse, araç bu değerleri toplamlar olarak değişmeden bildirir. Değişiklik oranı için araç üç saniye sonra 7-0=7 ve altı saniye sonra 19-7=12 değerini gösterir.
ObservableUpDownCounter (CreateObservableUpDownCounter) - Bu araç UpDownCounter'a benzer, ancak çağıranın toplam toplamı korumakla artık sorumlu olması gerekir. Çağıran, ObservableUpDownCounter oluşturulduğunda bir dönüş çağrısı temsilcisi sağlar ve araçlar geçerli toplamı gözlemlemek istediklerinde dönüş çağrısı gerçekleştirilir. Örneğin, bir koleksiyon aracı her üç saniyede bir güncelleştirilirse, geri çağırma işlevi de üç saniyede bir çağrılır. Geri çağırma fonksiyonu tarafından döndürülen değer, toplama aracında toplam olarak değiştirilmeden gösterilecektir.
Ölçer (CreateGauge) - Bu araç, çağıranın Record yöntemini kullanarak ölçümün geçerli değerini ayarlamasına olanak tanır. Yöntemi yeniden çağırarak değer istediğiniz zaman güncelleştirilebilir ve ölçüm toplama aracı en son ayarlanan değeri görüntüler.
ObservableGauge (CreateObservableGauge) - Bu araç, çağıranın ölçülen değerin doğrudan ölçüm olarak geçirildiği bir geri çağırma işlevi sağlamasına olanak tanır. Koleksiyon aracı her güncelleştirildiğinde geri çağırım fonksiyonu çağrılır ve fonksiyon tarafından döndürülen değer araçta görüntülenir.
Histogram (CreateHistogram) - Bu araç ölçümlerin dağılımını izler. Bir ölçü kümesini açıklamanın tek bir kurallı yolu yoktur, ancak histogramları veya hesaplanan yüzdebirlik değerleri kullanmak için araçlar önerilir. Örneğin, çağıranın toplama aracının güncelleştirme aralığı sırasında bu ölçümleri kaydetmek için Record çağırmış olduğunu varsayalım: 1,5,2,3,10,9,7,4,6,8. Bir toplama aracı, bu ölçümlerin 50. , 90. ve 95. yüzdebirlik değerlerinin sırasıyla 5, 9 ve 9 olduğunu bildirebilir.
Not
Histogram aracı oluştururken önerilen demet sınırlarını ayarlama hakkında ayrıntılı bilgi için bkz. Histogram araçlarını özelleştirmek için Öneri kullanma.
Bir alet türü seçerken en iyi yöntemler
Öğeleri veya yalnızca zaman içinde artan diğer değerleri saymak için Counter veya ObservableCounter kullanın. Mevcut koda eklenmesi daha kolay olana bağlı olarak Counter ve ObservableCounter arasında seçim yapın: her artış işlemi için bir API çağrısı veya kodun koruduğu bir değişkenden geçerli toplamı okuyacak bir geri çağırma fonksiyonu. Performansın önemli olduğu son derece sık erişimli kod yollarında ve Add kullanılması iş parçacığı başına saniyede bir milyondan fazla çağrı oluşturabilir ve ObservableCounter'ın kullanılması iyileştirme için daha fazla fırsat sunabilir.
Zamanlama için histogram genellikle tercih edilir. Genellikle ortalamalar veya toplamlar yerine bu dağılımların kuyruğunu (90. , 95. , 99. yüzdebirlik) anlamak yararlıdır.
Önbellek isabet oranları veya önbellek, kuyruk ve dosya boyutları gibi diğer yaygın durumlar genellikle
UpDownCounter
veyaObservableUpDownCounter
için uygundur. Mevcut koda eklenmesi daha kolay olan koda bağlı olarak bunlar arasından seçim yapın: her bir artış ve azaltma işlemi için api çağrısı veya kodun koruduğu değişkenden geçerli değeri okuyacak bir geri çağırma.
Not
.NET'in eski bir sürümünü veya UpDownCounter
ve ObservableUpDownCounter
(sürüm 7'den önce) desteklemeyen bir DiagnosticSource NuGet paketi kullanıyorsanız, ObservableGauge
genellikle iyi bir alternatiftir.
Farklı alet türleri örneği
Daha önce başlatılan örnek işlemi durdurun ve Program.cs
'daki örnek kodu şununla değiştirin:
using System;
using System.Diagnostics.Metrics;
using System.Threading;
class Program
{
static Meter s_meter = new Meter("HatCo.Store");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>("hatco.store.hats_sold");
static Histogram<double> s_orderProcessingTime = s_meter.CreateHistogram<double>("hatco.store.order_processing_time");
static int s_coatsSold;
static int s_ordersPending;
static Random s_rand = new Random();
static void Main(string[] args)
{
s_meter.CreateObservableCounter<int>("hatco.store.coats_sold", () => s_coatsSold);
s_meter.CreateObservableGauge<int>("hatco.store.orders_pending", () => s_ordersPending);
Console.WriteLine("Press any key to exit");
while(!Console.KeyAvailable)
{
// Pretend our store has one transaction each 100ms that each sell 4 hats
Thread.Sleep(100);
s_hatsSold.Add(4);
// Pretend we also sold 3 coats. For an ObservableCounter we track the value in our variable and report it
// on demand in the callback
s_coatsSold += 3;
// Pretend we have some queue of orders that varies over time. The callback for the orders_pending gauge will report
// this value on-demand.
s_ordersPending = s_rand.Next(0, 20);
// Last we pretend that we measured how long it took to do the transaction (for example we could time it with Stopwatch)
s_orderProcessingTime.Record(s_rand.Next(5, 15)/1000.0);
}
}
}
Yeni işlemi çalıştırın ve göstergeleri görüntülemek için diğer bir kabukta daha önce yaptığınız gibi dotnet-counters kullanın.
> dotnet-counters monitor -n metric-demo.exe --counters HatCo.Store
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[HatCo.Store]
hatco.store.coats_sold (Count) 8,181
hatco.store.hats_sold (Count) 548
hatco.store.order_processing_time
Percentile
50 0.012
95 0.013
99 0.013
hatco.store.orders_pending 9
Bu örnekte, değerlerinizin biraz değişmesi için rastgele oluşturulan bazı sayılar kullanılır. Dotnet sayaçları Histogram ölçüm araçlarını üç yüzdelik istatistik (50. yüzdelik, 95. yüzdelik ve 99. yüzdelik) olarak işler, ancak diğer araçlar dağılımı farklı özetleyebilir veya daha fazla yapılandırma seçeneği sunabilir.
En iyi yöntemler
Histogramlar, bellekte diğer ölçüm türlerinden çok daha fazla veri depolama eğilimindedir. Ancak, tam bellek kullanımı kullanılan koleksiyon aracı tarafından belirlenir. Histogram ölçümlerinin büyük bir sayısını (>100) tanımlıyorsanız, kullanıcılara tümünü aynı anda etkinleştirmeme veya duyarlılığı azaltarak araçlarını bellek tasarrufu sağlayacak şekilde yapılandırma konusunda rehberlik vermeniz gerekebilir. Bazı koleksiyon araçlarının aşırı bellek kullanımını önlemek için izleyecekleri eşzamanlı Histogram sayısı üzerinde sabit sınırları olabilir.
Tüm gözlemlenebilir araçlar için geri çağırmalar sırayla çağrılır, bu nedenle uzun süren geri çağırmalar tüm ölçümlerin toplanmasını geciktirebilir veya engelleyebilir. Önbelleğe alınmış bir değeri hızlı bir şekilde okumayı, ölçüm döndürmemeyi veya bir özel durum fırlatmayı, uzun süre çalışabilecek veya engelleyici bir işlem gerçekleştirmeye tercih edin.
ObservableCounter, ObservableUpDownCounter ve ObservableGauge geri çağırmaları genellikle değerleri güncelleştiren kodla eşitlenmemiş bir iş parçacığında gerçekleşir. Bellek erişimini eşitlemek veya eşitlenmemiş erişimin kullanılmasından kaynaklanabilir tutarsız değerleri kabul etmek sizin sorumluluğunuzdadır. Erişimi eşitlemek için yaygın yaklaşımlar, kilit kullanmak veya Volatile.Read ve Volatile.Writeçağırmaktır.
CreateObservableGauge ve CreateObservableCounter işlevleri bir izleme nesnesi döndürür, ancak çoğu durumda nesneyle daha fazla etkileşime gerek olmadığından bunu bir değişkene kaydetmeniz gerekmez. Bunu diğer araçlar için yaptığımız gibi statik bir değişkene atamak yasaldır ancak hataya açıktır çünkü C# statik başlatma yavaştır ve değişkene genellikle hiçbir zaman başvurulmaz. İşte sorunun bir örneği:
using System; using System.Diagnostics.Metrics; class Program { // BEWARE! Static initializers only run when code in a running method refers to a static variable. // These statics will never be initialized because none of them were referenced in Main(). // static Meter s_meter = new Meter("HatCo.Store"); static ObservableCounter<int> s_coatsSold = s_meter.CreateObservableCounter<int>("hatco.store.coats_sold", () => s_rand.Next(1,10)); static Random s_rand = new Random(); static void Main(string[] args) { Console.ReadLine(); } }
Açıklamalar ve birimler
Araçlar isteğe bağlı açıklamalar ve birimler belirtebilir. Bu değerler tüm metrik hesaplamalarına göre belirsizdir, ancak mühendislerin verilerin nasıl yorumlanacağını anlamasına yardımcı olmak için toplama aracı kullanıcı arabiriminde gösterilebilir. Daha önce başlattığınız örnek işlemi durdurun ve Program.cs
'daki örnek kodu şununla değiştirin:
using System;
using System.Diagnostics.Metrics;
using System.Threading;
class Program
{
static Meter s_meter = new Meter("HatCo.Store");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(name: "hatco.store.hats_sold",
unit: "{hats}",
description: "The number of hats sold in our store");
static void Main(string[] args)
{
Console.WriteLine("Press any key to exit");
while(!Console.KeyAvailable)
{
// Pretend our store has a transaction each 100ms that sells 4 hats
Thread.Sleep(100);
s_hatsSold.Add(4);
}
}
}
Yeni işlemi çalıştırın ve ölçümleri görüntülemek için ikinci bir kabukta dotnet-counters'ı her zamanki gibi kullanın.
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[HatCo.Store]
hatco.store.hats_sold ({hats}) 40
dotnet-counters şu anda kullanıcı arabirimindeki açıklama metnini kullanmaz, ancak sağlandığında birimi gösterir. Bu durumda, "{hats}" ifadesinin önceki açıklamalarda görünen genel "Count" terimini değiştirdiğini görürsünüz.
En iyi yöntemler
.NET API'leri herhangi bir dizenin birim olarak kullanılmasına izin verir, ancak birim adları için uluslararası bir standart olan UCUMkullanmanızı öneririz. "{hats}" çevresindeki küme ayraçları, UCUM standardının bir parçası olduğunu ve bunun saniye veya bayt gibi standartlaştırılmış bir anlama sahip birim adı yerine açıklayıcı bir not olduğunu belirtir.
Oluşturucuda belirtilen birim, tek bir ölçüm için uygun birimleri açıklamalıdır. Bu bazen bildirilen son ölçümdeki birimlerden farklı olacaktır. Bu örnekte, her ölçüm bir miktar şapkadır, bu nedenle "{hats}" yapıcıya iletilecek uygun birimdir. Koleksiyon aracı değişiklik oranını hesaplamış ve hesaplanmış hız ölçümü için uygun birimin {hats}/sn olduğunu kendi başına türetmiş olabilir.
Zaman ölçümlerini kaydederken, kayan nokta veya çift değer olarak kaydedilen saniye birimlerini tercih edin.
Çok boyutlu ölçümler
Ölçümler, verilerin analiz için kategorilere ayrılmasını sağlayan etiketler olarak adlandırılan anahtar-değer çiftleriyle de ilişkilendirilebilir. Örneğin, HatCo yalnızca satılan şapka sayısını değil, aynı zamanda hangi boyutta ve renkte olduklarını da kaydetmek isteyebilir. HatCo mühendisleri verileri daha sonra analiz ederken toplamları boyuta, renge veya her ikisinin herhangi bir bileşimine göre ayırabilir.
Sayaç ve Histogram etiketleri, bir veya daha fazla KeyValuePair
bağımsız değişkeni alan Add ve Record aşırı yüklemelerinde belirtilebilir. Mesela:
s_hatsSold.Add(2,
new KeyValuePair<string, object?>("product.color", "red"),
new KeyValuePair<string, object?>("product.size", 12));
Program.cs
kodunu değiştirin ve uygulamayı ve dotnet-counters'ı daha önce olduğu gibi yeniden çalıştırın:
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Threading;
class Program
{
static Meter s_meter = new Meter("HatCo.Store");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>("hatco.store.hats_sold");
static void Main(string[] args)
{
Console.WriteLine("Press any key to exit");
while(!Console.KeyAvailable)
{
// Pretend our store has a transaction, every 100ms, that sells two size 12 red hats, and one size 19 blue hat.
Thread.Sleep(100);
s_hatsSold.Add(2,
new KeyValuePair<string,object?>("product.color", "red"),
new KeyValuePair<string,object?>("product.size", 12));
s_hatsSold.Add(1,
new KeyValuePair<string,object?>("product.color", "blue"),
new KeyValuePair<string,object?>("product.size", 19));
}
}
}
Dotnet sayaçları artık temel bir kategori gösteriyor:
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[HatCo.Store]
hatco.store.hats_sold (Count)
product.color product.size
blue 19 73
red 12 146
ObservableCounter ve ObservableGauge için, oluşturucuya geçirilen geri çağırmada etiketli ölçümler sağlanabilir:
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Threading;
class Program
{
static Meter s_meter = new Meter("HatCo.Store");
static void Main(string[] args)
{
s_meter.CreateObservableGauge<int>("hatco.store.orders_pending", GetOrdersPending);
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
static IEnumerable<Measurement<int>> GetOrdersPending()
{
return new Measurement<int>[]
{
// pretend these measurements were read from a real queue somewhere
new Measurement<int>(6, new KeyValuePair<string,object?>("customer.country", "Italy")),
new Measurement<int>(3, new KeyValuePair<string,object?>("customer.country", "Spain")),
new Measurement<int>(1, new KeyValuePair<string,object?>("customer.country", "Mexico")),
};
}
}
Dotnet-counters ile daha önce olduğu gibi çalıştırıldığında sonuç şöyledir:
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[HatCo.Store]
hatco.store.orders_pending
customer.country
Italy 6
Mexico 1
Spain 3
En iyi yöntemler
API, herhangi bir nesnenin etiket değeri olarak kullanılmasına izin vermesine rağmen, sayısal türler ve dizeler koleksiyon araçları tarafından tahmin edilir. Diğer türler belirli bir koleksiyon aracı tarafından desteklenebilir veya desteklenmeyebilir.
Etiket adlarının OpenTelemetry adlandırma yönergelerini izlemesini öneririz, aynı öğedeki birden çok sözcüğü ayırmak için '_' karakterleriyle küçük noktalı hiyerarşi adları kullanır. Etiket adları farklı ölçümlerde veya diğer telemetri kayıtlarında yeniden kullanılıyorsa, kullanıldıkları her yerde aynı anlama ve yasal değerler kümesine sahip olmaları gerekir.
Örnek etiket adları:
customer.country
store.payment_method
store.purchase_result
Uygulamada etiket değerlerinin çok büyük veya ilişkisiz birleşimlerinin kaydedilmekte olmasına dikkat edin. .NET API uygulaması bunu işleyebilse de, koleksiyon araçları büyük olasılıkla her etiket bileşimiyle ilişkili ölçüm verileri için depolama alanı ayırır ve bu çok büyük olabilir. Örneğin, HatCo'nun 10 farklı şapka rengine ve 25 şapka boyutuna sahip olması ve takip etmek için 10*25=250 satış toplamına kadar olması sorun değil. Ancak, HatCo satış için CustomerID olan üçüncü bir etiket eklediyse ve dünya çapında 100 milyon müşteriye satılıyorsa, şimdi büyük olasılıkla milyarlarca farklı etiket bileşimi kaydediliyor olabilir. Ölçüm toplama araçlarının çoğu, teknik sınırlar içinde kalmak için verileri düşürür veya veri depolama ve işleme maliyetlerini karşılamak için büyük parasal giderler ortaya çıkabilir. Her toplama aracının uygulanması sınırlarını belirler, ancak büyük olasılıkla bir alet için 1000'den az kombinasyon güvenlidir. 1000'in üzerindeki birleşimler için toplama aracının filtreleme uygulaması veya yüksek ölçekte çalışacak şekilde tasarlanmış olması gerekir. Histogram uygulamaları diğer ölçümlerden çok daha fazla bellek kullanma eğilimindedir, bu nedenle güvenli sınırlar 10-100 kat daha düşük olabilir. Çok sayıda benzersiz etiket bileşimi olmasını bekliyorsanız günlükler, işlem veritabanları veya büyük veri işleme sistemleri gerekli ölçekte çalışmak için daha uygun çözümler olabilir.
Çok fazla sayıda etiket bileşimine sahip olacak araçlar için bellek yükünü azaltmaya yardımcı olmak için daha küçük bir depolama türü kullanmayı tercih edin. Örneğin,
Counter<short>
içinshort
depolamak etiket bileşimi başına yalnızca 2 bayt,Counter<double>
içindouble
ise etiket bileşimi başına 8 bayt kaplar.Koleksiyon araçlarının, ölçümleri aynı alete kaydetmeye yönelik her çağrı için aynı etiket adları kümesini aynı sırada belirten kod için iyileştirmesi teşvik edilir. Add ve Record sık sık çağırması gereken yüksek performanslı kodlar için, her çağrı için aynı etiket adları dizisini kullanmayı tercih edin.
.NET API'si, Add ve Record çağrılarında tek tek belirtilen üç veya daha az etiket için bellek ayırma yapmadan çalışacak şekilde optimize edilmiştir. Daha fazla sayıda etiket içeren ayırmaları önlemek için TagListkullanın. Genel olarak, daha fazla etiket kullanıldıkçe bu çağrıların performans yükü artar.
Not
OpenTelemetry etiketleri 'öznitelikler' olarak ifade eder. Bunlar aynı işlev için iki farklı addır.
Histogram araçlarını özelleştirmek için Öneri kullanma
Histogramları kullanırken, kaydedilen değerlerin dağılımını en iyi şekilde nasıl temsil etmek gerektiğine karar vermek için verileri toplayan araç veya kitaplığın sorumluluğundadır. Yaygın bir strateji (ve OpenTelemetrykullanılırken varsayılan mod
Histogram verilerini toplayan araç veya kitaplık, kullanacağı demetleri tanımlamakla sorumludur. OpenTelemetry kullanılırken varsayılan demet yapılandırması: [ 0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000 ]
.
Varsayılan değerler her Histogram için en iyi ayrıntı düzeyine neden olmayabilir. Örneğin, bir saniyenin altındaki istek sürelerinin tümü 0
kovasına girer.
Histogram verilerini toplayan araç veya kitaplık, kullanıcıların demet yapılandırmasını özelleştirmesine olanak sağlayan mekanizmalar sunabilir. Örneğin, OpenTelemetrybir
Deneyimi geliştirmek için System.Diagnostics.DiagnosticSource
paketinin 9.0.0
sürümü (InstrumentAdvice<T>) API'sini kullanıma sunar.
InstrumentAdvice
API, araç yazarları tarafından önerilen varsayılan aralık sınırları kümesini belirli bir Histogram için belirtmek üzere kullanılabilir. Histogram verilerini toplayan araç veya kitaplık daha sonra toplamayı yapılandırırken bu değerleri kullanmayı seçebilir ve bu da kullanıcılar için daha sorunsuz bir ekleme deneyimi sağlar. Bu,1.10.0 sürümünden itibaren
Önemli
Genel olarak daha fazla demet, belirli bir Histogram için daha hassas verilere yol açar, ancak her demet, toplanan ayrıntıları depolamak için belleğe ihtiyaç duyar ve bir ölçümü işlerken doğru demeti bulmak için CPU maliyeti vardır.
InstrumentAdvice
API aracılığıyla önerecek demet sayısını seçerken duyarlık ve CPU/bellek tüketimi arasındaki dengeleri anlamak önemlidir.
Aşağıdaki kodda önerilen varsayılan demetleri ayarlamak için InstrumentAdvice
API'sinin kullanıldığı bir örnek gösterilmektedir.
using System;
using System.Diagnostics.Metrics;
using System.Threading;
class Program
{
static Meter s_meter = new Meter("HatCo.Store");
static Histogram<double> s_orderProcessingTime = s_meter.CreateHistogram<double>(
name: "hatco.store.order_processing_time",
unit: "s",
description: "Order processing duration",
advice: new InstrumentAdvice<double> { HistogramBucketBoundaries = [0.01, 0.05, 0.1, 0.5, 1, 5] });
static Random s_rand = new Random();
static void Main(string[] args)
{
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
// Pretend our store has one transaction each 100ms
Thread.Sleep(100);
// Pretend that we measured how long it took to do the transaction (for example we could time it with Stopwatch)
s_orderProcessingTime.Record(s_rand.Next(5, 15) / 1000.0);
}
}
}
Ek bilgiler
OpenTelemetry'deki açık demet Histogramları hakkında daha fazla ayrıntı için bkz:
Özel ölçümleri test edin
MetricCollector<T>kullanarak eklediğiniz özel ölçümleri test etmek mümkündür. Bu tür, belirli araçlardaki ölçümleri kaydetmeyi ve değerlerin doğru olduğunu onaylamayı kolaylaştırır.
Bağımlılık enjeksiyonu ile test yapma
Aşağıdaki kodda bağımlılık ekleme ve IMeterFactory kullanan kod bileşenleri için örnek bir test çalışması gösterilmektedir.
public class MetricTests
{
[Fact]
public void SaleIncrementsHatsSoldCounter()
{
// Arrange
var services = CreateServiceProvider();
var metrics = services.GetRequiredService<HatCoMetrics>();
var meterFactory = services.GetRequiredService<IMeterFactory>();
var collector = new MetricCollector<int>(meterFactory, "HatCo.Store", "hatco.store.hats_sold");
// Act
metrics.HatsSold(15);
// Assert
var measurements = collector.GetMeasurementSnapshot();
Assert.Equal(1, measurements.Count);
Assert.Equal(15, measurements[0].Value);
}
// Setup a new service provider. This example creates the collection explicitly but you might leverage
// a host or some other application setup code to do this as well.
private static IServiceProvider CreateServiceProvider()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddMetrics();
serviceCollection.AddSingleton<HatCoMetrics>();
return serviceCollection.BuildServiceProvider();
}
}
Her MetricCollector nesnesi tek bir Alet için tüm ölçümleri kaydeder. Birden çok araçtan ölçümleri doğrulamanız gerekiyorsa, her biri için bir MetricCollector oluşturun.
Bağımlılık eklemeden test etme
Statik bir alanda paylaşılan genel Ölçüm nesnesi kullanan kodu test etmek de mümkündür, ancak bu tür testlerin paralel olarak çalıştırılmayacak şekilde yapılandırıldığından emin olun. Meter nesnesi paylaşıldığından, bir testteki MetricCollector paralel çalışan diğer testlerden oluşturulan ölçümleri gözlemler.
class HatCoMetricsWithGlobalMeter
{
static Meter s_meter = new Meter("HatCo.Store");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>("hatco.store.hats_sold");
public void HatsSold(int quantity)
{
s_hatsSold.Add(quantity);
}
}
public class MetricTests
{
[Fact]
public void SaleIncrementsHatsSoldCounter()
{
// Arrange
var metrics = new HatCoMetricsWithGlobalMeter();
// Be careful specifying scope=null. This binds the collector to a global Meter and tests
// that use global state should not be configured to run in parallel.
var collector = new MetricCollector<int>(null, "HatCo.Store", "hatco.store.hats_sold");
// Act
metrics.HatsSold(15);
// Assert
var measurements = collector.GetMeasurementSnapshot();
Assert.Equal(1, measurements.Count);
Assert.Equal(15, measurements[0].Value);
}
}