Benutzerdefinierte Sammlung von Metriken in .NET und .NET Core

Die .NET und .NET Core SDKs für Azure Monitor Application Insights bieten zum Sammeln benutzerdefinierter Metriken zwei Methoden: TrackMetric() und GetMetric(). Der Hauptunterschied dieser beiden Methoden ist die lokale Aggregation. Die TrackMetric()-Methode verfügt über keine Vorabaggregation. Die GetMetric()-Methode verfügt über Vorabaggregation. Es wird empfohlen, die Aggregation zu verwenden. Aus diesem Grund ist die TrackMetric()-Methode nicht länger die bevorzugte Methode zum Sammeln benutzerdefinierter Metriken. In diesem Artikel erfahren Sie mehr über die Logik der GetMetric()-Methode und ihre Funktionsweise.

Hinweis

Die folgende Dokumentation basiert auf der klassischen Application Insights-API. Der langfristige Plan für Application Insights besteht darin, Daten mithilfe von OpenTelemetry zu sammeln. Weitere Informationen finden Sie unter Aktivieren von Azure Monitor OpenTelemetry für .NET-, Node.js-, Python- und Java-Anwendungen.

Vorabaggregations- im Vergleich zur Nicht-Vorabaggregations-API

Die TrackMetric()-Methode sendet rohe Telemetriedaten, die eine Metrik angeben. Es ist ineffizient, für jeden Wert ein einzelnes Telemetrieelement zu senden. Die TrackMetric()-Methode ist auch in Bezug auf die Leistung ineffizient, da jedes TrackMetric(item) die vollständige SDK-Pipeline von Telemetrie-Initialisierern und -Prozessoren durchläuft.

Im Gegensatz zu TrackMetric() übernimmt GetMetric() für Sie die lokale Vorabaggregation und übermittelt dann nur in einem festen Intervall von einer Minute eine aggregierte zusammenfassende Metrik. Wenn Sie eine bestimmte benutzerdefinierte Metrik auf Sekunden- oder sogar Millisekundenebene genau überwachen müssen, können Sie dies tun, während Ihnen nur die Kosten für Speicher und Netzwerkdatenverkehr für eine minütliche Überwachung entstehen. Dieses Verhalten verringert auch das Risiko einer Drosselung erheblich, da die Gesamtzahl der Telemetrie-Elemente, die für eine aggregierte Metrik gesendet werden müssen, erheblich reduziert wird.

In Application Insights unterliegen benutzerdefinierte Metriken, die über TrackMetric() und GetMetric() gesammelt wurden, nicht der Stichprobenentnahme. Die Stichprobenentnahme wichtiger Metriken kann zu Szenarien führen, in denen die Warnungen, die Sie möglicherweise für diese Metriken eingerichtet haben, unzuverlässig werden könnten. Dadurch, dass Sie keine Stichproben Ihrer benutzerdefinierten Metriken entnehmen, können Sie sich im Allgemeinen darauf verlassen, dass bei Überschreitung Ihrer Warnschwellenwerte eine Warnung ausgelöst wird. Da für benutzerdefinierte Metriken keine Stichproben entnommen werden, gibt es möglicherweise einige Bedenken.

Die Nachverfolgung von Metriktrends im Sekundentakt oder einem noch kleineren Intervall kann zu Folgendem führen:

  • Höhere Datenspeicherkosten. Für die an Azure Monitor gesendete Datenmenge fallen Kosten an. Je mehr Daten Sie senden, desto höher sind die gesamten Überwachungskosten.
  • Es entsteht höherer Aufwand für Netzwerkdatenverkehr oder Leistung. In einigen Szenarien kann dieser Overhead sowohl monetäre Kosten als auch Kosten für die Anwendungsleistung bedeuten.
  • Risiko der Erfassungsdrosselung. Azure Monitor entfernt Datenpunkte (Drosselung), wenn Ihre App in kurzen Abständen eine große Menge an Telemetriedaten sendet.

