Aracılığıyla paylaş


Kesin tür tanımlı etiketlerle kaynak tarafından oluşturulan metrikler

Modern .NET uygulamaları System.Diagnostics.Metrics API'sini kullanarak ölçümleri yakalayabilir. Bu ölçümler genellikle etiketleri (telemetri sistemlerinde boyutlar olarak da adlandırılır) olarak adlandırılan anahtar-değer çiftleri biçiminde ek bağlam içerir. Bu makalede, bir derleme zamanı kaynak oluşturucusunu kullanarak kesin olarak belirlenmiş ölçüm etiketleri ve (TagNames) tanımlanan ölçüm kayıt türleri ve yöntemleri nasıl kullanılacağı gösterilmektedir. Güçlü türlendirilmiş etiketler kullanarak, yinelenen şablon kodunu ortadan kaldırır ve ilgili ölçümlerin derleme zamanı güvenliğiyle aynı etiket adlarını paylaştığından emin olursunuz. Bu yaklaşımın birincil avantajı, geliştirici üretkenliğini ve tür güvenliğini artırmaktır.

Not

Ölçümler bağlamında, bir etiket bazen "boyut" olarak da adlandırılır. Bu makalede .NET ölçüm terminolojisi ile netlik ve tutarlılık için "etiket" kullanılmıştır.

Başlayın

Başlamak için Microsoft.Extensions.Telemetry.Abstractions NuGet paketini yükleyin📦:

dotnet add package Microsoft.Extensions.Telemetry.Abstractions

Daha fazla bilgi için bkz. dotnet add package veya .NET uygulamalarında paket bağımlılıklarını yönetme.

Etiket adı varsayılanları ve özelleştirmesi

Varsayılan olarak, kaynak oluşturucu, etiket sınıfınızın alan ve özellik adlarından ölçüm etiketi adlarını türetir. Başka bir deyişle, kesin olarak türü belirlenmiş etiket nesnesindeki her ortak alan veya özellik varsayılan olarak bir etiket adı olur. Özel etiket adı belirtmek için bir alan veya özellik üzerindeki TagNameAttribute kullanarak bunu geçersiz kılabilirsiniz. Aşağıdaki örneklerde her iki yaklaşımın da çalıştığını göreceksiniz.

Örnek 1: Tek etiketli temel ölçüm

Aşağıdaki örnek, tek etiketli basit bir sayıcı metriği göstermektedir. Bu senaryoda, işlenen isteklerin sayısını saymak ve bunları bir Region etiketine göre kategorilere ayırmak istiyoruz:

public struct RequestTags
{
    public string Region { get; set; }
}

public static partial class MyMetrics
{
    [Counter<int>(typeof(RequestTags))]
    public static partial RequestCount CreateRequestCount(Meter meter);
}

Yukarıdaki kodda, RequestTags tek özelliği Regionolan kesin olarak belirlenmiş bir etiket yapısıdır. CreateRequestCount yöntemi, CounterAttribute<T> ile işaretlenmiştir; bu, T'nin bir int olduğu yerde, Counter değerlerini takip eden bir int aracı ürettiğini belirtir. Öznitelik typeof(RequestTags)'a atıfta bulunur, yani sayaç, ölçümleri kaydederken RequestTags içinde tanımlanan etiketleri kullanır. Kaynak oluşturucu, tamsayı değeri ve RequestCount nesnesi kabul eden bir yöntemle güçlü şekilde tiplenmiş bir Add enstrüman sınıfı (adlandırılmış RequestTags) oluşturur.

Oluşturulan ölçümü kullanmak için aşağıda gösterildiği gibi bir Meter oluşturun ve ölçümleri kaydedin:

Meter meter = new("MyCompany.MyApp", "1.0");
RequestCount requestCountMetric = MyMetrics.CreateRequestCount(meter);

// Create a tag object with the relevant tag value
var tags = new RequestTags { Region = "NorthAmerica" };

// Record a metric value with the associated tag
requestCountMetric.Add(1, tags);

Bu kullanım örneğinde, MyMetrics.CreateRequestCount(meter) çağrısı bir sayaç aracı (Meteraracılığıyla) oluşturur ve RequestCount bir ölçüm nesnesi döndürür. requestCountMetric.Add(1, tags)çağırdığınızda ölçüm sistemi Region="NorthAmerica"etiketiyle ilişkili 1 sayısını kaydeder. RequestTags nesnesini yeniden kullanabilir veya farklı bölgelerin sayılarını kaydetmek için yenilerini oluşturabilirsiniz; Region etiket adı her ölçüme tutarlı bir şekilde uygulanır.

