Lacak operasi kustom dengan Application Insights .NET SDK

Application Insights SDK secara otomatis melacak permintaan HTTP masuk dan panggilan ke layanan dependen, seperti permintaan HTTP dan kueri SQL. Pelacakan dan korelasi permintaan dan dependensi memberi Anda visibilitas ke dalam responsivitas dan keandalan seluruh aplikasi di semua layanan mikro yang menggabungkan aplikasi ini.

Ada kelas pola aplikasi yang tidak dapat didukung secara generis. Pemantauan yang tepat pada pola tersebut memerlukan instrumentasi kode manual. Artikel ini membahas beberapa pola yang mungkin memerlukan instrumentasi manual, seperti pemrosesan antrean kustom dan menjalankan tugas latar belakang yang berjalan lama.

Artikel ini menyediakan panduan tentang cara melacak operasi kustom dengan Application Insights SDK. Dokumentasi ini relevan untuk:

  • Application Insights untuk .NET (juga dikenal sebagai Base SDK) versi 2.4+.
  • Application Insights untuk aplikasi web (menjalankan ASP.NET) versi 2.4+.
  • Application Insights untuk ASP.NET Core versi 2.1+.

Catatan

Dokumentasi berikut bergantung pada API klasik Application Insights. Rencana jangka panjang untuk Application Insights adalah mengumpulkan data menggunakan OpenTelemetry. Untuk informasi selengkapnya, lihat Mengaktifkan Azure Monitor OpenTelemetry untuk aplikasi .NET, Node.js, Python, dan Java.

Gambaran Umum

Operasi adalah bagian logis dari pekerjaan yang dijalankan oleh aplikasi. Operasi memiliki nama, waktu mulai, durasi, hasil, dan konteks eksekusi seperti nama pengguna, properti, dan hasil. Jika operasi A dimulai oleh operasi B, maka operasi B ditetapkan sebagai induk untuk A. Operasi hanya dapat memiliki satu induk, tetapi dapat memiliki banyak operasi anak. Untuk informasi selengkapnya tentang operasi dan korelasi telemetri, lihat Korelasi telemetri Application Insights.

Dalam Application Insights .NET SDK, operasi ini dijelaskan oleh OperationTelemetry kelas abstrak dan keturunannya RequestTelemetry dan DependencyTelemetry.

Pelacakan operasi masuk

Web SDK Application Insights secara otomatis mengumpulkan permintaan HTTP untuk aplikasi ASP.NET yang berjalan dalam pipeline IIS dan semua aplikasi ASP.NET Core. Ada solusi yang didukung komunitas untuk platform dan kerangka kerja lainnya. Jika aplikasi tidak didukung oleh salah satu solusi standar atau yang didukung komunitas, Anda dapat melengkapinya secara manual.

Contoh lain yang memerlukan pelacakan kustom adalah pekerja yang menerima item dari antrean. Untuk beberapa antrean, panggilan untuk menambahkan pesan ke antrean ini dilacak sebagai dependensi. Operasi tingkat tinggi yang menjelaskan pemrosesan pesan tidak dikumpulkan secara otomatis.

Mari kita lihat cara operasi tersebut dapat dilacak.

Pada tingkat tinggi, tugasnya adalah membuat RequestTelemetry dan mengatur properti yang diketahui. Setelah operasi selesai, Anda lacak telemetrinya. Diagram berikut menunjukkan tugas ini.

Permintaan HTTP di aplikasi Owin yang dihosting sendiri

Dalam contoh ini, konteks jejak disebarkan sesuai dengan Protokol HTTP untuk Korelasi. Tunggu untuk menerima header yang dijelaskan di sana.

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

Protokol HTTP untuk Korelasi juga mendeklarasikan header Correlation-Context. Ini dihilangkan di sini untuk kesederhanaan.

Instrumentasi antrean

Konteks Pelacakan W3C dan Protokol HTTP untuk detail korelasi pass Korelasi dengan permintaan HTTP, tetapi setiap protokol antrean harus menentukan bagaimana detail yang sama diteruskan di sepanjang pesan antrean. Beberapa protokol antrean, seperti AMQP, memungkinkan melewati lebih banyak metadata. Protokol lain, seperti Azure Storage Queue, mengharuskan konteks dikodekan ke dalam payload pesan.

Catatan

Pelacakan lintas komponen belum didukung untuk antrean.

Dengan HTTP, jika produsen dan konsumen Anda mengirim telemetri ke sumber daya Application Insights yang berbeda, pengalaman diagnostik transaksi dan Peta Aplikasi menampilkan transaksi dan memetakan secara menyeluruh. Dalam kasus antrean, kemampuan ini belum didukung.

Antrean Microsoft Azure Service Bus

Untuk informasi pelacakan, lihat Pelacakan dan korelasi terdistribusi melalui olahpesan Azure Bus Layanan.

Antrean Azure Storage

Contoh berikut menunjukkan cara melacak operasi antrean Azure Storage dan menghubungkan telemetri antara produsen, konsumen, dan Azure Storage.

