Expert guidance for configuring and deploying the OpenTelemetry Collector. Use when setting up a Collector pipeline, configuring receivers, exporters, or processors, deploying a Collector to Kubernetes or Docker, or forwarding telemetry to Dash0. Triggers on requests involving collector, pipeline, OTLP receiver, exporter, or Dash0 collector setup.
95
93%
Does it follow best practices?
Impact
96%
1.39xAverage score across 12 eval scenarios
Advisory
Suggest reviewing before use
Expert guidance for implementing high-quality, cost-efficient OpenTelemetry telemetry.
| Use Case / Rule | Description |
|---|---|
| telemetry | Entrypoint — signal types, correlation, and navigation |
| resolve-values | Resolving configuration values from the codebase |
| resources | Resource attributes — service identity and environment |
| k8s | Kubernetes deployment — downward API, pod spec |
| spans | Spans — naming, kind, status, and hygiene |
| logs | Logs — structured logging, severity, trace correlation |
| metrics | Metrics — instrument types, naming, units, cardinality |
| sensitive-data | Sensitive data — PII prevention, sanitization, redaction |
| capture-database-query-parameters | Prepared-statement parameter capture per language (Java, .NET, Python, Node.js, Go) |
| validation | Telemetry validation — post-deployment verification checklist |
| nodejs | Node.js instrumentation setup |
| go | Go instrumentation setup |
| python | Python instrumentation setup |
| java | Java instrumentation setup |
| scala | Scala instrumentation setup |
| dotnet | .NET instrumentation setup |
| ruby | Ruby instrumentation setup |
| php | PHP instrumentation setup |
| browser | Browser instrumentation setup |
| nextjs | Next.js full-stack instrumentation (App Router) |
Follow these steps when instrumenting an application from scratch:
The snippet below shows a complete span with attributes and status for Node.js — see nodejs for full setup including SDK initialisation, exporter configuration, and auto-instrumentation:
import { trace, SpanStatusCode } from '@opentelemetry/api';
const tracer = trace.getTracer('my-service', '1.0.0');
tracer.startActiveSpan('operation-name', async (span) => {
try {
span.setAttribute('user.id', userId);
span.setAttribute('order.id', orderId);
const result = await processOrder(orderId);
span.setAttribute('order.status', result.status);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (err) {
// Record the exception as a structured log record, not span.recordException — see rules/spans.md
span.setStatus({ code: SpanStatusCode.ERROR, message: `${err.name}: ${err.message}` });
const spanContext = span.spanContext();
logger.error('operation-name.failed', {
'trace_id': spanContext.traceId,
'span_id': spanContext.spanId,
'exception.type': err.name,
'exception.message': err.message,
'exception.stacktrace': err.stack,
});
throw err;
} finally {
span.end();
}
});Every telemetry item should serve one of three purposes:
If it doesn't serve one of these purposes, don't emit it.
Use the AlwaysOn sampler (the default) in every SDK.
Do not configure SDK-side samplers — they make irreversible decisions before the outcome of a request is known.
Defer all sampling to the Collector, where policies can be changed centrally without redeploying applications.
SDK (AlwaysOn) → Collector (sampling) → Backend (retention)
↓ ↓ ↓
All spans Head or tail Storage policies
exported sampling applied