Aracılığıyla paylaş


Ölçüm oluşturma

Bu makale şunlar için geçerlidir: ✔️ .NET Core 6 ve sonraki sürümleri✔️ .NET Framework 4.6.1 ve sonraki sürümleri

.NET uygulamaları, önemli ölçümleri izlemek için API'ler kullanılarak System.Diagnostics.Metrics 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.

Dekont

.NET'in eventcounters ve System.Diagnostics.PerformanceCountergibi burada ele alınmayan 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

Önkoşullar: .NET Core 6 SDK veya sonraki bir sürüm

System.Diagnostics.DiagnosticSource NuGet paketi sürüm 8 veya sonraki bir sürüme başvuran yeni bir konsol uygulaması oluşturun. .NET 8+ hedefli uygulamalar varsayılan olarak bu başvuruya sahiptir. Ardından içindeki kodu Program.cs 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);
        }
    }
}

Türü System.Diagnostics.Metrics.Meter , adlandırılmış bir araç grubu oluşturmak için kitaplığın giriş noktasıdır. Ölçümler, ölçümleri hesaplamak için gereken sayısal ölçümleri kaydeder. Burada "hatco.store.hats_sold" adlı bir Sayaç aracı oluşturmak için kullanılır CreateCounter . Her rol yapma işlemi sırasında kod, satılan şapkaların ölçümünün (bu örnekte 4) kaydedilmesini çağırır Add . "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.

ve Counter<int>CreateCounter<int>(...) üzerindeki genel parametresiint, bu sayacın değerine kadar Int32.MaxValueolan değerleri depolayabilmesi gerektiğini tanımlar. Depolamanız gereken verilerin boyutuna ve kesirli değerlerin bytelongdecimalshortintfloatdoublegerekip gerekmediğine bağlı olarak , veya türlerinden herhangi birini kullanabilirsiniz.

Uygulamayı çalıştırın ve şimdilik çalışır durumda bırakı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 Ekleme (DI) kapsayıcısında kullanılmak üzere tasarlanmamış kodlar için Ölçüm'leri bir kez oluşturun ve statik değişkende depolayın. 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 idiyomatik bir yaklaşım gösterir. Her kitaplık veya kitaplık alt bileşeni kendi Meteröğesini oluş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.

  • Oluşturucuya Meter geçirilen ad, diğer Ölçümlerden ayırt etmek için benzersiz olmalıdır. Noktalı hiyerarşik adlar kullanan OpenTelemetry adlandırma yönergelerini öneririz. İzleme yapılan kod için derleme adları veya ad alanı adları genellikle iyi bir seçimdir. Bir derleme ikinci ve bağımsız bir derlemede kod için izleme eklerse, adın kodu izlenen derlemeyi değil Meter'ı tanımlayan derlemeyi temel alması 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 noktalı hiyerarşik adlar ve alt çizgi ('_') kullanan OpenTelemetry adlandırma yönergelerini izlemenizi öneririz. Ölçüm araçlarının tümü Ölçüm adını son ölçüm adının bir parçası olarak korumaz, bu nedenle ölçüm aracının adını tek başına genel olarak benzersiz hale getirmek yararlı olur.

    Örnek araç adları:

    • contoso.ticket_queue.duration
    • contoso.reserved_tickets
    • contoso.purchased_tickets
  • ölçümler 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 (Add bu örnekte) 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 öğreticide geçici analiz için yararlı olan dotnet-counters aracı kullanılır. Diğer alternatifler için ölçüm toplama öğreticisini de görebilirsiniz. dotnet-counters aracı henüz yüklü değilse SDK'yı kullanarak yükleyin:

> 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 ekleme yoluyla Ölçüm alma