Örnek 2: İç içe etiket nesneleriyle ölçüm

Daha karmaşık senaryolar için birden çok etiket, iç içe nesneler ve hatta devralınan özellikler içeren etiket sınıflarını tanımlayabilirsiniz. Bu, bir grup ilgili ölçümün ortak bir etiket kümesini etkili bir şekilde paylaşmasına olanak tanır. Sonraki örnekte, bir dizi etiket sınıfı tanımlayacak ve bunları üç farklı ölçüm için kullanacaksınız:

using Microsoft.Extensions.Diagnostics.Metrics;

namespace MetricsGen;

public class MetricTags : MetricParentTags
{
    [TagName("Dim1DimensionName")]
    public string? Dim1;                      // custom tag name via attribute
    public Operations Operation { get; set; } // tag name defaults to "Operation"
    public MetricChildTags? ChildTagsObject { get; set; }
}

public enum Operations
{
    Unknown = 0,
    Operation1 = 1,
}

public class MetricParentTags
{
    [TagName("DimensionNameOfParentOperation")]
    public string? ParentOperationName { get; set; }  // custom tag name via attribute
    public MetricTagsStruct ChildTagsStruct { get; set; }
}

public class MetricChildTags
{
    public string? Dim2 { get; set; }  // tag name defaults to "Dim2"
}

public struct MetricTagsStruct
{
    public string Dim3 { get; set; }   // tag name defaults to "Dim3"
}

Yukarıdaki kod, ölçüm devralmayı ve nesne şekillerini tanımlar. Aşağıdaki kod, sınıfında gösterildiği Metric gibi bu şekillerin oluşturucuyla nasıl kullanılacağını gösterir:

using System.Diagnostics.Metrics;
using Microsoft.Extensions.Diagnostics.Metrics;

public static partial class Metric
{
    [Histogram<long>(typeof(MetricTags))]
    public static partial Latency CreateLatency(Meter meter);

    [Counter<long>(typeof(MetricTags))]
    public static partial TotalCount CreateTotalCount(Meter meter);

    [Counter<int>(typeof(MetricTags))]
    public static partial TotalFailures CreateTotalFailures(Meter meter);
}

Bu örnekte MetricTags, MetricParentTags'den devralan bir etiket sınıfıdır ve ayrıca iç içe etiket nesnesi (MetricChildTags) ve iç içe geçmiş bir yapı (MetricTagsStruct) içerir. Etiket özellikleri hem varsayılan hem de özelleştirilmiş etiket adlarını gösterir:

  • Dim1'daki MetricTags alanının [TagName("Dim1DimensionName")] özniteliği olduğundan etiket adı "Dim1DimensionName"olur.
  • Operation özelliğinin özniteliği olmadığından etiket adı varsayılan olarak "Operation"olur.
  • MetricParentTagsiçinde ParentOperationName özelliği "DimensionNameOfParentOperation"özel etiket adıyla geçersiz kılındı.
  • İç içe MetricChildTags sınıfı bir Dim2 özelliği tanımlar (öznitelik yok, etiket adı "Dim2").
  • MetricTagsStruct yapısı bir Dim3 alanı tanımlar (etiket adı "Dim3").

Tüm CreateLatency, CreateTotalCountve CreateTotalFailures ölçüm tanımları, etiket nesnesi türü olarak MetricTags'ü kullanır. Bu, oluşturulan ölçüm türlerinin (Latency, TotalCountve TotalFailures) veri kaydederken bir MetricTags örneği bekleyeceği anlamına gelir. Bu ölçümlerin her biri aynı etiket adları kümesine sahiptir:Dim1DimensionName, Operation, Dim2, Dim3ve DimensionNameOfParentOperation.

Aşağıdaki kod, bir sınıfta bu ölçümlerin nasıl oluşturulacağını ve kullanılacağını gösterir:

internal class MyClass
{
    private readonly Latency _latencyMetric;
    private readonly TotalCount _totalCountMetric;
    private readonly TotalFailures _totalFailuresMetric;

    public MyClass(Meter meter)
    {
        // Create metric instances using the source-generated factory methods
        _latencyMetric = Metric.CreateLatency(meter);
        _totalCountMetric = Metric.CreateTotalCount(meter);
        _totalFailuresMetric = Metric.CreateTotalFailures(meter);
    }

