Aangepaste bewerkingen bijhouden met Application Insights .NET SDK

Application Insights SDK's volgen automatisch binnenkomende HTTP-aanvragen en aanroepen naar afhankelijke services, zoals HTTP-aanvragen en SQL-query's. Bijhouden en correlatie van aanvragen en afhankelijkheden geven u inzicht in de reactiesnelheid en betrouwbaarheid van de hele toepassing voor alle microservices die deze toepassing combineren.

Er is een klasse toepassingspatronen die algemeen niet kunnen worden ondersteund. Voor een goede bewaking van dergelijke patronen is handmatige code-instrumentatie vereist. Dit artikel bevat een aantal patronen waarvoor handmatige instrumentatie is vereist, zoals het verwerken van aangepaste wachtrijen en het uitvoeren van langlopende achtergrondtaken.

Dit artikel bevat richtlijnen voor het bijhouden van aangepaste bewerkingen met de Application Insights SDK. Deze documentatie is relevant voor:

  • Application Insights voor .NET (ook wel bekend als Base SDK) versie 2.4+.
  • Application Insights voor webtoepassingen (met ASP.NET) versie 2.4+.
  • Application Insights voor ASP.NET Core versie 2.1+.

Notitie

De volgende documentatie is afhankelijk van de klassieke Application Insights-API. Het langetermijnplan voor Application Insights is het verzamelen van gegevens met behulp van OpenTelemetry. Zie Azure Monitor OpenTelemetry inschakelen voor .NET-, Node.js-, Python- en Java-toepassingen voor meer informatie.

Overzicht

Een bewerking is een logisch werk dat door een toepassing wordt uitgevoerd. Het heeft een naam, begintijd, duur, resultaat en een context van uitvoering, zoals gebruikersnaam, eigenschappen en resultaat. Als bewerking A is gestart door bewerking B, wordt bewerking B ingesteld als een bovenliggend item voor A. Een bewerking kan slechts één bovenliggende bewerking hebben, maar kan veel onderliggende bewerkingen hebben. Zie Application Insights-telemetriecorrelatie voor meer informatie over bewerkingen en telemetriecorrelatie.

In de .NET SDK van Application Insights wordt de bewerking beschreven door de abstracte klasse OperationTelemetry en de onderliggende RequestTelemetry en DependencyTelemetry.

Bijhouden van binnenkomende bewerkingen

De Application Insights-web-SDK verzamelt automatisch HTTP-aanvragen voor ASP.NET toepassingen die worden uitgevoerd in een IIS-pijplijn en alle ASP.NET Core-toepassingen. Er zijn door de community ondersteunde oplossingen voor andere platforms en frameworks. Als de toepassing niet wordt ondersteund door een van de standaard- of door de community ondersteunde oplossingen, kunt u deze handmatig instrumenteren.

Een ander voorbeeld waarvoor aangepaste tracering is vereist, is de werkrol die items uit de wachtrij ontvangt. Voor sommige wachtrijen wordt de aanroep om een bericht aan deze wachtrij toe te voegen, bijgehouden als een afhankelijkheid. De bewerking op hoog niveau waarin berichtverwerking wordt beschreven, wordt niet automatisch verzameld.

Laten we eens kijken hoe dergelijke bewerkingen kunnen worden bijgehouden.

Op hoog niveau is de taak het maken RequestTelemetry en instellen van bekende eigenschappen. Nadat de bewerking is voltooid, houdt u de telemetrie bij. In het volgende voorbeeld ziet u deze taak.

HTTP-aanvraag in zelf-hostende Owin-app

In dit voorbeeld wordt traceringscontext doorgegeven volgens het HTTP-protocol voor correlatie. U kunt verwachten dat er headers worden weergegeven die daar worden beschreven.