Önceki örnekte Ölçüm, ile new oluşturup statik bir alana atanarak 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 kullanan kodda veya Genel Ana Bilgisayarlı uygulamalarda kullanarak IMeterFactoryMeter nesnesini oluşturun. .NET 8'den başlayarak, konaklar hizmet kapsayıcısında otomatik olarak kaydolacak IMeterFactory veya çağırarak AddMetricstürü herhangi bir IServiceCollection kapsayıcıya el ile 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 parametre ekleyin ve çağrısı yapın Create. 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ünü içinde Program.csDI kapsayıcısı ile 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 nesnelerin Meter yaşam ömrünü otomatik olarak yönetir ve DI kapsayıcısı atıldığında bunları yok eder. üzerinde çağırmak Dispose()Meteriçin ek kod eklemek gereksizdir ve hiçbir etkisi olmaz.

Alet türleri

Şu ana kadar yalnızca bir Counter<T> alet gösterdik, ancak daha fazla araç türü mevcut. Araçlar iki şekilde farklılık gösterir:

  • Varsayılan ölçüm hesaplamaları - Alet ölçümlerini toplayan ve analiz eden araçlar, alete bağlı olarak farklı varsayılan ölçümleri hesaplar.
  • Toplanan verilerin Depolama - En kullanışlı ölçümlerin 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:

  • Sayaç (CreateCounter) - Bu araç zaman içinde artan bir değeri izler ve çağıran kullanarak Addartış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 bir kez çağırdığını Add() 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, kullanarak Addartışları ve düşüşleri bildirir. Örneğin, çağıranın 1, 5, -2, 3, -1, -3 ardışık değerlerle her saniye bir kez çağırdığını Add() 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ç Counter'a benzer, ancak çağıranın toplanmış toplamı korumakla artık sorumlu olması gerekir. Çağıran, ObservableCounter oluşturulduğunda bir geri çağırma temsilcisi sağlar ve araçların geçerli toplamı gözlemlemeleri gerektiğinde geri çağırma çağrılı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şiklik oranı ö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 toplanmış toplamın korunmasından artık sorumlu olması gerekir. Çağıran, ObservableUpDownCounter oluşturulduğunda bir geri çağırma temsilcisi sağlar ve araçların geçerli toplamı gözlemlemeleri gerektiğinde geri çağırma çağrılır. Ö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 tarafından döndürülen değer toplama aracında toplam olarak değiştirilmeden gösterilir.

  • ObservableGauge (CreateObservableGauge) - Bu araç, çağıranın ölçülen değerin doğrudan ölçüm olarak geçirildiği bir geri çağırma sağlamasına olanak tanır. Koleksiyon aracı her güncelleştirildiğinde geri arama çağrılır ve geri çağırma 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 çağırıldığını Record 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.

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 olan koda bağlı olarak Counter ve ObservableCounter arasında seçim yapın: her artım işlemi için api çağrısı veya kodun koruduğu değişkenden geçerli toplamı okuyacak bir geri çağırma. Performansın önemli olduğu ve kullanımın Add iş parçacığı başına saniyede bir milyondan fazla çağrı oluşturabileceği son derece sık erişimli kod yollarında, 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 önbelleklerin, kuyrukların ve dosyaların boyutları gibi diğer yaygın durumlar genellikle veya ObservableUpDownCounteriçin UpDownCounter 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.

Dekont

.NET'in eski bir sürümünü veya desteklemeyen UpDownCounter bir DiagnosticSource NuGet paketi kullanıyorsanız ( ObservableUpDownCounter sürüm 7'den önce) ObservableGauge genellikle iyi bir alternatiftir.

Farklı alet türleri örneği

Daha önce başlatılan örnek işlemi durdurun ve içindeki örnek kodu Program.cs ş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(0.005, 0.015));
        }
    }
}

Ölçümleri görüntülemek için yeni işlemi çalıştırın ve ikinci bir kabukta daha önce olduğu 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

[HatCo.Store]
    hatco.store.coats_sold (Count / 1 sec)                                27
    hatco.store.hats_sold (Count / 1 sec)                                 36
    hatco.store.order_processing_time
        Percentile=50                                                      0.012
        Percentile=95                                                      0.014
        Percentile=99                                                      0.014
    hatco.store.orders_pending                                             5