Antrean Penyimpanan memiliki HTTP API. Semua panggilan ke antrean dilacak oleh Kolektor Dependensi Application Insights untuk permintaan HTTP. Ini dikonfigurasi secara default pada aplikasi ASP.NET dan ASP.NET Core. Dengan jenis aplikasi lain, lihat dokumentasi aplikasi Konsol.

Anda juga mungkin ingin menghubungkan ID operasi Application Insights dengan ID permintaan Penyimpanan. Untuk informasi tentang cara mengatur dan mendapatkan klien permintaan Penyimpanan dan ID permintaan server, lihat Memantau, mendiagnosis, dan memecahkan masalah Azure Storage.

Masukkan Antrean

Karena antrean Penyimpanan mendukung HTTP API, semua operasi dengan antrean secara otomatis dilacak oleh Application Insights. Dalam banyak kasus, instrumentasi ini cukup. Untuk menghubungkan jejak di sisi konsumen dengan jejak produsen, Anda harus melewati beberapa konteks korelasi yang mirip dengan cara kami melakukannya dalam Protokol HTTP untuk Korelasi.

Contoh ini menunjukkan cara melacak operasi Enqueue. Anda dapat:

  • Menyambungkan percobaan kembali (jika ada): Mereka semua memiliki satu induk umum yaitu operasi Enqueue. Jika tidak, mereka dilacak sebagai anak dari permintaan masuk. Jika ada beberapa permintaan logis untuk antrean, mungkin sulit untuk menemukan panggilan mana yang mengakibatkan percobaan kembali.
  • Menyambungkan log Penyimpanan (jika dan ketika diperlukan): Mereka disambungkan dengan telemetri Application Insights.

Operasi Enqueue ini adalah turunan dari operasi induk. Contohnya adalah permintaan HTTP masuk. Panggilan dependensi HTTP adalah anak dari Enqueue operasi dan cucu permintaan masuk.

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

Untuk mengurangi jumlah telemetri laporan aplikasi Anda atau jika Anda tidak ingin melacak operasi Enqueue karena alasan lain, gunakan API Activity secara langsung:

  • Buat (dan mulai) Activity baru daripada memulai operasi Application Insights. Anda tidak perlu menetapkan properti apa pun di atasnya kecuali nama operasi.
  • Pembuat serialisasi yourActivity.Id ke dalam muatan pesan daripada operation.Telemetry.Id. Anda juga dapat menggunakan Activity.Current.Id.

Keluarkan dari Antrean

Serupa dengan Enqueue, permintaan HTTP aktual ke antrean Penyimpanan secara otomatis dilacak oleh Application Insights. Enqueue Operasi ini mungkin terjadi dalam konteks induk, seperti konteks permintaan masuk. Application Insights SDK secara otomatis menghubungkan operasi seperti itu, dan bagian HTTP-nya, dengan permintaan induk dan telemetri lain yang dilaporkan dalam cakupan yang sama.

Operasi Dequeue rumit. Application Insights SDK secara otomatis melacak permintaan HTTP. Tetapi tidak tahu konteks korelasi sampai pesan diurai. Tidak dimungkinkan untuk menghubungkan permintaan HTTP untuk mendapatkan pesan dengan telemetri lainnya, terutama ketika lebih dari satu pesan diterima.

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

Proses

Dalam contoh berikut, pesan masuk dilacak dengan cara yang mirip dengan permintaan HTTP masuk:

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

Demikian pula, operasi antrean lainnya dapat dijadikan instrumen. Operasi intip harus dijadikan instrumen dengan cara yang sama seperti operasi keluarkan dari antrean. Instrumentasi operasi manajemen antrean tidak diperlukan. Application Insights melacak operasi seperti HTTP, dan dalam banyak kasus, itu cukup.

Saat Anda menghapus pesan instrumen, pastikan Anda mengatur pengidentifikasi operasi (korelasi). Selain itu, Anda dapat menggunakan ActivityAPI. Maka Anda tidak perlu mengatur pengidentifikasi operasi pada item telemetri karena Application Insights SDK melakukannya untuk Anda:

  • Buat Activity baru setelah Anda mendapatkan item dari antrean.
  • Gunakan Activity.SetParentId(message.ParentId) untuk mengkorelasikan log konsumen dan produsen.
  • Mulai Activity.
  • Lacak keluarkan dari antrean, proses, dan hapus operasi dengan menggunakan pembantu Start/StopOperation. Lakukan dari alur kontrol asinkron yang sama (konteks eksekusi). Dengan cara ini, mereka berkorelasi dengan benar.
  • Hentikan Activity.
  • Gunakan Start/StopOperation atau panggil Track telemetri secara manual.

Jenis dependensi

Application Insights menggunakan jenis dependensi untuk menyesuaikan pengalaman UI. Untuk antrean, ia mengenali jenis berikut yang DependencyTelemetry meningkatkan pengalaman diagnostik Transaksi:

  • Azure queue untuk antrean Azure Storage
  • Azure Event Hubs untuk Azure Event Hubs
  • Azure Service Bus untuk Azure Service Bus