public class ApplicationInsightsMiddleware : OwinMiddleware
{
    // You may create a new TelemetryConfiguration instance, reuse one you already have,
    // or fetch the instance created by Application Insights SDK.
    private readonly TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.CreateDefault();
    private readonly TelemetryClient telemetryClient = new TelemetryClient(telemetryConfiguration);
    
    public ApplicationInsightsMiddleware(OwinMiddleware next) : base(next) {}

    public override async Task Invoke(IOwinContext context)
    {
        // Let's create and start RequestTelemetry.
        var requestTelemetry = new RequestTelemetry
        {
            Name = $"{context.Request.Method} {context.Request.Uri.GetLeftPart(UriPartial.Path)}"
        };

        // If there is a Request-Id received from the upstream service, set the telemetry context accordingly.
        if (context.Request.Headers.ContainsKey("Request-Id"))
        {
            var requestId = context.Request.Headers.Get("Request-Id");
            // Get the operation ID from the Request-Id (if you follow the HTTP Protocol for Correlation).
            requestTelemetry.Context.Operation.Id = GetOperationId(requestId);
            requestTelemetry.Context.Operation.ParentId = requestId;
        }

        // StartOperation is a helper method that allows correlation of 
        // current operations with nested operations/telemetry
        // and initializes start time and duration on telemetry items.
        var operation = telemetryClient.StartOperation(requestTelemetry);

        // Process the request.
        try
        {
            await Next.Invoke(context);
        }
        catch (Exception e)
        {
            requestTelemetry.Success = false;
            requestTelemetry.ResponseCode;
            telemetryClient.TrackException(e);
            throw;
        }
        finally
        {
            // Update status code and success as appropriate.
            if (context.Response != null)
            {
                requestTelemetry.ResponseCode = context.Response.StatusCode.ToString();
                requestTelemetry.Success = context.Response.StatusCode >= 200 && context.Response.StatusCode <= 299;
            }
            else
            {
                requestTelemetry.Success = false;
            }

            // Now it's time to stop the operation (and track telemetry).
            telemetryClient.StopOperation(operation);
        }
    }
    
    public static string GetOperationId(string id)
    {
        // Returns the root ID from the '|' to the first '.' if any.
        int rootEnd = id.IndexOf('.');
        if (rootEnd < 0)
            rootEnd = id.Length;

        int rootStart = id[0] == '|' ? 1 : 0;
        return id.Substring(rootStart, rootEnd - rootStart);
    }
}

Het HTTP-protocol voor correlatie declareert ook de Correlation-Context header. Het wordt hier weggelaten om het eenvoudig te maken.

Wachtrij-instrumentatie

Het W3C-traceringscontext en HTTP-protocol voor correlatiegegevens doorgeven aan HTTP-aanvragen, maar elk wachtrijprotocol moet definiëren hoe dezelfde details worden doorgegeven aan het wachtrijbericht. Sommige wachtrijprotocollen, zoals AMQP, staan het doorgeven van meer metagegevens toe. Voor andere protocollen, zoals Azure Storage Queue, moet de context worden gecodeerd in de nettolading van het bericht.

Notitie

Tracering tussen onderdelen wordt nog niet ondersteund voor wachtrijen.

Als uw producent en consument telemetrie verzenden naar verschillende Application Insights-resources, worden transacties weergegeven en end-to-end toegewezen met BEHULP van HTTP. In het geval van wachtrijen wordt deze mogelijkheid nog niet ondersteund.

Service Bus-wachtrij

Zie gedistribueerde tracering en correlatie via Azure Service Bus-berichten voor traceringsinformatie.

Azure Storage-wachtrij

In het volgende voorbeeld ziet u hoe u de bewerkingen in de Azure Storage-wachtrij kunt bijhouden en telemetrie kunt correleren tussen de producent, de consument en Azure Storage.

