Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Moderne .NET-Anwendungen können Metriken mithilfe der System.Diagnostics.Metrics API erfassen. Diese Metriken enthalten häufig zusätzlichen Kontext in Form von Schlüsselwertpaaren, die als Tags bezeichnet werden (manchmal auch als Dimensionen in Telemetriesystemen bezeichnet). In diesem Artikel wird gezeigt, wie Sie einen Kompilierungszeitquellgenerator verwenden, um stark typierte Metriktags (TagNames) und Metrikaufzeichnungstypen und -methoden zu definieren. Durch die Verwendung stark typisierter Tags vermeiden Sie sich wiederholenden Codebausteine und stellen sicher, dass verwandte Metriken den gleichen Satz von Tagnamen mit Kompilierungszeitsicherheit teilen. Der Hauptvorteil dieses Ansatzes besteht darin, die Produktivität und Typsicherheit von Entwicklern zu verbessern.
Hinweis
Im Kontext von Metriken wird ein Tag manchmal auch als "Dimension" bezeichnet. In diesem Artikel wird "Tag" für Klarheit und Konsistenz mit der Terminologie von .NET-Metriken verwendet.
Loslegen
Installieren Sie zunächst das 📦 NuGet-Paket "Microsoft.Extensions.Telemetry.Abstractions NuGet":
dotnet add package Microsoft.Extensions.Telemetry.Abstractions
Weitere Informationen finden Sie unter dotnet add package oder Verwalten von Paketabhängigkeiten in .NET-Anwendungen.
Standardvorgaben und Anpassung der Tagnamen
Standardmäßig leitet der Quellgenerator metrische Tagnamen aus den Feld- und Eigenschaftennamen Ihrer Tagklasse ab. Mit anderen Worten, jedes öffentliche Feld oder jede Eigenschaft im stark typierten Tagobjekt wird standardmäßig zu einem Tagnamen. Sie können dies überschreiben, indem Sie ein TagNameAttribute Feld oder eine Eigenschaft verwenden, um einen benutzerdefinierten Tagnamen anzugeben. In den folgenden Beispielen werden beide Ansätze in Aktion angezeigt.
Beispiel 1: Einfache Metrik mit einem einzelnen Tag
Im folgenden Beispiel wird eine einfache Zählermetrik mit einem Tag veranschaulicht. In diesem Szenario möchten wir die Anzahl der verarbeiteten Anforderungen zählen und nach einem Region Tag kategorisieren:
public struct RequestTags
{
public string Region { get; set; }
}
public static partial class MyMetrics
{
[Counter<int>(typeof(RequestTags))]
public static partial RequestCount CreateRequestCount(Meter meter);
}
Im vorherigen Code RequestTags handelt es sich um eine stark typierte Tagstruktur mit einer einzelnen Eigenschaft Region. Die CreateRequestCount Methode ist mit CounterAttribute<T> markiert, wobei T ein int ist, was angibt, dass sie ein Counter Instrument generiert, das int Werte verfolgt. Das Attribut verweist auf typeof(RequestTags), was bedeutet, dass der Zähler die Tags verwendet, die in RequestTags definiert sind, wenn Metriken aufgezeichnet werden. Der Quellgenerator erzeugt eine stark typierte Instrumentklasse (benannt RequestCount) mit einer Add Methode, die ganzzahlige Werte und RequestTags Objekte akzeptiert.
Um die generierte Metrik zu verwenden, erstellen Sie eine Meter und zeichnen Sie die Messungen wie unten gezeigt auf:
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);
In diesem Verwendungsbeispiel wird durch aufrufen MyMetrics.CreateRequestCount(meter) ein Zählerinstrument (über das Meter) erstellt und ein metrisches RequestCount Objekt zurückgegeben. Beim Aufrufen requestCountMetric.Add(1, tags)zeichnet das Metriksystem die Anzahl 1 auf, die dem Tag Region="NorthAmerica"zugeordnet ist. Sie können das RequestTags Objekt wiederverwenden oder neue erstellen, um die Anzahl für verschiedene Bereiche aufzuzeichnen, und der Tagname Region wird konsistent auf jede Messung angewendet.
Beispiel 2: Metrik mit geschachtelten Tagobjekten
Für komplexere Szenarien können Sie Tagklassen definieren, die mehrere Tags, geschachtelte Objekte oder sogar geerbte Eigenschaften enthalten. Auf diese Weise kann eine Gruppe verwandter Metriken effektiv einen gemeinsamen Satz von Tags gemeinsam nutzen. Im nächsten Beispiel definieren Sie einen Satz von Tagklassen und verwenden sie für drei verschiedene Metriken:
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"
}
Der vorangehende Code definiert die metrische Vererbung und Objektformen. Der folgende Code veranschaulicht, wie diese Shapes mit dem Generator verwendet werden, wie in der Metric Klasse gezeigt:
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);
}
In diesem Beispiel ist MetricTags eine Tagklasse, die von MetricParentTags erbt und außerdem ein geschachteltes Tagobjekt (MetricChildTags) sowie eine geschachtelte Struktur (MetricTagsStruct) enthält. Die Tageigenschaften veranschaulichen sowohl standard- als auch angepasste Tagnamen:
- Das
Dim1Feld inMetricTagsverfügt über ein[TagName("Dim1DimensionName")]Attribut, sodass der Tagname lautet"Dim1DimensionName". - Die
Operation-Eigenschaft hat kein Attribut, sodass der Tagname standardmäßig als"Operation"gesetzt wird. - In
MetricParentTagswird dieParentOperationName-Eigenschaft mit einem benutzerdefinierten Tagnamen"DimensionNameOfParentOperation"überschrieben. - Die geschachtelte
MetricChildTagsKlasse definiert eineDim2Eigenschaft (kein Attribut, Tagname"Dim2"). - Die
MetricTagsStructStruktur definiert einDim3Feld (Tagname"Dim3").
Alle drei Metrikdefinitionen CreateLatency, CreateTotalCountund CreateTotalFailures verwenden MetricTags sie als Tagobjekttyp. Dies bedeutet, dass die generierten Metriktypen (Latency, TotalCountund TotalFailures) beim Aufzeichnen von Daten eine MetricTags Instanz erwarten.
Jede dieser Metriken hat denselben Satz von Tagnamen:Dim1DimensionName, Operation, , Dim2, und Dim3DimensionNameOfParentOperation.
Der folgende Code zeigt, wie Sie diese Metriken in einer Klasse erstellen und verwenden:
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);
}
}
}
In der vorherigen MyClass.DoWork-Methode wird ein MetricTags-Objekt mit Werten für jedes Tag aufgefüllt. Dieses einzelne tags Objekt wird dann beim Aufzeichnen von Daten an alle drei Instrumente übergeben. Die Latency Metrik (ein Histogramm) zeichnet die verstrichene Zeit auf, und beide Zähler (TotalCount und TotalFailures) erfassen die Anzahl der Vorkommen. Da alle Metriken denselben Tagobjekttyp aufweisen, sind die Tags (Dim1DimensionName, Operation, Dim2, Dim3, DimensionNameOfParentOperation) für jede Messung vorhanden.
Angeben von Einheiten
Ab .NET 10.2 können Sie optional eine Maßeinheit für Ihre Metriken mithilfe des Unit Parameters angeben. Dies hilft dabei, Kontext darüber bereitzustellen, was die Metrik misst (z. B. "Sekunden", "Bytes" und "Anforderungen"). Die Einheit wird beim Erstellen des Instruments an den zugrunde liegenden Meter übergeben.
Der folgende Code veranschaulicht die Verwendung des Generators mit primitiven Typen mit angegebenen Einheiten:
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);
}
Leistungsüberlegungen
Die Verwendung stark typierter Tags über die Quellgenerierung fügt im Vergleich zur direkten Verwendung von Metriken keinen Aufwand hinzu. Wenn Sie die Zuordnungen für sehr häufig auftretende Metriken weiter minimieren müssen, sollten Sie das Tagobjekt als struct (Werttyp) anstelle eines classWerts definieren. Die Verwendung eines struct als Tagsobjekt kann Heap-Zuordnungen beim Aufzeichnen von Metriken vermeiden, da die Tags als Wert übergeben werden.
Generierte Anforderungen an die Metrikmethode
Beim Definieren von Fabrikmethoden für Metriken (die teilweise Methoden, die mit [Counter], [Histogram] usw. versehen sind), stellt der Quellgenerator einige Anforderungen.
- Jede Methode muss sein
public static partial(damit der Quellgenerator die Implementierung bereitstellt). - Der Rückgabetyp jeder partiellen Methode muss eindeutig sein (sodass der Generator einen eindeutig benannten Typ für die Metrik erstellen kann).
- Der Methodenname sollte nicht mit einem Unterstrich (
_) beginnen, und Parameternamen sollten nicht mit einem Unterstrich beginnen. - Der erste Parameter muss ein Meter sein (dies ist die Meterinstanz, die zum Erstellen des zugrunde liegenden Instruments verwendet wird).
- Die Methoden können nicht generisch sein und können keine generischen Parameter aufweisen.
- Die Tageigenschaften in der Tagklasse können nur vom Typ
stringoderenumsein. Konvertieren Sie für andere Typen (z. B. numerische Typen) den Wert in eine Zeichenfolge,boolbevor Sie ihn dem Tagobjekt zuweisen.
Durch die Einhaltung dieser Anforderungen wird sichergestellt, dass der Quellgenerator erfolgreich die Metriktypen und -methoden produzieren kann.
Siehe auch
- Generierte Quellmetriken in .NET
- Erstellen von Metriken in .NET (Lernprogramm zur Instrumentierung)
- Sammeln von Metriken in .NET (Using MeterListener and exporters)
- Protokollierungsquellengenerierung in .NET (für einen ähnlichen Ansatz der Quellgenerierung, der auf die Protokollierung angewendet wird)