Spåra anpassade åtgärder med Application Insights .NET SDK

Application Insights SDK:er spårar automatiskt inkommande HTTP-begäranden och anrop till beroende tjänster, till exempel HTTP-begäranden och SQL-frågor. Spårning och korrelation av begäranden och beroenden ger dig insyn i hela programmets svarstider och tillförlitlighet för alla mikrotjänster som kombinerar det här programmet.

Det finns en klass med programmönster som inte kan stödjas allmänt. Korrekt övervakning av sådana mönster kräver manuell kodinstrumentation. Den här artikeln beskriver några mönster som kan kräva manuell instrumentering, till exempel anpassad köbearbetning och tidskrävande bakgrundsuppgifter.

Den här artikeln innehåller vägledning om hur du spårar anpassade åtgärder med Application Insights SDK. Den här dokumentationen är relevant för:

  • Application Insights för .NET (även kallat Base SDK) version 2.4+.
  • Application Insights för webbprogram (som kör ASP.NET) version 2.4+.
  • Application Insights för ASP.NET Core version 2.1+.

Kommentar

Följande dokumentation förlitar sig på det klassiska API:et Application Insights. Den långsiktiga planen för Application Insights är att samla in data med OpenTelemetry. Mer information finns i Aktivera Azure Monitor OpenTelemetry för .NET-, Node.js-, Python- och Java-program.

Översikt

En åtgärd är ett logiskt arbete som körs av ett program. Den har ett namn, starttid, varaktighet, resultat och en kontext för körning som användarnamn, egenskaper och resultat. Om åtgärd A initierades av åtgärd B anges åtgärd B som överordnad för A. En åtgärd kan bara ha en överordnad åtgärd, men den kan ha många underordnade åtgärder. Mer information om åtgärder och telemetrikorrelation finns i Application Insights telemetrikorrelation.

I Application Insights .NET SDK beskrivs åtgärden av den abstrakta klassen OperationTelemetry och dess underordnade RequestTelemetry och DependencyTelemetry.

Spårning av inkommande åtgärder

Application Insights webb-SDK samlar automatiskt in HTTP-begäranden för ASP.NET program som körs i en IIS-pipeline och alla ASP.NET Core-program. Det finns lösningar som stöds av communityn för andra plattformar och ramverk. Om programmet inte stöds av någon av de standardlösningar eller lösningar som stöds av communityn kan du instrumentera det manuellt.

Ett annat exempel som kräver anpassad spårning är arbetaren som tar emot objekt från kön. För vissa köer spåras anropet för att lägga till ett meddelande i den här kön som ett beroende. Den övergripande åtgärd som beskriver meddelandebearbetning samlas inte in automatiskt.

Nu ska vi se hur sådana åtgärder kan spåras.

På hög nivå är uppgiften att skapa RequestTelemetry och ange kända egenskaper. När åtgärden är klar spårar du telemetrin. I följande exempel visas den här uppgiften.

HTTP-begäran i en lokalt installerad Owin-app

I det här exemplet sprids spårningskontexten enligt HTTP-protokollet för korrelation. Du bör förvänta dig att få rubriker som beskrivs där.

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

HTTP-protokollet för korrelation deklarerar Correlation-Context också huvudet. Det utelämnas här för enkelhetens skull.

Köinstrumentation

W3C-spårningskontexten och HTTP-protokollet för korrelationspasskorrelationsinformation med HTTP-begäranden, men varje köprotokoll måste definiera hur samma information skickas längs kömeddelandet. Vissa köprotokoll, till exempel AMQP, tillåter överföring av fler metadata. Andra protokoll, till exempel Azure Storage Queue, kräver att kontexten kodas i meddelandets nyttolast.

Kommentar

Spårning mellan komponenter stöds inte för köer ännu.

Med HTTP, om din producent och konsument skickar telemetri till olika Application Insights-resurser, visar transaktionsdiagnostikupplevelsen och Programkarta transaktioner och mappar från slutpunkt till slutpunkt. När det gäller köer stöds inte den här funktionen ännu.

Service Bus-kö

Information om spårning finns i Distribuerad spårning och korrelation via Azure Service Bus-meddelanden.

Azure Storage-kö

I följande exempel visas hur du spårar Azure Storage-köåtgärderna och korrelerar telemetri mellan producenten, konsumenten och Azure Storage.

