Observability and OpenTelemetry in .NET
Modern applications are no longer simple, single deployments. They are distributed, cloud-native, and composed of multiple services communicating with each other. When something goes wrong, logs alone are no longer enough.
In this article, we’ll explore what observability and OpenTelemetry are, why they matter, and how they integrate naturally into a .NET application.
What is Observability?
Observability is about monitoring how a system performs and understanding why things might go wrong.
It involves collecting and analyzing telemetry, which is data about how an application runs and how different parts of the system interact.
The concept originated in control theory and has since been adapted for software engineering, particularly for complex, distributed systems.
In a distributed system, observability enables you to monitor performance changes and diagnose issues by analyzing key components such as logs, metrics, and traces.
Logs: Detailed records of events, such as incoming requests, errors, or actions (e.g., an order being placed). They are time-stamped and categorized so you can track what happened and when.
Metrics: Provide numerical measures of performance, such as how many requests have been completed, how many users are active, or how long tasks take. It’s a way to see overall performance trends.
Tracing: This lets you follow requests as they pass through different parts of the system.
Together, these tools let you continuously monitor how your system behaves. When something changes, you can quickly identify the root cause and fix it.
What Is OpenTelemetry?
OpenTelemetry (OTel) is an open-source, cross-platform solution for collecting and exporting telemetry data from applications.
The goal of OpenTelemetry is to provide a unified way to collect observability data, so you are not locked into a specific monitoring or APM tool.
This makes observability consistent and portable across systems and platforms.
OpenTelemetry or Prometheus (They’re Not Competitors)
A common misconception is that OpenTelemetry replaces tools like Prometheus. In reality, they solve different parts of the observability problem.
OpenTelemetry focuses on collecting telemetry data (traces, metrics, logs) and describing how data flows through your system. It tracks request flows and bottlenecks.
Prometheus specializes in storing and querying metrics and triggering alerts based on time-series data. It monitors system health and alerts on anomalies.
OpenTelemetry Architecture in .NET
In a .NET application, OpenTelemetry is implemented through NuGet packages grouped into clear responsibilities.
Instrumentation Packages
Instrumentation automatically collects telemetry from common frameworks and libraries without changing your business code, such as:
Exporters
Exporters send collected telemetry to an external system for storage and visualization, such as:
Basic OpenTelemetry Setup in a .NET App
Let’s look at a simple ASP.NET Core example.
Install Required Packages
dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Exporter.Console
Configure OpenTelemetry
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService("MyDotNetService"))
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddConsoleExporter();
});
var app = builder.Build();
app.MapGet("/", () => "Hello OpenTelemetry!");
app.Run();
Now every HTTP request is automatically traced, and spans are exported to the console.
Metrics with OpenTelemetry in .NET
.NET provides Meter and Counter APIs that integrate directly with OpenTelemetry.
using System.Diagnostics.Metrics;
var meter = new Meter("MyApp.Metrics");
var requestCounter = meter.CreateCounter<int>("requests_total");
app.Use(async (context, next) =>
{
requestCounter.Add(1);
await next();
});
More information about different metrics we can define will be explained in future articles.
Ingress and Egress Telemetry Flow
OpenTelemetry uses a pipeline model to process telemetry data.
Ingress
Ingress refers to telemetry entering the pipeline, such as accepted spans and accepted metric points.
Examples:
Received HTTP requests
Collected database spans
Egress
Egress refers to telemetry leaving the pipeline and being sent to exporters.
Examples:
Exported spans
Exported metric points
In future articles I will speak more about traces and metrics in detail, best practices, and how to monitor your solution according to your needs.