    public void DoWork()
    {
        var startingTimestamp = Stopwatch.GetTimestamp();
        bool requestSuccessful = true;
        // Perform some operation to measure
        var elapsedTime = Stopwatch.GetElapsedTime(startingTimestamp);

        // Create a tag object with values for all tags
        var tags = new MetricTags
        {
            Dim1 = "Dim1Value",
            Operation = Operations.Operation1,
            ParentOperationName = "ParentOpValue",
            ChildTagsObject = new MetricChildTags
            {
                Dim2 = "Dim2Value",
            },
            ChildTagsStruct = new MetricTagsStruct
            {
                Dim3 = "Dim3Value"
            }
        };

        // Record the metric values with the associated tags
        _latencyMetric.Record(elapsedTime.ElapsedMilliseconds, tags);
        _totalCountMetric.Add(1, tags);
        if (!requestSuccessful)
        {
            _totalFailuresMetric.Add(1, tags);
        }
    }
}

Önceki MyClass.DoWork yönteminde, bir MetricTags nesnesi her etiket için değerlerle doldurulur. Bu tek tags nesnesi daha sonra veri kaydederken üç alete de geçirilir. Latency metriği (histogram) geçen süreyi kaydeder ve her iki sayaç (TotalCount ve TotalFailures) olay sayısını kaydeder. Tüm ölçümler aynı etiket nesnesi türünü paylaştığından, etiketler (Dim1DimensionName, Operation, Dim2, Dim3, DimensionNameOfParentOperation) her ölçümde bulunur.

Birimleri belirtme

.NET 10.2'den başlayarak, isteğe bağlı olarak parametresini kullanarak Unit ölçümleriniz için bir ölçü birimi belirtebilirsiniz. Bu, ölçümün ölçüleri hakkında bağlam sağlamaya yardımcı olur (örneğin, "saniye", "bayt" ve "istekler"). Ünite, cihaz oluşturulurken altta yatan Meter üzerine geçirilir.

Aşağıdaki kod, belirtilen birimlerle birlikte ilkel türlerle jeneratörün nasıl kullanılacağını gösterir.

public static partial class Metric
{
    [Histogram<long>(typeof(MetricTags), Unit = "ms")]
    public static partial Latency CreateLatency(Meter meter);

    [Counter<long>(typeof(MetricTags), Unit = "requests")]
    public static partial TotalCount CreateTotalCount(Meter meter);

    [Counter<int>(typeof(MetricTags), Unit = "failures")]
    public static partial TotalFailures CreateTotalFailures(Meter meter);
}

Performansla ilgili dikkat edilmesi gerekenler

Kaynak oluşturma yoluyla güçlü şekilde tiplenmiş etiketlerin kullanılması, ölçümleri doğrudan kullanmaya kıyasla ek bir yük oluşturmaz. Çok yüksek frekanslı ölçümler için ayırmaları daha da en aza indirmeniz gerekiyorsa, etiket nesnenizi structyerine class (değer türü) olarak tanımlamayı göz önünde bulundurun. Etiket nesnesi için bir struct kullanmak, etiketler değere göre geçirileceğinden ölçümleri kaydederken yığın ayırmalarını önleyebilir.

Oluşturulan ölçüm yöntemi gereksinimleri

Ölçüm fabrikası yöntemlerini tanımlarken ([Counter], [Histogram]vb. ile dekore edilmiş kısmi yöntemler), kaynak oluşturucu birkaç gereksinim sunar:

  • Her yöntem public static partial olmalıdır (kaynak oluşturucunun uygulamayı sağlaması için).
  • Her kısmi yöntemin dönüş türü benzersiz olmalıdır (böylece oluşturucu ölçüm için benzersiz olarak adlandırılmış bir tür oluşturabilir).
  • Yöntem adı bir alt çizgi (_) ile başlamamalı ve parametre adları bir alt çizgiyle başlamamalıdır.
  • İlk parametre bir Meter olmalıdır (bu, temel alınan aracı oluşturmak için kullanılan ölçüm örneğidir).
  • Yöntemler genel olamaz ve genel parametreleri olamaz.
  • Etiket sınıfındaki etiket özellikleri yalnızca string veya enumtüründe olabilir. Diğer türler için (örneğin, bool veya sayısal türler), değeri etiket nesnesine atamadan önce dizeye dönüştürün.

Bu gereksinimlere bağlı olmak, kaynak oluşturucunun ölçüm türlerini ve yöntemlerini başarıyla üretebilmesini sağlar.

Ayrıca bkz.