Die Drosselung ist ein Problem, da sie zu verpassten Warnungen führen kann. Es kann vorkommen, dass die Bedingung zum Auslösen einer Warnung lokal auftritt und dann am Erfassungsendpunkt aufgrund zu vieler gesendeter Daten verloren geht. Aus diesem Grund raten wir dazu, TrackMetric() nur dann für .NET und .NET Core zu verwenden, wenn Sie Ihre eigene lokale Aggregationslogik implementiert haben. Wenn Sie alle Instanzen eines Ereignisses innerhalb einer bestimmten Zeitspanne nachverfolgen möchten, ist TrackEvent() möglicherweise besser geeignet. Beachten Sie, dass benutzerdefinierte Ereignisse im Gegensatz zu benutzerdefinierten Metriken Stichproben unterliegen. Sie können TrackMetric() immer noch verwenden, auch ohne Ihre eigene lokale Voraggregation zu schreiben. Seien Sie sich aber der Fallstricke bewusst, wenn Sie sich dafür entscheiden.

Zusammenfassend ist GetMetric() der empfohlene Ansatz, da er eine Voraggregation durchführt, Werte aus allen Track()-Aufrufen sammelt und einmal pro Minute eine Zusammenfassung/Aggregation sendet. Die GetMetric()-Methode kann den Kosten- und Leistungsaufwand erheblich reduzieren, da weniger Datenpunkte gesendet, aber dennoch alle relevanten Informationen erfasst werden.

Hinweis

Nur die .NET und .NET-Core SDKs bieten eine GetMetric()-Methode. Wenn Sie Java verwenden, finden Sie weitere Informationen unter Senden benutzerdefinierter Metriken mithilfe von Micrometer. Für JavaScript und Node.js können Sie weiterhin TrackMetric() einsetzen. Beachten Sie jedoch die im vorherigen Abschnitt dargelegten Nachteile. Für Python können Sie OpenCensus.stats verwenden, um benutzerdefinierte Metriken zu senden. Die Implementierung der Metriken unterscheidet sich aber.

Erste Schritte mit GetMetric

Für unsere Beispiele verwenden wir eine einfache .NET Core 3.1-Workerdienstanwendung. Wenn Sie die in diesen Beispielen verwendete Testumgebung replizieren möchten, führen Sie die Schritte 1 bis 6 aus dem Artikel zur Überwachung von Workerdiensten aus. Mithilfe dieser Schritte wird Application Insights einer einfachen Workerdienstprojektvorlage hinzugefügt. Die Konzepte gelten für alle allgemeinen Anwendungen, für die das SDK verwendet werden kann, einschließlich Web- und Konsolen-Apps.

Senden von Metriken

Ersetzen Sie den Inhalt der Datei worker.cs durch folgenden Code:

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.ApplicationInsights;

