OpenTelemetry using .NET
This guide explains how to configure a .NET app using the .NET OpenTelemetry SDK to send telemetry data to Axiom.
OpenTelemetry provides a unified approach to collecting telemetry data from your .NET applications. This guide explains how to configure OpenTelemetry in a .NET application to send telemetry data to Axiom using the OpenTelemetry SDK.
Prerequisites
- Create an Axiom account.
- Create a dataset where you want to send data.
- Create an API token in Axiom with permissions to ingest and query data.
- Install the .NET 6.0 SDK on your development machine.
- Use your existing .NET application or start with the sample provided in the
program.cs
below.
Install dependencies
Run the following command in your terminal to install the necessary NuGet packages:
dotnet add package OpenTelemetry --version 1.7.0
dotnet add package OpenTelemetry.Exporter.Console --version 1.7.0
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --version 1.7.0
dotnet add package OpenTelemetry.Extensions.Hosting --version 1.7.0
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --version 1.7.1
dotnet add package OpenTelemetry.Instrumentation.Http --version 1.6.0-rc.1
Replace the dotnet.csproj
file in your project with the following:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.6.0-rc.1" />
</ItemGroup>
</Project>
The dotnet.csproj
file is important for defining your project’s settings, including target framework, nullable reference types, and package references. It informs the .NET SDK and build tools about the components and configurations your project requires.
Core application
program.cs
is the core of the .NET application. It uses ASP.NET to create a simple web server. The server has an endpoint /rolldice
that returns a random number, simulating a basic API.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Globalization;
// Set up the web application builder
var builder = WebApplication.CreateBuilder(args);
// Configure OpenTelemetry for detailed tracing information
TracingConfiguration.ConfigureOpenTelemetry();
var app = builder.Build();
// Map the GET request for '/rolldice/{player?}' to a handler
app.MapGet("/rolldice/{player?}", (ILogger<Program> logger, string? player) =>
{
// Start a manual tracing activity
using var activity = TracingConfiguration.StartActivity("HandleRollDice");
// Call the RollDice function to get a dice roll result
var result = RollDice();
if (activity != null)
{
// Add detailed information to the tracing activity for debugging and monitoring
activity.SetTag("player.name", player ?? "anonymous"); // Tag the player’s name, default to 'anonymous' if not provided
activity.SetTag("dice.rollResult", result); // Tag the result of the dice roll
activity.SetTag("operation.success", true); // Flag the operation as successful
activity.SetTag("custom.attribute", "Additional detail here"); // Add a custom attribute for potential further detail
}
// Log the dice roll event
LogRollDice(logger, player, result);
// Retur the dice roll result as a string
return result.ToString(CultureInfo.InvariantCulture);
});
// Start the web application
app.Run();
// Log function to log the result of a dice roll
void LogRollDice(ILogger logger, string? player, int result)
{
// Log message varies based on whether a player’s name is provided
if (string.IsNullOrEmpty(player))
{
// Log for an anonymous player
logger.LogInformation("Anonymous player is rolling the dice: {result}", result);
}
else
{
// Log for a named player
logger.LogInformation("{player} is rolling the dice: {result}", player, result);
}
}
// Function to roll a dice and return a random number between 1 and 6
int RollDice()
{
// Use the shared instance of Random for thread safety
return Random.Shared.Next(1, 7);
}
Exporter
The tracing.cs
file sets up the OpenTelemetry instrumentation. It configures the OTLP (OpenTelemetry Protocol) exporters for traces and initializes the ASP.NET SDK with automatic instrumentation capabilities.
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Diagnostics;
using System.Reflection;
// Class to configure OpenTelemetry tracing
public static class TracingConfiguration
{
// Declare an ActivitySource for creating tracing activities
private static readonly ActivitySource ActivitySource = new("MyCustomActivitySource");
// Configure OpenTelemetry with custom settings and instrumentation
public static void ConfigureOpenTelemetry()
{
// Retrieve the service name and version from the executing assembly metadata
var serviceName = Assembly.GetExecutingAssembly().GetName().Name ?? "UnknownService";
var serviceVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "UnknownVersion";
// Set up the tracer provider with various configurations
Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(
// Set resource attributes including service name and version
ResourceBuilder.CreateDefault().AddService(serviceName, serviceVersion: serviceVersion)
.AddAttributes(new[] { new KeyValuePair<string, object>("environment", "development") }) // Additional attributes
.AddTelemetrySdk() // Add telemetry SDK information to the traces
.AddEnvironmentVariableDetector()) // Detect resource attributes from environment variables
.AddSource(ActivitySource.Name) // Add the ActivitySource defined above
.AddAspNetCoreInstrumentation() // Add automatic instrumentation for ASP.NET Core
.AddHttpClientInstrumentation() // Add automatic instrumentation for HttpClient requests
.AddOtlpExporter(options => // Configure the OTLP exporter
{
options.Endpoint = new Uri("https://api.axiom.co/v1/traces"); // Set the endpoint for the exporter
options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf; // Set the protocol
options.Headers = "Authorization=Bearer API_TOKEN, X-Axiom-Dataset=DATASET"; // Update API token and dataset
})
.Build(); // Build the tracer provider
}
// Method to start a new tracing activity with an optional activity kind
public static Activity? StartActivity(string activityName, ActivityKind kind = ActivityKind.Internal)
{
// Starts and returns a new activity if sampling allows it, otherwise returns null
return ActivitySource.StartActivity(activityName, kind);
}
}
In the tracing.cs
file, make the following changes:
- Replace the value of the
serviceName
variable with the name of the service you want to trace. This is used for identifying and categorizing trace data, particularly in systems with multiple services. - Replace
API_TOKEN
with your Axiom API key. - Replace
DATASET_NAME
with the name of the Axiom dataset where you want to send data.
Run the instrumented application
-
Run in local development mode using the development settings in
appsettings.development.json
. Ensure your Axiom API token and dataset name are correctly set intracing.cs
. -
Before deploying, run in production mode by switching to
appsettings.json
for production settings. Ensure your Axiom API token and dataset name are correctly set intracing.cs
. -
Run your application with
dotnet run
. Your application starts and you can interact with it by sending requests to the/rolldice
endpoint.
For example, if you are using port 8080
, your application is accessible locally at http://localhost:8080/rolldice
. This URL will direct your requests to the /rolldice
endpoint of your server running on your local machine.
Observe the telemetry data
As you interact with your application, traces are collected and exported to Axiom where you can monitor and analyze your application’s performance and behavior.
-
Log into your Axiom account and click the Datasets or Stream tab.
-
Select your dataset from the list.
-
From the list of fields, click on the trace_id, to view your spans.
Dynamic OpenTelemetry Traces dashboard
The data can then be further viewed and analyzed in the traces dashboard, providing insights into the performance and behavior of your application.
-
Log into your Axiom account, select Dashboards, and click on the traces dashboard named after your dataset.
-
View the dashboard which displays your total traces, incoming spans, average span duration, errors, slowest operations, and top 10 span errors across services.
Send data from an existing .NET project
Manual Instrumentation
Manual instrumentation involves adding code to create, configure, and manage telemetry data, such as traces and spans, providing control over what data is collected.
- Initialize ActivitySource. Define an
ActivitySource
to create activities (spans) for tracing specific operations within your application.
private static readonly ActivitySource MyActivitySource = new ActivitySource("MyActivitySourceName");
- Start and stop activities. Manually start activities (spans) at the beginning of the operations you want to trace and stop them when the operations complete. You can add custom attributes to these activities for more detailed tracing.
using var activity = MyActivitySource.StartActivity("MyOperationName");
activity?.SetTag("key", "value");
// Perform the operation here
activity?.Stop();
- Add custom attributes. Enhance activities with custom attributes to provide additional context, making it easier to analyze telemetry data.
activity?.SetTag("UserId", userId);
activity?.SetTag("OperationDetail", "Detail about the operation");
Automatic Instrumentation
Automatic instrumentation uses the OpenTelemetry SDK and additional libraries to automatically generate telemetry data for certain operations, such as incoming HTTP requests and database queries.
- Configure OpenTelemetry SDK. Use the OpenTelemetry SDK to configure automatic instrumentation in your application. This typically involves setting up a
TracerProvider
in yourprogram.cs
or startup configuration, which automatically captures telemetry data from supported libraries.
Sdk.CreateTracerProviderBuilder()
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri("https://api.axiom.co/v1/traces");
// Ensure to replace YOUR_API_TOKEN and YOUR_DATASET_NAME with your actual API token and dataset name
options.Headers = $"Authorization=Bearer YOUR_API_TOKEN, X-Axiom-Dataset=YOUR_DATASET_NAME";
})
.Build();
-
Install and configure additional OpenTelemetry instrumentation packages as needed, based on the technologies your application uses. For example, to automatically trace SQL database queries, you might add the corresponding database instrumentation package.
-
With automatic instrumentation set up, no further code changes are required for tracing basic operations. The OpenTelemetry SDK and its instrumentation packages handle the creation and management of traces for supported operations.
Reference
List of OpenTelemetry trace fields
Field Category | Field Name | Description |
---|---|---|
General Trace Information | ||
_rowId | Unique identifier for each row in the trace data. | |
_sysTime | System timestamp when the trace data was recorded. | |
_time | Timestamp when the actual event being traced occurred. | |
trace_id | Unique identifier for the entire trace. | |
span_id | Unique identifier for the span within the trace. | |
parent_span_id | Unique identifier for the parent span within the trace. | |
HTTP Attributes | ||
attributes.http.request.method | HTTP method used for the request. | |
attributes.http.response.status_code | HTTP status code returned in response. | |
attributes.http.route | Route accessed during the HTTP request. | |
attributes.url.path | Path component of the URL accessed. | |
attributes.url.scheme | Scheme component of the URL accessed. | |
attributes.server.address | Address of the server handling the request. | |
attributes.server.port | Port number on the server handling the request. | |
Network Attributes | ||
attributes.network.protocol.version | Version of the network protocol used. | |
User Agent | ||
attributes.user_agent.original | Original user agent string, providing client software and OS. | |
Custom Attributes | ||
attributes.custom[“custom.attribute”] | Custom attribute provided in the trace. | |
attributes.custom[“dice.rollResult”] | Result of a dice roll operation. | |
attributes.custom[“operation.success”] | Indicates if the operation was successful. | |
attributes.custom[“player.name”] | Name of the player in the operation. | |
Operational Details | ||
duration | Time taken for the operation. | |
kind | Type of span (e.g., server, client, internal). | |
name | Name of the span. | |
Resource Attributes | ||
resource.custom.environment | Environment where the trace was captured, e.g., development. | |
Telemetry SDK Attributes | ||
telemetry.sdk.language | Language of the telemetry SDK, e.g., dotnet. | |
telemetry.sdk.name | Name of the telemetry SDK, e.g., opentelemetry. | |
telemetry.sdk.version | Version of the telemetry SDK, e.g., 1.7.0. | |
Service Attributes | ||
service.instance.id | Unique identifier for the instance of the service. | |
service.name | Name of the service generating the trace, e.g., dotnet. | |
service.version | Version of the service generating the trace, e.g., 1.0.0.0. | |
Scope Attributes | ||
scope.name | Name of the scope for the operation, e.g., OpenTelemetry.Instrumentation.AspNetCore. | |
scope.version | Version of the scope, e.g., 1.0.0.0. |
List of imported libraries
OpenTelemetry
<PackageReference Include="OpenTelemetry" Version="1.7.0" />
This is the core SDK for OpenTelemetry in .NET. It provides the foundational tools needed to collect and manage telemetry data within your .NET applications. It’s the base upon which all other OpenTelemetry instrumentation and exporter packages build.
OpenTelemetry.Exporter.Console
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
This package allows applications to export telemetry data to the console. It is primarily useful for development and testing purposes, offering a simple way to view the telemetry data your application generates in real time.
OpenTelemetry.Exporter.OpenTelemetryProtocol
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
This package enables your application to export telemetry data using the OpenTelemetry Protocol (OTLP) over gRPC or HTTP. It’s vital for sending data to observability platforms that support OTLP, ensuring your telemetry data can be easily analyzed and monitored across different systems.
OpenTelemetry.Extensions.Hosting
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
Designed for .NET applications, this package integrates OpenTelemetry with the .NET Generic Host. It simplifies the process of configuring and managing the lifecycle of OpenTelemetry resources such as TracerProvider, making it easier to collect telemetry data in applications that use the hosting model.
OpenTelemetry.Instrumentation.AspNetCore
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.1" />
This package is designed for instrumenting ASP.NET Core applications. It automatically collects telemetry data about incoming requests and responses. This is important for monitoring the performance and reliability of web applications and APIs built with ASP.NET Core.
OpenTelemetry.Instrumentation.Http
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.6.0-rc.1" />
This package provides automatic instrumentation for HTTP clients in .NET applications. It captures telemetry data about outbound HTTP requests, including details such as request and response headers, duration, success status, and more. It’s key for understanding external dependencies and interactions in your application.
Was this page helpful?