Bu örnekte, değerlerinizin biraz değişmesi için rastgele oluşturulan bazı sayılar kullanılır. (Sayaç) ve hatco.store.coats_sold (ObservableCounter) değerlerinin her ikisinin de fiyat olarak gösterildiğini görebilirsiniz hatco.store.hats_sold . ObservableGauge, hatco.store.orders_pendingmutlak bir değer olarak görünür. Dotnet sayaçları Histogram araçlarını üç yüzdebirlik istatistik (50. , 95. ve 99. ) olarak işler, ancak diğer araçlar dağılımı farklı özetler 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. Çok sayıda (>100) Histogram ölçümü tanımlıyorsanız, kullanıcılara tümünü aynı anda etkinleştirmeme veya duyarlılığı azaltarak bellek tasarrufu sağlayacak araçlarını 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ürmeyi veya uzun süre çalışma olasılığı olan veya engelleme işlemini gerçekleştirmek yerine bir özel durum oluşturmayı 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 bir kilit veya çağrı Volatile.ReadVolatile.Writeve kullanmaktı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 ölçüm hesaplamalarına göre normal değildir, ancak mühendislerin verilerin nasıl yorumlanacakları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 içindeki örnek kodu Program.cs ş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);
        }
    }
}

Ölçümleri görüntülemek için yeni işlemi çalıştırın ve ikinci bir kabukta daha önce olduğu gibi dotnet-counters kullanın:

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

[HatCo.Store]
    hatco.store.hats_sold ({hats} / 1 sec)                                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 UCUM'u kullanmanızı öneririz. "{hats}" çevresindeki küme ayraçları, UCUM standardının bir parçasıdır ve bunun saniye veya bayt gibi standartlaştırılmış bir anlama sahip birim adı yerine açıklayıcı bir ek açıklama olduğunu belirtir.

  • Oluşturucuda belirtilen birim, tek bir ölçüm için uygun birimleri açıklamalıdır. Bu bazen son ölçümdeki birimlerden farklı olacaktır. Bu örnekte, her ölçü bir dizi şapkadır, bu nedenle "{hats}" oluşturucuyu geçirmek için uygun birimdir. Koleksiyon aracı bir hız hesaplayıp hesaplanmış ölçüm için uygun birimin {hats}/sn olduğunu kendi başına türetmiştir.

  • 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şken alan ve Record aşırı yüklemelerinde Add belirtilebilir. Örneğin:

s_hatsSold.Add(2,
               new KeyValuePair<string, object>("product.color", "red"),
               new KeyValuePair<string, object>("product.size", 12));

kodunu Program.cs 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

[HatCo.Store]
    hatco.store.hats_sold (Count / 1 sec)
        product.color=blue,product.size=19                                 9
        product.color=red,product.size=12                                 18

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

[HatCo.Store]
    hatco.store.orders_pending
        customer.country=Italy                                             6
        customer.country=Mexico                                            1
        customer.country=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, aynı öğedeki birden çok sözcüğü ayırmak için '_' karakterleriyle küçük harfli noktalı hiyerarşi adları kullanan OpenTelemetry adlandırma yönergelerini izlemesini öneririz. 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 bırakır veya veri depolama ve işlemeyi kapsayacak büyük parasal maliyetler olabilir. 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, için depolamak short etiket bileşimi başına yalnızca 2 bayt, double a için Counter<double> ise etiket bileşimi başına 8 bayt kaplar.Counter<short>

  • 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. Sık ve sık çağrı AddRecord yapması gereken yüksek performanslı kodlar için, her çağrı için aynı etiket adları dizisini kullanmayı tercih edin.

  • .NET API'si, ayrı ayrı belirtilen üç veya daha az etiket içeren ve Record çağrıları için Add ayırma gerektirmeden olacak şekilde iyileştirilmiştir. Daha fazla sayıda etiket içeren ayırmaları önlemek için kullanın TagList. Genel olarak, daha fazla etiket kullanıldıkçe bu çağrıların performans yükü artar.

Dekont

OpenTelemetry etiketleri 'öznitelikler' olarak ifade eder. Bunlar aynı işlev için iki farklı addır.

Özel ölçümleri test edin

kullanarak MetricCollector<T>eklediğiniz tüm ö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 ekleme ile test etme

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