Modern applications generate thousands of requests every minute. Without proper monitoring, identifying performance bottlenecks, failed dependencies, or resource exhaustion becomes difficult. Traditional logging helps explain what happened, but it doesn't provide a real-time view of application health.

OpenTelemetry has become the standard for collecting telemetry across applications. It enables developers to capture metrics, traces, and logs using a vendor-neutral API that integrates with popular observability platforms.

In this article, you'll learn how to implement production-ready OpenTelemetry metrics in a .NET 11 application, expose metrics for monitoring, create custom application metrics, and follow best practices for production deployments.

Note: This article focuses on implementation. Dashboard configurations, alert thresholds, and performance measurements should be validated within your own monitoring environment.

What Are OpenTelemetry Metrics?

Metrics are numerical measurements collected over time that describe the health and performance of an application.

Examples include:

Unlike logs, metrics are lightweight and ideal for continuous monitoring.

Why Use OpenTelemetry?

OpenTelemetry provides a consistent way to collect telemetry regardless of the monitoring platform.

Benefits include:

Project Setup

Create a new Web API.

dotnet new webapi -n OpenTelemetryMetricsDemo

Install the required packages.

dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

Depending on your monitoring stack, you may also install exporters such as Prometheus or Azure Monitor.

Configure OpenTelemetry

Register OpenTelemetry during application startup.

using OpenTelemetry.Metrics;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenTelemetry()
    .WithMetrics(metrics =>
    {
        metrics
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddRuntimeInstrumentation()
            .AddMeter("ProductApi")
            .AddOtlpExporter();
    });

var app = builder.Build();

app.Run();

Why This Configuration?

Each component serves a specific purpose:

Creating Custom Metrics

Business metrics are often more valuable than infrastructure metrics.

Create a custom meter.

using System.Diagnostics.Metrics;

public static class MetricsRegistry
{
    public static readonly Meter Meter =
        new("ProductApi");

    public static readonly Counter<int> OrdersCreated =
        Meter.CreateCounter<int>("orders.created");
}

Increment the counter whenever an order is created.

public async Task CreateOrderAsync(Order order)
{
    // Save order

    MetricsRegistry.OrdersCreated.Add(1);

    await Task.CompletedTask;
}

This metric can later be visualized on dashboards to monitor application activity.

Measuring Request Duration

Histograms are useful for recording durations.

public static readonly Histogram<double> ProcessingTime =
    MetricsRegistry.Meter.CreateHistogram<double>(
        "order.processing.time",
        unit: "ms");

Record elapsed time.

var stopwatch = Stopwatch.StartNew();

// Business logic

stopwatch.Stop();

MetricsRegistry.ProcessingTime.Record(
    stopwatch.Elapsed.TotalMilliseconds);

Histograms allow monitoring platforms to calculate averages, percentiles, and latency distributions.

Recording Active Users

Observable gauges report values collected during metric scraping.

public static int ActiveUsers;

MetricsRegistry.Meter.CreateObservableGauge(
    "users.active",
    () => ActiveUsers);

The monitoring system reads the latest value whenever metrics are collected.

End-to-End Flow

A typical request follows this sequence:

  1. Client sends an HTTP request.

  2. ASP.NET Core instrumentation records request metrics.

  3. Business logic updates custom counters and histograms.

  4. Runtime instrumentation collects memory and thread metrics.

  5. Metrics are exported through the configured OTLP exporter.

  6. Dashboards visualize the collected data.

This provides a complete view of both application and infrastructure health.

Useful Metrics to Collect

CategoryExample Metrics
HTTPRequest count, duration, status codes
RuntimeGC collections, memory usage, thread pool
DatabaseQuery duration, failed queries
CacheHit ratio, misses
BusinessOrders, registrations, payments
External APIsLatency, failures

Collecting both technical and business metrics provides better operational visibility.

Exporting Metrics

OpenTelemetry supports multiple exporters.

ExporterTypical Use Case
OTLPOpenTelemetry Collector
PrometheusPrometheus + Grafana
Azure MonitorAzure-hosted applications
JaegerPrimarily tracing
ConsoleLocal development

Choose the exporter that aligns with your observability platform.

Production Considerations

Minimize Metric Cardinality

Avoid labels with highly variable values.

Avoid:

userId = 123456

Prefer:

region = us-east

High-cardinality labels increase storage requirements and reduce query performance.

Record Meaningful Metrics

Not every event needs to become a metric.

Focus on metrics that help answer operational questions such as:

Keep Metric Names Consistent

Use a clear naming convention.

Examples:

orders.created
orders.failed
orders.processing.time

Consistent names improve dashboard readability and simplify alert configuration.

Monitoring Methodology

The research brief does not include dashboard screenshots, alert thresholds, or production measurements. To evaluate your monitoring implementation:

Test Environment

Keep the following consistent:

Simulate Traffic

Generate realistic workloads using tools such as:

Exercise both successful and failing requests.

Validate Metrics

Verify that dashboards correctly display:

Also ensure metrics remain accurate under sustained load.

Best Practices

Common Mistakes

MistakeImpact
Recording too many metricsIncreased storage costs
High-cardinality labelsPoor query performance
Ignoring runtime metricsMissed infrastructure issues
Inconsistent metric namesConfusing dashboards
Collecting metrics without alertsDelayed issue detection
Exposing sensitive data in labelsSecurity risks

Troubleshooting

Metrics Are Not Appearing

Verify:

Custom Metrics Are Missing

Ensure:

High Resource Usage

Review:

Reducing unnecessary metrics can improve performance.

FAQs

What is OpenTelemetry?

OpenTelemetry is an open standard for collecting metrics, traces, and logs across applications and services.

What is the difference between metrics and logs?

Metrics provide aggregated numerical measurements over time, while logs capture detailed event information for troubleshooting.

Should I collect every possible metric?

No. Focus on metrics that provide operational value and support monitoring, troubleshooting, and business insights.

Can I create my own metrics?

Yes. OpenTelemetry allows custom counters, histograms, gauges, and other metric instruments using the Meter API.

Do I need Prometheus?

No. OpenTelemetry supports multiple exporters. Prometheus is one popular option, but you can export metrics to any compatible observability platform.

Conclusion

OpenTelemetry provides a standardized and extensible way to monitor .NET applications through metrics. By combining built-in ASP.NET Core instrumentation with custom business metrics, developers gain valuable insights into application performance, reliability, and usage patterns.

A production-ready monitoring strategy goes beyond collecting infrastructure data. It includes meaningful business metrics, consistent naming, controlled metric cardinality, and integration with dashboards and alerting systems. Validate your telemetry pipeline under production-like workloads to ensure it delivers accurate and actionable insights when they matter most.