De Storage-wachtrij heeft een HTTP-API. Alle aanroepen naar de wachtrij worden bijgehouden door de Application Insights Dependency Collector voor HTTP-aanvragen. Deze is standaard geconfigureerd voor ASP.NET- en ASP.NET Core-toepassingen. Zie de documentatie voor Console-toepassingen voor andere soorten toepassingen.

Mogelijk wilt u ook de Application Insights-bewerkings-id correleren met de opslagaanvraag-id. Zie Azure Storage controleren, diagnosticeren en problemen oplossen voor informatie over het instellen en ophalen van een opslagaanvraagclient en een serveraanvraag-id.

Enqueue

Omdat Storage-wachtrijen ondersteuning bieden voor de HTTP-API, worden alle bewerkingen met de wachtrij automatisch bijgehouden door Application Insights. In veel gevallen moet deze instrumentatie voldoende zijn. Als u traceringen aan de consumentenzijde wilt correleren met producertraceringen, moet u een bepaalde correlatiecontext doorgeven op dezelfde manier als in het HTTP-protocol voor correlatie.

In dit voorbeeld ziet u hoe u de Enqueue bewerking kunt bijhouden. U kunt:

  • Retries correleren (indien aanwezig): ze hebben allemaal één veelvoorkomend bovenliggend element dat de Enqueue bewerking is. Anders worden ze bijgehouden als onderliggende items van de binnenkomende aanvraag. Als er meerdere logische aanvragen naar de wachtrij zijn, kan het lastig zijn om te vinden welke aanroep heeft geresulteerd in nieuwe pogingen.
  • Opslaglogboeken correleren (indien en indien nodig): ze zijn gecorreleerd met Application Insights-telemetrie.

De Enqueue bewerking is het onderliggende element van een bovenliggende bewerking. Een voorbeeld hiervan is een binnenkomende HTTP-aanvraag. De HTTP-afhankelijkheidsaanroep is het onderliggende element van de Enqueue bewerking en het kleinkind van de binnenkomende aanvraag.

public async Task Enqueue(CloudQueue queue, string message)
{
    var operation = telemetryClient.StartOperation<DependencyTelemetry>("enqueue " + queue.Name);
    operation.Telemetry.Type = "Azure queue";
    operation.Telemetry.Data = "Enqueue " + queue.Name;

    // MessagePayload represents your custom message and also serializes correlation identifiers into payload.
    // For example, if you choose to pass payload serialized to JSON, it might look like
    // {'RootId' : 'some-id', 'ParentId' : '|some-id.1.2.3.', 'message' : 'your message to process'}
    var jsonPayload = JsonConvert.SerializeObject(new MessagePayload
    {
        RootId = operation.Telemetry.Context.Operation.Id,
        ParentId = operation.Telemetry.Id,
        Payload = message
    });
    
    CloudQueueMessage queueMessage = new CloudQueueMessage(jsonPayload);

    // Add operation.Telemetry.Id to the OperationContext to correlate Storage logs and Application Insights telemetry.
    OperationContext context = new OperationContext { ClientRequestID = operation.Telemetry.Id};

    try
    {
        await queue.AddMessageAsync(queueMessage, null, null, new QueueRequestOptions(), context);
    }
    catch (StorageException e)
    {
        operation.Telemetry.Properties.Add("AzureServiceRequestID", e.RequestInformation.ServiceRequestID);
        operation.Telemetry.Success = false;
        operation.Telemetry.ResultCode = e.RequestInformation.HttpStatusCode.ToString();
        telemetryClient.TrackException(e);
    }
    finally
    {
        // Update status code and success as appropriate.
        telemetryClient.StopOperation(operation);
    }
}  

Als u de hoeveelheid telemetrie van uw toepassingsrapporten wilt verminderen of als u de Enqueue bewerking om andere redenen niet wilt bijhouden, gebruikt u de Activity API rechtstreeks:

  • Maak (en start) een nieuwe Activity in plaats van de Application Insights-bewerking te starten. U hoeft er geen eigenschappen aan toe te wijzen, behalve de naam van de bewerking.
  • Serialiseer yourActivity.Id in de nettolading van het bericht in plaats van operation.Telemetry.Id. U kunt ook .Activity.Current.Id

