Serena MCP is mandatory for C# code. First call
mcp__serena__initial_instructionsto load the Serena tool manual, then use the Serena tools for ALL.csreading / searching / navigation / creation / editing — prefer symbol navigation (get_symbols_overview/find_symbol/find_referencing_symbols) over whole-file reads. NativeEdit/Writeon.csis hook-blocked (the TS/React frontend uses the native tools).
OpenTelemetry for the {{ProductName}} .NET API
Adapted for our stack: OTLP → self-hosted Grafana/Tempo/Loki/Prometheus on your (EU) host — never Azure
Monitor / Application Insights. EF Core on Npgsql (not SqlClient). C# (.cs) edits go through Serena
(native Edit/Write on .cs is blocked). Follows docs/projectStandards/backend-architecture.md and the
backend rules. Every NuGet package below needs Dan's explicit approval before adding — the OTel packages
are the CNCF standard but still dependencies (no library without approval).
1. Packages (flag for approval)
OpenTelemetry.Extensions.Hosting # required for DI integration
OpenTelemetry.Instrumentation.AspNetCore
OpenTelemetry.Instrumentation.Http
OpenTelemetry.Exporter.OpenTelemetryProtocol # OTLP — traces, metrics AND logs through one exporter
OpenTelemetry.Instrumentation.EntityFrameworkCore # NOT .Instrumentation.SqlClient — we're on Npgsql
# OpenTelemetry.Instrumentation.Runtime # optional GC/thread metrics
# OpenTelemetry.Exporter.Console # DEV ONLY — never in production
Do not install OpenTelemetry alone — you need .Extensions.Hosting for DI.
2. Configure all three signals in Program.cs (via Serena)
builder.Services.AddOpenTelemetry() → .ConfigureResource(r => r.AddService("{{ProjectName}}-api")) →
.WithTracing(t => t.AddAspNetCoreInstrumentation(o => o.Filter = ctx => !ctx.Request.Path.StartsWithSegments("/health")).AddHttpClientInstrumentation(o => o.RecordException = true).AddEntityFrameworkCoreInstrumentation().AddSource("{{ProjectName}}.*")).WithMetrics(m => m.AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddMeter("{{ProjectName}}.*")).WithLogging(l => l.IncludeScopes = true).UseOtlpExporter();— readsOTEL_EXPORTER_OTLP_ENDPOINT; point it at our collector. Default gRPC 4317; for HTTP setOtlpExportProtocol.HttpProtobuf(4318). Prometheus OTLP ingestion needs explicit opt-in.
3. Logs correlate automatically
.WithLogging() stamps every log with TraceId/SpanId and propagates the resource — no extra packages.
4. Custom spans
private static readonly ActivitySource ActivitySource = new("{{ProjectName}}.<Feature>");— the source name MUST exactly match anAddSource("{{ProjectName}}.*")filter or spans are silently dropped (the #1 bug).using var activity = ActivitySource.StartActivity("ProcessProject");thenactivity?.SetTag("project.id", id), child spans withActivityKind.Client,activity?.SetStatus(ActivityStatusCode.Error, msg).- Prefer
_logger.LogError(ex, ...)overactivity?.RecordException(ex)(OTel is deprecating span-event exceptions).
5. Custom metrics — via IMeterFactory (DI), not new Meter()
_meter = meterFactory.Create("{{ProjectName}}.<Feature>");thenCreateCounter<long>/CreateHistogram<double>/CreateUpDownCounter<int>; record with aTagListfor dimensions.- The metrics class uses an explicit constructor assigning
readonlyfields (no primary constructors), registeredAddSingleton<…Metrics>().
6. Context propagation across queues/pipeline stages
Automatic over HTTP; for your agentic pipeline / any message hop, Inject/Extract with
Propagators.DefaultTextMapPropagator + PropagationContext/Baggage, then start the downstream activity
with the extracted ActivityContext as parent.
Conventions (ours)
- Naming: ActivitySources and Meters are
{{ProjectName}}.<Feature>(match our namespaces). - Cardinality + tenancy:
tenant_idmay be a span attribute (useful for tracing), but never a metric dimension if tenant count is non-trivial (cardinality blowup). No user IDs / UUIDs / request IDs as metric tags. Be mindful of EU residency — don't ship PII in telemetry attributes. - Pitfalls: null
StartActivity→ source-name mismatch; missing traces → wrong OTLP port/protocol;ActivitySourceis static,Metercomes from the factory.