Lagringskön har ett HTTP-API. Alla anrop till kön spåras av Application Insights Dependency Collector för HTTP-begäranden. Den konfigureras som standard för ASP.NET- och ASP.NET Core-program. Med andra typer av program kan du läsa dokumentationen om konsolprogram.

Du kanske också vill korrelera Application Insights-åtgärds-ID:t med ID:t för lagringsbegäran. Information om hur du anger och hämtar en klient för lagringsbegäran och ett serverbegärans-ID finns i Övervaka, diagnostisera och felsöka Azure Storage.

Enqueue

Eftersom Lagringsköer stöder HTTP-API:et spåras alla åtgärder med kön automatiskt av Application Insights. I många fall bör den här instrumentationen vara tillräcklig. För att korrelera spårningar på konsumentsidan med producentspårningar måste du skicka en korrelationskontext som liknar hur vi gör det i HTTP-protokollet för korrelation.

Det här exemplet visar hur du spårar åtgärden Enqueue . Du kan:

  • Korrelera återförsök (om några): De har alla en gemensam överordnad som är åtgärden Enqueue . Annars spåras de som underordnade till den inkommande begäran. Om det finns flera logiska begäranden till kön kan det vara svårt att hitta vilket anrop som resulterade i återförsök.
  • Korrelera lagringsloggar (om och när det behövs): De korreleras med Application Insights-telemetri.

Åtgärden Enqueue är underordnad en överordnad åtgärd. Ett exempel är en inkommande HTTP-begäran. HTTP-beroendeanropet är underordnad åtgärden Enqueue och barnbarnet till den inkommande begäran.

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

Om du vill minska mängden telemetri i dina programrapporter eller om du inte vill spåra Enqueue åtgärden av andra skäl använder du API:et Activity direkt:

  • Skapa (och starta) en ny Activity i stället för att starta Application Insights-åtgärden. Du behöver inte tilldela några egenskaper för den förutom åtgärdsnamnet.
  • Serialisera yourActivity.Id i meddelandets nyttolast i stället för operation.Telemetry.Id. Du kan också använda Activity.Current.Id.

Inaktivera kö

EnqueuePå samma sätt spåras en faktisk HTTP-begäran till lagringskö automatiskt av Application Insights. Åtgärden Enqueue sker förmodligen i den överordnade kontexten, till exempel en kontext för inkommande begäranden. Application Insights SDK:er korrelerar automatiskt en sådan åtgärd och dess HTTP-del med den överordnade begäran och annan telemetri som rapporteras i samma omfång.

Åtgärden Dequeue är knepig. Application Insights SDK spårar automatiskt HTTP-begäranden. Men den känner inte till korrelationskontexten förrän meddelandet parsas. Det går inte att korrelera HTTP-begäran för att få meddelandet med resten av telemetrin, särskilt när fler än ett meddelande tas emot.

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

Process

I följande exempel spåras ett inkommande meddelande på ett sätt som liknar en inkommande HTTP-begäran:

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

På samma sätt kan andra köåtgärder instrumenteras. En granskningsåtgärd bör instrumenteras på ett liknande sätt som en dequeue-åtgärd. Instrumentering av köhanteringsåtgärder är inte nödvändigt. Application Insights spårar åtgärder som HTTP, och i de flesta fall räcker det.

När du instrumentera borttagning av meddelanden kontrollerar du att du anger åtgärdsidentifierarna (korrelation). Du kan också använda API:et Activity . Sedan behöver du inte ange åtgärdsidentifierare för telemetriobjekten eftersom Application Insights SDK gör det åt dig:

  • Skapa en ny Activity när du har fått ett objekt från kön.
  • Använd Activity.SetParentId(message.ParentId) för att korrelera konsument- och producentloggar.
  • ActivityStarta .
  • Spåra dequeue-, process- och borttagningsåtgärder med hjälp av hjälpfunktioner Start/StopOperation . Gör det från samma asynkrona kontrollflöde (körningskontext). På så sätt korreleras de korrekt.
  • ActivityStoppa .
  • Använd Start/StopOperation eller anropa Track telemetri manuellt.

Beroendetyper

Application Insights använder beroendetyp för att anpassa användargränssnittsupplevelser. För köer identifieras följande typer av som förbättrar upplevelsen av DependencyTelemetry transaktionsdiagnostik:

  • Azure queue för Azure Storage-köer
  • Azure Event Hubs för Azure Event Hubs
  • Azure Service Bus för Azure Service Bus

