---
name: net-observability
description: Implement observability patterns with OpenTelemetry, structured logging, and distributed tracing
license: MIT
compatibility: opencode
metadata:
audience: .net-developers
framework: aspnetcore
patterns: opentelemetry, serilog, metrics
---
## What I Do
I help you implement enterprise observability patterns:
- Structured logging with Serilog
- Distributed tracing with OpenTelemetry
- Metrics collection with Prometheus
- Health checks for Kubernetes
- Correlation IDs for request tracking
- Application Performance Monitoring (APM)
## When to Use Me
Use this skill when:
- Setting up logging infrastructure
- Implementing distributed tracing
- Adding metrics and monitoring
- Configuring health checks
- Preparing for production deployment
## Packages Required
```xml
```
## Serilog Configuration
### Program.cs Setup
```csharp
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Configure Serilog
builder.Host.UseSerilog((context, loggerConfiguration) =>
{
loggerConfiguration
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithEnvironmentName()
.Enrich.WithThreadId()
.Enrich.WithProperty("Application", "YourAppName")
.WriteTo.Console(
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {CorrelationId} {Message:lj} {Properties:j}{NewLine}{Exception}")
.WriteTo.Seq("http://localhost:5341"); // Optional: Seq server
});
```
### appsettings.json
```json
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
}
}
]
}
}
```
## OpenTelemetry Configuration
### Distributed Tracing Setup
```csharp
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using OpenTelemetry.Metrics;
builder.Services.AddOpenTelemetry()
.ConfigureResource(resource => resource
.AddService(serviceName: "YourServiceName", serviceVersion: "1.0.0"))
.WithTracing(tracing => tracing
.AddSource("YourServiceName")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddEntityFrameworkCoreInstrumentation()
.AddJaegerExporter(options =>
{
options.AgentHost = "localhost";
options.AgentPort = 6831;
}))
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddPrometheusExporter());
```
## Correlation ID Middleware
```csharp
public class CorrelationIdMiddleware
{
private const string CorrelationIdHeader = "X-Correlation-Id";
private readonly RequestDelegate _next;
public CorrelationIdMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var correlationId = context.Request.Headers[CorrelationIdHeader].FirstOrDefault()
?? Guid.NewGuid().ToString();
context.Items["CorrelationId"] = correlationId;
context.Response.Headers[CorrelationIdHeader] = correlationId;
using (LogContext.PushProperty("CorrelationId", correlationId))
{
await _next(context);
}
}
}
```
## Health Checks
```csharp
builder.Services.AddHealthChecks()
.AddNpgSql(connectionString, name: "database", tags: new[] { "ready" })
.AddRedis(redisConnectionString, name: "redis", tags: new[] { "ready" })
.AddCheck("self", () => HealthCheckResult.Healthy(), tags: new[] { "live" });
// Map endpoints
app.MapHealthChecks("/health");
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("ready")
});
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("live")
});
```
## Custom Metrics
```csharp
using System.Diagnostics.Metrics;
public class ApplicationMetrics
{
private readonly Counter _requestCounter;
private readonly Histogram _requestDuration;
public ApplicationMetrics(IMeterFactory meterFactory)
{
var meter = meterFactory.Create("YourApp.Metrics");
_requestCounter = meter.CreateCounter(
"app.requests.total",
description: "Total number of requests");
_requestDuration = meter.CreateHistogram(
"app.requests.duration",
unit: "ms",
description: "Request duration in milliseconds");
}
public void RecordRequest(string endpoint, long durationMs)
{
_requestCounter.Add(1, new KeyValuePair("endpoint", endpoint));
_requestDuration.Record(durationMs, new KeyValuePair("endpoint", endpoint));
}
}
```
## Best Practices
1. **Structured Logging**: Always use structured logging with properties
2. **Correlation IDs**: Propagate correlation IDs across services
3. **Log Levels**: Use appropriate log levels (Debug, Information, Warning, Error, Critical)
4. **Sensitive Data**: Never log sensitive data (passwords, tokens, PII)
5. **Performance**: Be mindful of logging overhead in hot paths
6. **Health Checks**: Implement both liveness and readiness probes
7. **Metrics**: Track business and technical metrics separately
## Example Usage
```
Use net-observability skill to:
1. Set up Serilog with structured logging
2. Add OpenTelemetry distributed tracing
3. Configure Prometheus metrics
4. Implement health checks for Kubernetes
5. Add correlation ID tracking
```
I will generate complete observability infrastructure following .NET 8 best practices.