namespace WorkerService3
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private TelemetryClient _telemetryClient;

        public Worker(ILogger<Worker> logger, TelemetryClient tc)
        {
            _logger = logger;
            _telemetryClient = tc;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {   // The following line demonstrates usages of GetMetric API.
            // Here "computersSold", a custom metric name, is being tracked with a value of 42 every second.
            while (!stoppingToken.IsCancellationRequested)
            {
                _telemetryClient.GetMetric("ComputersSold").TrackValue(42);

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

Wenn Sie den Beispielcode ausführen, wird die while-Schleife wiederholt ausgeführt, ohne dass Telemetriedaten an das Visual Studio-Ausgabefenster gesendet werden. Nach etwa 60 Sekunden wird ein einzelnes Telemetrieelement gesendet. Das sieht in unserem Test folgendermaßen aus:

Application Insights Telemetry: {"name":"Microsoft.ApplicationInsights.Dev.00000000-0000-0000-0000-000000000000.Metric", "time":"2019-12-28T00:54:19.0000000Z",
"ikey":"00000000-0000-0000-0000-000000000000",
"tags":{"ai.application.ver":"1.0.0.0",
"ai.cloud.roleInstance":"Test-Computer-Name",
"ai.internal.sdkVersion":"m-agg2c:2.12.0-21496",
"ai.internal.nodeName":"Test-Computer-Name"},
"data":{"baseType":"MetricData",
"baseData":{"ver":2,"metrics":[{"name":"ComputersSold",
"kind":"Aggregation",
"value":1722,
"count":41,
"min":42,
"max":42,
"stdDev":0}],
"properties":{"_MS.AggregationIntervalMs":"42000",
"DeveloperMode":"true"}}}}

Dieses einzelne Telemetrieelement stellt ein Aggregat von Messungen 41 verschiedener Metriken dar. Da wir immer wieder denselben Wert senden, haben wir eine Standardabweichung (stDev) von 0 mit identischen Maximal- (max) und Minimalwerten (min). Die Eigenschaft value stellt die Summe aller aggregierten Einzelwerte dar.

Hinweis

Die GetMetric -Methode unterstützt die Nachverfolgung des letzten Werts (z. B gauge) oder das Nachverfolgen von Histogrammen oder Verteilungen nicht.

Wenn wir unsere Application Insights-Ressource auf der Oberfläche Protokolle (Analytics) untersuchen, sieht das einzelne Telemetrieelement wie auf folgendem Screenshot aus.

Screenshot that shows the Log Analytics query view.

Hinweis

Da das rohe Telemetrieelement nach der Erfassung weder eine explizite Summeneigenschaft noch Summenfeld enthielt, erstellen wir dies für Sie. In diesem Fall stellen die Eigenschaften value und valueSum dasselbe dar.

Sie können auf Ihre benutzerdefinierten Metriktelemetriedaten auch im Abschnitt Metriken des Portals sowohl als protokollbasierte als auch als benutzerdefinierte Metrik zugreifen. Der folgende Screenshot zeigt ein Beispiel einer protokollbasierten Metrik.

Screenshot that shows the Metrics explorer view.

Referenz zur Zwischenspeicherung von Metriken für Nutzung mit hohem Durchsatz

In einigen Fällen werden Metrikwerte möglicherweise in kurzen Abständen beobachtet. Beispielsweise kann für einen Dienst mit hohem Durchsatz, der 500 Anforderungen pro Sekunde verarbeitet, der Wunsch bestehen, für jede Anforderung 20 Telemetriemetriken zu senden. Das bedeutet, dass 10.000 Werte pro Sekunde nachverfolgt werden müssen. In solchen Szenarien mit hohem Durchsatz müssen Benutzer das SDK möglicherweise unterstützen, indem bestimmte Lookups vermieden werden.

Im vorherigen Beispiel wurde beispielsweise ein Lookup nach einem Handle für die Metrik „ComputersSold“ durchgeführt und dann der beobachtete Wert „42“ nachverfolgt. Stattdessen kann der Handle für Aufrufe mehrerer Nachverfolgungen möglicherweise zwischengespeichert werden:

//...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // This is where the cache is stored to handle faster lookup
            Metric computersSold = _telemetryClient.GetMetric("ComputersSold");
            while (!stoppingToken.IsCancellationRequested)
            {

                computersSold.TrackValue(42);

                computersSold.TrackValue(142);

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(50, stoppingToken);
            }
        }

Zusätzlich zur Zwischenspeicherung des Metrikhandles reduzierte das vorherige Beispiel auch Task.Delay auf 50 Millisekunden, sodass die Schleife häufiger ausgeführt wurde. Das Ergebnis lautet 772 TrackValue()-Aufrufe.

Mehrdimensionale Metriken

Die Beispiele im vorherigen Abschnitt zeigen Metriken ohne Dimensionen. Sie können auch mehrdimensionale Metriken erstellen, Wir unterstützen derzeit bis zu 10 Dimensionen.

Hier sehen Sie ein Beispiel für das Erstellen einer eindimensionalen Metrik:

//...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // This is an example of a metric with a single dimension.
            // FormFactor is the name of the dimension.
            Metric computersSold= _telemetryClient.GetMetric("ComputersSold", "FormFactor");

            while (!stoppingToken.IsCancellationRequested)
            {
                // The number of arguments (dimension values)
                // must match the number of dimensions specified while GetMetric.
                // Laptop, Tablet, etc are values for the dimension "FormFactor"
                computersSold.TrackValue(42, "Laptop");
                computersSold.TrackValue(20, "Tablet");
                computersSold.TrackValue(126, "Desktop");


                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(50, stoppingToken);
            }
        }

Das Ausführen des Beispielcodes für mindestens 60 Sekunden führt zu drei verschiedenen Telemetrieelementen, die an Azure gesendet werden. Jedes Element stellt die Aggregation eines der drei Formfaktoren dar. Wie zuvor kann zur weiteren Untersuchung die Ansicht Protokolle (Analytics) verwendet werden.

Screenshot that shows the Log Analytics view of multidimensional metric.

Im Metrik-Explorer:

Screenshot that shows Custom metrics.

Beachten Sie, dass Sie die Metrik nicht nach Ihrer neuen benutzerdefinierten Dimension aufteilen oder Ihre benutzerdefinierte Dimension mit der Metrik-Ansicht anzeigen können.

Screenshot that shows splitting support.

Standardmäßig sind mehrdimensionale Metriken innerhalb des Metrik-Explorers in Application Insights-Ressourcen nicht aktiviert.

Mehrdimensionale Metriken aktivieren

Um mehrdimensionale Metriken für eine Application Insights-Ressource zu aktivieren, wählen Sie Nutzung und geschätzte Kosten>Benutzerdefinierte Metriken>Dimensionswarnungen für benutzerdefinierte Metriken aktivieren>OK aus. Weitere Informationen finden Sie unter Benutzerdefinierte Metrikdimensionen und Vorabaggregation.

Nachdem Sie diese Änderung vorgenommen und neue mehrdimensionale Telemetriedaten gesendet haben, können Sie Aufteilung anwenden auswählen.

Hinweis

Nur für neu gesendete Metriken, die nach dem Aktivieren der Funktion im Portal gesendet wurden, werden Dimensionen gespeichert.

Screenshot that shows applying splitting.

Zeigen Sie Ihre Metrikaggregationen für jede FormFactor-Dimension an.

Screenshot that shows form factors.

Verwenden von MetricIdentifier, wenn mehr als drei Dimensionen vorhanden sind

Derzeit werden 10 Dimensionen unterstützt. Die Nutzung von mehr als drei Dimensionen macht die Verwendung von MetricIdentifier erforderlich:

// Add "using Microsoft.ApplicationInsights.Metrics;" to use MetricIdentifier
// MetricIdentifier id = new MetricIdentifier("[metricNamespace]","[metricId],"[dim1]","[dim2]","[dim3]","[dim4]","[dim5]");
MetricIdentifier id = new MetricIdentifier("CustomMetricNamespace","ComputerSold", "FormFactor", "GraphicsCard", "MemorySpeed", "BatteryCapacity", "StorageCapacity");
Metric computersSold  = _telemetryClient.GetMetric(id);
computersSold.TrackValue(110,"Laptop", "Nvidia", "DDR4", "39Wh", "1TB");

Konfiguration benutzerdefinierter Metriken

Wenn Sie die Metrikkonfiguration ändern möchten, müssen Sie Änderungen an der Stelle vornehmen, an der die Metrik initialisiert wird.

Besondere Dimensionsnamen

Metriken verwenden nicht den Telemetriekontext der TelemetryClient, die für den Zugriff auf sie verwendet wird. Diese Einschränkung umgehen Sie am besten durch die Verwendung spezieller Dimensionsnamen, die als Konstanten in der MetricDimensionNames-Klasse verfügbar sind.

Bei Metrikaggregaten, die von der folgenden Special Operation Request Size-Metrik gesendet werden, muss Context.Operation.Namenicht auf Special Operation festgelegt werden. Die TrackMetric()- oder jede andere TrackXXX()-Methode wird OperationName ordnungsgemäß auf Special Operation festgelegen.

        //...
        TelemetryClient specialClient;
        private static int GetCurrentRequestSize()
        {
            // Do stuff
            return 1100;
        }
        int requestSize = GetCurrentRequestSize()

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                //...
                specialClient.Context.Operation.Name = "Special Operation";
                specialClient.GetMetric("Special Operation Request Size").TrackValue(requestSize);
                //...
            }
                   
        }

