Introduction
As applications become increasingly distributed, monitoring them using only log files is no longer sufficient. Modern cloud-native applications often consist of multiple APIs, background services, message brokers, databases, and external dependencies. When something goes wrong, developers need visibility into the entire request lifecycle—not just isolated log entries.
This is where observability comes in. Observability enables teams to understand system behavior by collecting logs, metrics, and distributed traces. In the .NET ecosystem, OpenTelemetry has become the standard for collecting telemetry, while Prometheus stores metrics and Grafana provides powerful dashboards for visualization.
In this article, you'll learn how to implement observability in .NET 10 applications and prepare them for production monitoring.
What Is Observability?
Observability is the ability to understand the internal state of an application by analyzing its outputs.
Modern observability consists of three pillars:
| Pillar | Purpose |
|---|---|
| Logs | Record application events and errors |
| Metrics | Measure application health and performance |
| Traces | Track requests across distributed services |
Together, these provide a complete picture of application behavior.
Why OpenTelemetry?
OpenTelemetry is an open standard for collecting telemetry data across different programming languages and platforms.
Key benefits include:
Vendor-neutral instrumentation
Distributed tracing
Automatic telemetry collection
Standardized APIs
Integration with popular monitoring platforms
Support for cloud-native applications
Rather than locking applications into a specific monitoring vendor, OpenTelemetry allows telemetry to be exported to multiple backends.
Typical Architecture
A production monitoring solution often includes the following components:
| Component | Responsibility |
|---|---|
| ASP.NET Core Application | Generates telemetry |
| OpenTelemetry | Collects logs, metrics, and traces |
| Prometheus | Stores metrics |
| Grafana | Visualizes dashboards |
| Jaeger or Azure Monitor | Stores distributed traces |
This architecture enables developers to identify performance issues quickly across distributed systems.
Configuring OpenTelemetry
Install the required NuGet packages.
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore
Register OpenTelemetry during application startup.
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation();
metrics.AddHttpClientInstrumentation();
metrics.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation();
tracing.AddHttpClientInstrumentation();
});
This automatically captures telemetry from ASP.NET Core requests, outgoing HTTP calls, and runtime metrics without requiring manual instrumentation.
Exposing Metrics
Expose Prometheus metrics through an endpoint.
app.MapPrometheusScrapingEndpoint();
Prometheus periodically scrapes this endpoint to collect application metrics.
What Should You Monitor?
Meaningful metrics provide better operational insight than collecting everything indiscriminately.
Recommended metrics include:
HTTP request count
Request duration
Error rate
CPU utilization
Memory usage
Thread pool usage
Database query duration
External API latency
Monitoring these metrics helps identify issues before they affect users.
Distributed Tracing
Distributed tracing follows a request as it travels through multiple services.
For example:
API Gateway receives a request.
Order Service processes the request.
Payment Service validates payment.
Inventory Service reserves stock.
Notification Service sends confirmation.
A single trace connects every step, making it much easier to identify bottlenecks.
Production Considerations
Dependency Injection
Register OpenTelemetry through ASP.NET Core's dependency injection container.
This centralizes telemetry configuration and ensures consistent instrumentation across your application.
Configuration
Store telemetry settings in appsettings.json.
{
"OpenTelemetry": {
"ServiceName": "ProductApi"
}
}
Override environment-specific values using environment variables or your deployment platform.
Logging
Logs remain an important part of observability.
Log:
Application startup
Unhandled exceptions
Authentication failures
Business events
Dependency failures
Retry operations
Use structured logging to make log searching and correlation easier.
Error Handling
Monitor application failures such as:
HTTP 5xx responses
Database connection failures
Timeout exceptions
External API errors
Message processing failures
Combining logs with traces significantly reduces troubleshooting time.
Security
Observability data may contain sensitive information.
Protect it by:
Avoiding sensitive data in logs.
Masking personally identifiable information (PII).
Encrypting telemetry during transmission.
Restricting dashboard access.
Applying role-based authorization.
Defining log retention policies.
Only collect the information required for diagnostics.
Performance
Telemetry collection introduces some overhead, so configure it carefully.
Optimize by:
Sampling traces in production.
Logging meaningful events only.
Avoiding excessive custom metrics.
Exporting telemetry asynchronously.
Monitoring storage consumption.
The goal is actionable insight, not excessive telemetry volume.
Observability in Distributed Systems
When working with microservices, monitor:
Service dependencies
Queue processing time
Database latency
API gateway performance
Container health
Service availability
Correlating telemetry across services helps identify failures that would otherwise be difficult to diagnose.
Deployment
Observability should be configured as part of every deployment.
A typical production deployment includes:
OpenTelemetry instrumentation
Prometheus metrics collection
Grafana dashboards
Centralized log aggregation
Health checks
Alerting rules
Monitoring should be operational before users begin using the application.
Best Practices
Instrument applications early in development.
Use structured logging.
Monitor business metrics as well as technical metrics.
Create dashboards for critical services.
Configure alerts for production issues.
Correlate logs, metrics, and traces.
Regularly review telemetry data to identify optimization opportunities.
Common Mistakes
Avoid these common pitfalls:
Logging excessive information.
Ignoring distributed tracing.
Creating dashboards without actionable metrics.
Collecting telemetry without alerts.
Exposing sensitive information in logs.
Waiting for production incidents before implementing monitoring.
Observability should be an integral part of application design rather than an afterthought.
Troubleshooting
| Problem | Solution |
|---|---|
| Metrics are not appearing | Verify Prometheus is scraping the correct endpoint and OpenTelemetry is configured correctly. |
| Missing traces | Check instrumentation, exporters, and sampling configuration. |
| Dashboards show incomplete data | Confirm Prometheus targets are healthy and telemetry exporters are running. |
| High telemetry storage usage | Reduce log verbosity, enable trace sampling, and remove unnecessary metrics. |
| Difficult root-cause analysis | Correlate logs, metrics, and traces using shared trace identifiers. |
Conclusion
Observability is essential for operating modern .NET applications reliably at scale. By combining OpenTelemetry for instrumentation, Prometheus for metrics collection, and Grafana for visualization, developers gain comprehensive insight into application health, performance, and reliability.
Implementing observability from the beginning of a project makes it easier to diagnose production issues, optimize performance, and maintain high availability. Rather than reacting to failures after users report them, teams can detect, investigate, and resolve problems proactively using a unified view of logs, metrics, and distributed traces.

Jasen FiciPosted Aug 12, 2026, 1:11 PM
Thanks for sharing this. We featured it in DotNetNews here: https://dotnetnews.co/archive/the-net-news-daily-issue-517/