Uit wachtrij verwijderen

Op dezelfde manier Enqueuewordt een werkelijke HTTP-aanvraag voor de opslagwachtrij automatisch bijgehouden door Application Insights. De Enqueue bewerking vindt waarschijnlijk plaats in de bovenliggende context, zoals een context voor binnenkomende aanvragen. Application Insights SDK's correleren automatisch een dergelijke bewerking en het BIJBEHORENDE HTTP-onderdeel, met de bovenliggende aanvraag en andere telemetrie die in hetzelfde bereik worden gerapporteerd.

De Dequeue operatie is lastig. De Application Insights SDK houdt automatisch HTTP-aanvragen bij. Maar de correlatiecontext is pas bekend als het bericht is geparseerd. Het is niet mogelijk om de HTTP-aanvraag te correleren om het bericht op te halen met de rest van de telemetrie, met name wanneer er meer dan één bericht wordt ontvangen.

public async Task<MessagePayload> Dequeue(CloudQueue queue)
{
    var operation = telemetryClient.StartOperation<DependencyTelemetry>("dequeue " + queue.Name);
    operation.Telemetry.Type = "Azure queue";
    operation.Telemetry.Data = "Dequeue " + queue.Name;
    
    try
    {
        var message = await queue.GetMessageAsync();
    }
    catch (StorageException e)
    {
        operation.telemetry.Properties.Add("AzureServiceRequestID", e.RequestInformation.ServiceRequestID);
        operation.telemetry.Success = false;
        operation.telemetry.ResultCode = e.RequestInformation.HttpStatusCode.ToString();
        telemetryClient.TrackException(e);
    }
    finally
    {
        // Update status code and success as appropriate.
        telemetryClient.StopOperation(operation);
    }

    return null;
}

Proces

In het volgende voorbeeld wordt een binnenkomend bericht bijgehouden op een manier die vergelijkbaar is met een binnenkomende HTTP-aanvraag:

public async Task Process(MessagePayload message)
{
    // After the message is dequeued from the queue, create RequestTelemetry to track its processing.
    RequestTelemetry requestTelemetry = new RequestTelemetry { Name = "process " + queueName };
    
    // It might also make sense to get the name from the message.
    requestTelemetry.Context.Operation.Id = message.RootId;
    requestTelemetry.Context.Operation.ParentId = message.ParentId;

    var operation = telemetryClient.StartOperation(requestTelemetry);

    try
    {
        await ProcessMessage();
    }
    catch (Exception e)
    {
        telemetryClient.TrackException(e);
        throw;
    }
    finally
    {
        // Update status code and success as appropriate.
        telemetryClient.StopOperation(operation);
    }
}

Op dezelfde manier kunnen andere wachtrijbewerkingen worden geïnstrueerd. Een peek-bewerking moet op een vergelijkbare manier worden geïnstrueerd als een dequeue-bewerking. Het instrumenteren van wachtrijbeheerbewerkingen is niet nodig. Application Insights houdt bewerkingen zoals HTTP bij en in de meeste gevallen is dit voldoende.

Wanneer u berichtverwijdering instrumenteert, moet u de bewerkings-id's (correlatie- id's) instellen. U kunt ook de Activity API gebruiken. Vervolgens hoeft u geen bewerkings-id's in te stellen voor de telemetrie-items, omdat de Application Insights SDK dit voor u doet:

  • Maak een nieuw Activity item nadat u een item uit de wachtrij hebt.
  • Gebruik Activity.SetParentId(message.ParentId) dit om consumenten- en producentlogboeken te correleren.
  • Start de Activity.
  • Volg dequeue-, proces- en verwijderbewerkingen met behulp van Start/StopOperation helpers. Doe dit vanuit dezelfde asynchrone controlestroom (uitvoeringscontext). Op deze manier worden ze correct gecorreleerd.
  • Stop de Activity.
  • Telemetrie handmatig gebruiken Start/StopOperation of aanroepen Track .