Verwenden Sie in diesem Fall die speziellen Dimensionsnamen, die in der MetricDimensionNames-Klasse aufgeführt sind, um die TelemetryContext-Werte anzugeben.

Wenn z. B. das Metrikaggregat, das sich aus der nächsten Anweisung ergibt, an den Cloudendpunkt von Application Insights gesendet wird, wird sein Context.Operation.Name-Datenfeld auf „Special Operation“ festgelegt:

_telemetryClient.GetMetric("Request Size", MetricDimensionNames.TelemetryContext.Operation.Name).TrackValue(requestSize, "Special Operation");

Die Werte dieser speziellen Dimension werden in „TelemetryContext“ kopiert und nicht als normale Dimension verwendet. Wenn Sie eine Vorgangsdimension auch für die normale Erkundung von Metriken beibehalten möchten, müssen Sie für diesen Zweck eine separate Dimension erstellen:

_telemetryClient.GetMetric("Request Size", "Operation Name", MetricDimensionNames.TelemetryContext.Operation.Name).TrackValue(requestSize, "Special Operation", "Special Operation");

Obergrenzen von Dimensionen und Zeitreihen

Um zu verhindern, dass das Telemetriesubsystem versehentlich Ihre Ressourcen ausschöpft, können Sie die maximale Anzahl von Datenreihen pro Metrik steuern. Die Standardgrenzwerte sind höchstens insgesamt 1.000 Datenreihen pro Metrik und höchstens 100 verschiedene Werte pro Dimension.