Batchbearbetning

Med vissa köer kan du ta bort flera meddelanden med en begäran. Bearbetningen av sådana meddelanden är förmodligen oberoende och tillhör de olika logiska åtgärderna. Det går inte att korrelera åtgärden Dequeue med ett visst meddelande som bearbetas.

Varje meddelande ska bearbetas i sitt eget asynkrona kontrollflöde. Mer information finns i avsnittet Spårning av utgående beroenden.

Långvariga bakgrundsaktiviteter

Vissa program startar tidskrävande åtgärder som kan orsakas av användarbegäranden. Ur spårnings-/instrumentationsperspektivet skiljer det sig inte från instrumentation för begäran eller beroende:

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

I det här exemplet telemetryClient.StartOperation skapar DependencyTelemetry och fyller korrelationskontexten. Anta att du har en överordnad åtgärd som skapades av inkommande begäranden som schemalagt åtgärden. Så länge som BackgroundTask startar i samma asynkrona kontrollflöde som en inkommande begäran korreleras den med den överordnade åtgärden. BackgroundTask och alla kapslade telemetriobjekt korreleras automatiskt med den begäran som orsakade den, även när begäran har avslutats.

När aktiviteten startar från bakgrundstråden som inte har någon åtgärd (Activity) associerad med den, BackgroundTask har den ingen överordnad. Den kan dock ha kapslade åtgärder. Alla telemetriobjekt som rapporteras från aktiviteten korreleras till de som skapats DependencyTelemetry i BackgroundTask.

Spårning av utgående beroenden

Du kan spåra din egen beroendetyp eller en åtgärd som inte stöds av Application Insights.

Metoden Enqueue i Service Bus-kön eller lagringskön kan fungera som exempel för sådan anpassad spårning.

Den allmänna metoden för anpassad beroendespårning är att:

  • Anropa metoden TelemetryClient.StartOperation (tillägg) som fyller de DependencyTelemetry egenskaper som behövs för korrelation och vissa andra egenskaper, till exempel start, tidsstämpel och varaktighet.
  • Ange andra anpassade egenskaper för DependencyTelemetry, till exempel namnet och alla andra kontexter som du behöver.
  • Ring ett beroendeanrop och vänta på det.
  • Stoppa åtgärden med StopOperation när den är klar.
  • Hantera undantag.
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.
        }
    }
}

Om du tar bort en åtgärd stoppas åtgärden, så du kan göra det i stället för att anropa StopOperation.

Varning

I vissa fall kan ett ohanterat undantag förhindrafinally att anropas, så åtgärder kanske inte spåras.

Bearbetning och spårning av parallella åtgärder

Anrop StopOperation stoppar bara den åtgärd som startades. Om den aktuella åtgärden som körs inte matchar den som du vill stoppa, StopOperation gör ingenting. Den här situationen kan inträffa om du startar flera åtgärder parallellt i samma körningskontext.

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;

Se till att du alltid anropar StartOperation och bearbetar åtgärden i samma asynkron metod för att isolera åtgärder som körs parallellt. Om åtgärden är synkron (eller inte asynkron), omsluter du processen och spårar med 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-åtgärder jämfört med System.Diagnostics.Activity

System.Diagnostics.Activity representerar den distribuerade spårningskontexten och används av ramverk och bibliotek för att skapa och sprida kontext i och utanför processen och korrelera telemetriobjekt. Activity fungerar tillsammans med System.Diagnostics.DiagnosticSource som meddelandemekanism mellan ramverket/biblioteket för att meddela om intressanta händelser som inkommande eller utgående begäranden och undantag.

Aktiviteter är förstklassiga medborgare i Application Insights. Automatisk beroende- och begärandeinsamling är starkt beroende av dem tillsammans med DiagnosticSource händelser. Om du har skapat Activity i ditt program skulle det inte leda till att Application Insights-telemetri skapas. Application Insights måste ta emot DiagnosticSource händelser och känna till händelsernas namn och nyttolaster för att översättas Activity till telemetri.

Varje Application Insights-åtgärd (begäran eller beroende) omfattar Activity. När StartOperation anropas skapas Activity den under. StartOperation är det rekommenderade sättet att spåra telemetrier för begäran eller beroende manuellt och se till att allt är korrelerat.

Nästa steg