Afhankelijkheidstypen

Application Insights maakt gebruik van het afhankelijkheidstype om gebruikersinterface-ervaringen aan te passen. Voor wachtrijen worden de volgende typen DependencyTelemetry herkend die de diagnostische ervaring voor transacties verbeteren:

  • Azure queue voor Azure Storage-wachtrijen
  • Azure Event Hubs voor Azure Event Hubs
  • Azure Service Bus voor Azure Service Bus

Batchverwerking

Met sommige wachtrijen kunt u meerdere berichten uit de wachtrij verwijderen met één aanvraag. Het verwerken van dergelijke berichten is vermoedelijk onafhankelijk en behoort tot de verschillende logische bewerkingen. Het is niet mogelijk om de Dequeue bewerking te correleren met een bepaald bericht dat wordt verwerkt.

Elk bericht moet worden verwerkt in een eigen asynchrone controlestroom. Zie de sectie Voor het bijhouden van uitgaande afhankelijkheden voor meer informatie.

Langlopende achtergrondtaken

Sommige toepassingen starten langdurige bewerkingen die mogelijk worden veroorzaakt door gebruikersaanvragen. Vanuit het perspectief van tracering/instrumentatie is dit niet anders dan aanvraag- of afhankelijkheidsinstrumentatie:

async Task BackgroundTask()
{
    var operation = telemetryClient.StartOperation<DependencyTelemetry>(taskName);
    operation.Telemetry.Type = "Background";
    try
    {
        int progress = 0;
        while (progress < 100)
        {
            // Process the task.
            telemetryClient.TrackTrace($"done {progress++}%");
        }
        // Update status code and success as appropriate.
    }
    catch (Exception e)
    {
        telemetryClient.TrackException(e);
        // Update status code and success as appropriate.
        throw;
    }
    finally
    {
        telemetryClient.StopOperation(operation);
    }
}

In dit voorbeeld telemetryClient.StartOperation wordt de correlatiecontext gemaakt DependencyTelemetry en ingevuld. Stel dat u een bovenliggende bewerking hebt die is gemaakt door binnenkomende aanvragen die de bewerking hebben gepland. Zolang BackgroundTask het begint in dezelfde asynchrone controlestroom als een binnenkomende aanvraag, wordt deze gecorreleerd met die bovenliggende bewerking. BackgroundTask en alle geneste telemetrie-items worden automatisch gecorreleerd met de aanvraag die dit heeft veroorzaakt, zelfs nadat de aanvraag is beëindigd.

Wanneer de taak begint vanaf de achtergrondthread waaraan geen bewerking (Activity) is gekoppeld, BackgroundTask is er geen bovenliggend item. Het kan echter geneste bewerkingen hebben. Alle telemetrie-items die van de taak worden gerapporteerd, worden gecorreleerd aan de DependencyTelemetry gemaakte in BackgroundTask.

Bijhouden van uitgaande afhankelijkheden

U kunt uw eigen soort afhankelijkheid bijhouden of een bewerking die niet wordt ondersteund door Application Insights.

De Enqueue methode in de Service Bus-wachtrij of de opslagwachtrij kan fungeren als voorbeelden voor dergelijke aangepaste tracering.

De algemene benadering voor het bijhouden van aangepaste afhankelijkheid is het volgende:

  • Roep de TelemetryClient.StartOperation methode (extensie) aan die de DependencyTelemetry eigenschappen vult die nodig zijn voor correlatie en een aantal andere eigenschappen, zoals begin, tijdstempel en duur.
  • Stel andere aangepaste eigenschappen in op de DependencyTelemetrynaam, zoals de naam en eventuele andere context die u nodig hebt.
  • Maak een afhankelijkheidsaanroep en wacht erop.
  • Stop de bewerking met StopOperation wanneer deze is voltooid.
  • Uitzonderingen verwerken.