Wichtig

Verwenden Sie für Dimensionen niedrige Kardinalwerte, um Drosselungen zu vermeiden.

Im Zusammenhang mit der Obergrenze für Dimensionen und Zeitreihen verwenden wir Metric.TrackValue(..), um sicherzustellen, dass die Grenzwerte eingehalten werden. Wenn die Grenzwerte bereits erreicht sind, gibt Metric.TrackValue(..)False“ zurück, und der Wert wird nicht nachverfolgt. Andernfalls wird Truezurückgegeben. Dieses Verhalten ist nützlich, wenn die Daten für eine Metrik aus Benutzereingaben stammen.

Der Konstruktor MetricConfiguration übernimmt einige Optionen, wie verschiedene Reihen innerhalb der jeweiligen Metrik und ein Objekt einer Klasse zu verwalten sind, die IMetricSeriesConfiguration implementiert, die das Aggregationsverhalten für jede einzelne Reihe der Metrik angibt:

var metConfig = new MetricConfiguration(seriesCountLimit: 100, valuesPerDimensionLimit:2,
                new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false));

Metric computersSold = _telemetryClient.GetMetric("ComputersSold", "Dimension1", "Dimension2", metConfig);

// Start tracking.
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value1");
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value2");

// The following call gives 3rd unique value for dimension2, which is above the limit of 2.
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value3");
// The above call does not track the metric, and returns false.
  • seriesCountLimit ist die maximale Anzahl von Datenzeitreihen, die eine Metrik enthalten kann. Wenn dieser Grenzwert erreicht wird, geben Aufrufe von TrackValue(), die normalerweise zu einer neuen Reihe führen würden, „false“ zurück.
  • valuesPerDimensionLimit begrenzt auf ähnliche Weise die Anzahl der verschiedenen Werte pro Dimension.
  • restrictToUInt32Values bestimmt, ob nur nicht negative ganzzahlige Werte nachverfolgt werden sollen oder nicht.

Das folgende Beispiel zeigt, wie Sie eine Nachricht senden, um zu erfahren, ob Obergrenzen überschritten werden:

if (! computersSold.TrackValue(100, "Dim1Value1", "Dim2Value3"))
{
// Add "using Microsoft.ApplicationInsights.DataContract;" to use SeverityLevel.Error
_telemetryClient.TrackTrace("Metric value not tracked as value of one of the dimension exceeded the cap. Revisit the dimensions to ensure they are within the limits",
SeverityLevel.Error);
}

Nächste Schritte