Exporting Custom OpenTelemetry Metrics to Azure Monitor using ASP.NET Core

OpenTelemetry Metrics

OpenTelemetry is an observability framework that provides APIs, libraries, agents, and instrumentation to collect distributed traces and metrics from an application. It's an open-source, CNCF project that aims to standardize the generation and collection of telemetry data (metrics, logs, and traces) for cloud-native software.

In this article, you will learn how to export custom OpenTelemetry metrics from your ASP.NET Core applications to Azure Monitor.

Here are the steps to follow along.

  • Create a new Application Insights resource in Azure. You can use the detailed instructions in this Microsoft Learn guide to create the resource using the Azure Portal or Azure CLI. Please copy the connection string for the resource as you will need it later.
    Application Insights resource
  • Create a new ASP.NET Core Minimal API project using your preferred IDE or the .NET CLI. Please follow the instructions in this Microsoft guide to create the project. Use an officially supported version of .NET Core to avoid any issues.
  • Install the latest version of the following NuGet packages in your project.
    dotnet add package Azure.Monitor.OpenTelemetry.AspNetCore
  • Replace the contents of the Program.cs file with the following code.
    using System.Diagnostics.Metrics;
    using Azure.Monitor.OpenTelemetry.AspNetCore;
    using Azure.Monitor.OpenTelemetry.Exporter;
    using OpenTelemetry.Metrics;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Configure the OpenTelemetry meter provider to add a meter named "OTel.AzureMonitor.Demo".
    builder.Services.ConfigureOpenTelemetryMeterProvider((sp, builder) =>
        builder.AddMeter("OTel.AzureMonitor.Demo"));
    
    // Add the Azure Monitor telemetry service to the application.
    // This service will collect and send telemetry data to Azure Monitor.
    builder.Services.AddOpenTelemetry().UseAzureMonitor();
    
    // Build the ASP.NET Core web application.
    var app = builder.Build();
    
    // Create a new meter named "OTel.AzureMonitor.Demo".
    var meter = new Meter("OTel.AzureMonitor.Demo");
    
    // Create a new counter metric named "MyDiceCounter".
    var myDiceCounter = meter.CreateCounter<long>("MyDiceCounter");
    
    app.MapGet("/metrics-demo", () =>
    {
        var gameId = Guid.NewGuid().ToString();
        for (var i = 0; i < 5; i++)
        {
            var diceValue = new Random().Next(1, 6);
            myDiceCounter.Add(1, new("faceValue", diceValue), new("gameId", gameId));
        }
    
        return "Counter incremented";
    });
    
    // Run the application.
    app.Run();
    

The above code snippet demonstrates how to set up an ASP.NET Core web application with OpenTelemetry and Azure Monitor integration for the purpose of collecting and exporting telemetry data. It configures the OpenTelemetry meter provider to add a meter named OTel.AzureMonitor.Demo. Additionally, it adds the Azure Monitor telemetry service to the application, which is responsible for collecting and sending telemetry data to Azure Monitor.

Following the setup, the program creates a new meter named OTel.AzureMonitor.Demo. Then, it creates a new counter metric named MyDiceCounter from the meter.

To explain the usage of the metric, let's consider a scenario where we want to play a game where we count the number of times a dice value is generated. In this case, when the endpoint at /metrics-demo is invoked, the program increments the MyDiceCounter counter by 1. The value of the dice roll is randomly generated five times between 1 and 6 and is stored as a tag for the metric value. Additionally, the unique game ID is also recorded with the metric value as a tag. Finally, the endpoint returns the message "Counter incremented" as the result of the operation.

Before proceeding further with debugging the application, you need to configure the connection string for the Application Insights resource that you created earlier. To do so, set the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable to the connection string. You can do this by running the following command in the terminal.

APPLICATIONINSIGHTS_CONNECTION_STRING=<connection-string>

Output

Debug the application and invoke the endpoint at /metrics-demo a few times. Every successful invocation of the endpoint will increment the metric for the counter by 1. Every measurement recorded will be exported to Azure Monitor where it will be summed by tags that are associated with the metric.

To view the exported metrics, visit the Azure Portal and navigate to the Application Insights resource that you created earlier. Click on the Logs tab and run the following query.

customMetrics   
| project timestamp, value, faceValue = tostring(customDimensions["faceValue"]), gameId = tostring(customDimensions["gameId"])

The following screenshot shows the output of the query.

Query

Let's break down the query to understand the output. The query first selects the custom metrics table, which contains the custom metrics that were exported to Azure Monitor. Then, it projects the timestamp, value, faceValue, and gameId columns from the table. The face value and gameId columns are extracted from the customDimensions column, which contains the tags associated with the metric.

You can now plot the results on a chart by clicking on the Chart button. The following screenshot shows the chart for the query output.

 Chart button

To explore the integration between Azure Monitor and OpenTelemetry further, including the various types of metrics that can be exported, please refer to the official documentation.