public async Task RunMyTaskAsync()
{
    using (var operation = telemetryClient.StartOperation<DependencyTelemetry>("task 1"))
    {
        try 
        {
            var myTask = await StartMyTaskAsync();
            // Update status code and success as appropriate.
        }
        catch(...) 
        {
            // Update status code and success as appropriate.
        }
    }
}

Als u een bewerking opstelt, wordt de bewerking gestopt, dus u kunt dit doen in plaats van aanroepen StopOperation.

Waarschuwing

In sommige gevallen kan een niet-verwerkte uitzondering voorkomen datfinally deze wordt aangeroepen, zodat bewerkingen mogelijk niet worden bijgehouden.

Parallelle bewerkingen verwerken en bijhouden

Het aanroepen StopOperation stopt alleen de bewerking die is gestart. Als de huidige actieve bewerking niet overeenkomt met de bewerking die u wilt stoppen, StopOperation doet u niets. Deze situatie kan optreden als u meerdere bewerkingen parallel start in dezelfde uitvoeringscontext.

var firstOperation = telemetryClient.StartOperation<DependencyTelemetry>("task 1");
var firstTask = RunMyTaskAsync();

var secondOperation = telemetryClient.StartOperation<DependencyTelemetry>("task 2");
var secondTask = RunMyTaskAsync();

await firstTask;

// FAILURE!!! This will do nothing and will not report telemetry for the first operation
// as currently secondOperation is active.
telemetryClient.StopOperation(firstOperation); 

await secondTask;

Zorg ervoor dat u de bewerking altijd aanroept StartOperation en verwerkt in dezelfde asynchrone methode om bewerkingen die parallel worden uitgevoerd, te isoleren. Als de bewerking synchroon (of niet asynchroon) is, verpakt u het proces en houdt u het bij met Task.Run.

public void RunMyTask(string name)
{
    using (var operation = telemetryClient.StartOperation<DependencyTelemetry>(name))
    {
        Process();
        // Update status code and success as appropriate.
    }
}

public async Task RunAllTasks()
{
    var task1 = Task.Run(() => RunMyTask("task 1"));
    var task2 = Task.Run(() => RunMyTask("task 2"));
    
    await Task.WhenAll(task1, task2);
}

ApplicationInsights-bewerkingen versus System.Diagnostics.Activity

System.Diagnostics.Activity vertegenwoordigt de context voor gedistribueerde tracering en wordt gebruikt door frameworks en bibliotheken om context binnen en buiten het proces te maken en door te geven en telemetrie-items te correleren. Activity werkt samen met System.Diagnostics.DiagnosticSource het meldingsmechanisme tussen het framework/de bibliotheek om te informeren over interessante gebeurtenissen, zoals binnenkomende of uitgaande aanvragen en uitzonderingen.

Activiteiten zijn eersteklas burgers in Application Insights. Automatische afhankelijkheid en aanvraagverzameling zijn sterk afhankelijk van deze, samen met DiagnosticSource gebeurtenissen. Als u in uw toepassing hebt gemaakt Activity , zou dit er niet toe leiden dat application Insights-telemetrie wordt gemaakt. Application Insights moet gebeurtenissen ontvangen DiagnosticSource en weten welke namen en nettoladingen van gebeurtenissen moeten worden omgezet Activity in telemetrie.

Elke Application Insights-bewerking (aanvraag of afhankelijkheid) omvat Activity. Wanneer StartOperation deze wordt aangeroepen, wordt deze eronder gemaakt Activity . StartOperation is de aanbevolen manier om aanvraag- of afhankelijkheidstelemetrieën handmatig bij te houden en ervoor te zorgen dat alles is gecorreleerd.

Volgende stappen