Pemrosesan batch

Dengan beberapa antrean, Anda dapat mengeluarkan beberapa pesan dari antrean dengan satu permintaan. Memproses pesan tersebut mungkin independen dan termasuk dalam operasi logis berbeda. Tidak mungkin untuk menghubungkan operasi Dequeue ke pesan tertentu yang sedang diproses.

Setiap pesan harus diproses dalam alur kontrol asinkronnya sendiri. Untuk informasi selengkapnya, lihat bagian Pelacakan dependensi keluar.

Tugas latar belakang yang berjalan lama

Beberapa aplikasi memulai operasi jangka panjang yang mungkin disebabkan oleh permintaan pengguna. Dari perspektif pelacakan/instrumentasi, tidak berbeda dengan instrumentasi permintaan atau dependensi:

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

Dalam contoh ini, telemetryClient.StartOperationmembuat DependencyTelemetry dan mengisi konteks korelasi. Semisal Anda memiliki operasi induk yang dibuat oleh permintaan masuk yang menjadwalkan operasi. Selama BackgroundTask dimulai dalam alur kontrol asinkron yang sama dengan permintaan masuk, upaya itu berkorelasi dengan operasi induk itu. BackgroundTask dan semua item telemetri bertumpuk secara otomatis berkorelasi dengan permintaan yang menyebabkannya, bahkan setelah permintaan berakhir.

Ketika tugas dimulai dari thread latar belakang yang tidak memiliki operasi apa pun (Activity) yang terkait dengannya, BackgroundTask tidak memiliki induk. Namun, ia dapat memiliki operasi bertumpuk. Semua item telemetri yang dilaporkan dari tugas berkorelasi dengan DependencyTelemetry yang dibuat di BackgroundTask.

Pelacakan dependensi keluar

Anda dapat melacak jenis dependensi Anda sendiri atau operasi yang tidak didukung oleh Application Insights.

Metode Enqueue dalam antrean Bus Layanan atau antrean Penyimpanan dapat berfungsi sebagai contoh untuk pelacakan kustom tersebut.

Pendekatan umum untuk pelacakan dependensi kustom adalah:

  • TelemetryClient.StartOperation Panggil metode (ekstensi) yang mengisi DependencyTelemetry properti yang diperlukan untuk korelasi dan beberapa properti lainnya, seperti mulai, stempel waktu, dan durasi.
  • Atur properti kustom lainnya pada DependencyTelemetry, seperti nama dan konteks lain yang Anda butuhkan.
  • Lakukan panggilan dependensi dan tunggu.
  • Hentikan operasi StopOperation ketika sudah selesai.
  • Menangani pengecualian.
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.
        }
    }
}

Membuang operasi menyebabkan operasi berhenti, sehingga Anda mungkin melakukannya alih-alih memanggil StopOperation.

Peringatan

Dalam beberapa kasus, pengecualian yang tidak tertangani mungkin mencegahfinally dipanggil, sehingga operasi mungkin tidak dilacak.

Pemrosesan dan pelacakan operasi paralel

StopOperation Panggilan hanya menghentikan operasi yang dimulai. Jika operasi yang berjalan saat ini tidak cocok dengan operasi yang ingin Anda hentikan, StopOperation tidak melakukan apa pun. Situasi ini mungkin terjadi jika Anda memulai beberapa operasi secara paralel dalam konteks eksekusi yang sama.

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;

Pastikan Anda selalu memanggil StartOperation dan memproses operasi dalam metode asinkron yang sama untuk mengisolasi operasi yang berjalan secara paralel. Jika operasi sinkron (atau tidak asinkron), bungkus proses dan lacak dengan 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);
}

Operasi ApplicationInsights vs. System.Diagnostics.Activity

System.Diagnostics.Activity mewakili konteks pelacakan terdistribusi dan digunakan oleh kerangka kerja dan pustaka untuk membuat dan menyebarkan konteks di dalam dan di luar proses dan menghubungkan item telemetri. Activity bekerja sama dengan System.Diagnostics.DiagnosticSource sebagai mekanisme pemberitahuan antara kerangka kerja/pustaka untuk memberi tahu tentang peristiwa menarik seperti permintaan masuk atau keluar dan pengecualian.

Aktivitas adalah warga negara kelas satu di Application Insights. Dependensi otomatis dan pengumpulan permintaan sangat bergantung pada mereka bersama dengan DiagnosticSource peristiwa. Jika Anda membuat Activity di aplikasi, itu tidak akan mengakibatkan telemetri Application Insights dibuat. Application Insights perlu menerima DiagnosticSource peristiwa dan mengetahui nama peristiwa dan payload untuk diterjemahkan Activity ke dalam telemetri.

Setiap operasi Application Insights (permintaan atau dependensi) melibatkan Activity. Ketika StartOperation dipanggil, itu menciptakan Activity di bawahnya. StartOperation adalah cara yang disarankan untuk melacak telemetri permintaan atau dependensi secara manual dan memastikan semuanya berkorelasi.

Langkah berikutnya