TL;DR — Kurzzusammenfassung
OpenTelemetry vereint Traces, Metriken und Logs neutral. OTel Collector, Auto-Instrumentierung und Grafana-Backends für einheitliches Monitoring meistern.
OpenTelemetry (OTel) ist der quelloffene CNCF-Standard, der die Erfassung von Traces, Metriken und Logs unter einer herstellerneutralen API, einem SDK und einem Netzwerkprotokoll vereint. Vor OTel benötigte jeder Observabilitäts-Anbieter — Datadog, New Relic, Dynatrace, Elastic — seinen eigenen proprietären Agent, was Teams zwang, Code mehrfach zu instrumentieren. OTel bricht diese Abhängigkeit auf: einmal instrumentieren, an beliebige Backends senden. Dieser Leitfaden behandelt die vollständige OTel-Architektur, Collector-Konfiguration, automatische und manuelle Instrumentierung, verteiltes Tracing, Kubernetes-Deployment-Muster und ein praktisches Beispiel mit Node.js + Python-Microservices und Grafana.
Voraussetzungen
- Grundkenntnisse in Docker und Kubernetes (für die Kubernetes-Abschnitte)
- Eine Zielanwendung in Node.js, Python, Java, .NET oder Go
- Docker Compose oder ein Kubernetes-Cluster für das praktische Beispiel
- Grundverständnis von Traces, Metriken und Logs als Konzepte
kubectlkonfiguriert, falls Sie die Kubernetes-Operator-Abschnitte nutzen
OpenTelemetry-Architektur
OTel ist in drei klar getrennte Schichten gegliedert:
API — Sprachspezifische Schnittstellen (z. B. tracer.startSpan()). Dies ist das, was Ihr Anwendungscode aufruft. Die API allein tut nichts; sie benötigt eine SDK-Implementierung, die zur Laufzeit injiziert wird.
SDK — Die Implementierung der API. Das SDK trifft Sampling-Entscheidungen, erkennt Ressourcen (Hostname, k8s-Pod-Name, Cloud-Region) und exportiert Telemetrie via OTLP an ein Backend.
Collector — Eine eigenständige Binärdatei (oder Docker-Container), die als Telemetrie-Pipeline fungiert: empfängt von Apps → verarbeitet → exportiert an Backends.
OTLP (OpenTelemetry Line Protocol) ist das kanonische Netzwerkformat: Protobuf über gRPC (Port 4317) oder HTTP/JSON (Port 4318).
Der OpenTelemetry Collector
Der Collector ist die leistungsstärkste Komponente eines OTel-Produktionsdeployments und funktioniert als Pipeline mit drei Stufen:
Receiver
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"
prometheus:
config:
scrape_configs:
- job_name: "meine-app"
static_configs:
- targets: ["app:8080"]
filelog:
include: ["/var/log/app/*.log"]
operators:
- type: json_parser
hostmetrics:
collection_interval: 30s
scrapers:
cpu: {}
memory: {}
disk: {}
network: {}
Processors
processors:
memory_limiter:
check_interval: 1s
limit_mib: 400
batch:
send_batch_size: 10000
timeout: 10s
attributes:
actions:
- key: environment
value: production
action: insert
filter:
traces:
span:
- 'attributes["http.target"] == "/health"'
tail_sampling:
decision_wait: 10s
policies:
- name: fehler-richtlinie
type: status_code
status_code: {status_codes: [ERROR]}
- name: langsame-traces-richtlinie
type: latency
latency: {threshold_ms: 1000}
- name: probabilistische-richtlinie
type: probabilistic
probabilistic: {sampling_percentage: 10}
tail_sampling läuft im Collector und trifft Entscheidungen, nachdem der vollständige Trace gesehen wurde — erfasst alle Fehler und sampelt nur einen Bruchteil gesunder Traces.
Exporter und Pipelines
exporters:
otlp/tempo:
endpoint: "tempo:4317"
tls:
insecure: true
prometheus:
endpoint: "0.0.0.0:9464"
loki:
endpoint: "http://loki:3100/loki/api/v1/push"
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, tail_sampling]
exporters: [otlp/tempo]
metrics:
receivers: [otlp, prometheus, hostmetrics]
processors: [memory_limiter, batch, attributes]
exporters: [prometheus]
logs:
receivers: [otlp, filelog]
processors: [memory_limiter, batch]
exporters: [loki]
Auto-Instrumentierung
Auto-Instrumentierung fügt OTel hinzu, ohne Anwendungscode zu ändern, und fängt HTTP-, Datenbank- und Messaging-Aufrufe automatisch ab.
Java — Führen Sie den OTel Java Agent als JVM-Flag aus:
java -javaagent:/otel-javaagent.jar \
-Dotel.service.name=mein-service \
-Dotel.exporter.otlp.endpoint=http://collector:4317 \
-jar meine-app.jar
Python — Verwenden Sie opentelemetry-instrument:
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap --action=install
opentelemetry-instrument \
--service_name mein-service \
--exporter_otlp_endpoint http://collector:4317 \
python app.py
Node.js — Importieren Sie das SDK vor jedem Anwendungscode:
// tracing.js — muss zuerst via --require geladen werden
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const sdk = new NodeSDK({
serviceName: 'mein-node-service',
traceExporter: new OTLPTraceExporter({ url: 'http://collector:4317' }),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
Manuelle Instrumentierung
Spans erstellen
const opentelemetry = require('@opentelemetry/api');
const tracer = opentelemetry.trace.getTracer('mein-service', '1.0.0');
async function bestellungVerarbeiten(bestellungId) {
return tracer.startActiveSpan('bestellungVerarbeiten', async (span) => {
try {
span.setAttribute('bestellung.id', bestellungId);
const ergebnis = await zahlungAusfuehren(bestellungId);
span.addEvent('zahlung.ausgefuehrt', { 'zahlung.betrag': ergebnis.betrag });
return ergebnis;
} catch (err) {
span.recordException(err);
span.setStatus({ code: opentelemetry.SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
});
}
Metriken erstellen
const meter = opentelemetry.metrics.getMeter('mein-service', '1.0.0');
const anfragenZaehler = meter.createCounter('http.server.requests');
const latenzHistogramm = meter.createHistogram('http.server.duration', { unit: 'ms' });
const aktiveVerbindungen = meter.createUpDownCounter('db.connections.active');
meter.createObservableGauge('process.memory.usage').addCallback((result) => {
result.observe(process.memoryUsage().heapUsed);
});
Verteiltes Tracing
Ein Trace ist ein gerichteter azyklischer Graph von Spans, der eine Ende-zu-Ende-Anfrage durch Ihr System darstellt. Jeder Span hat: TraceId, SpanId, ParentSpanId, SpanKind, Attribute, Events und Status.
Kopfbasiertes Sampling — entscheidet am Root-Span, einfach aber kann keine langsamen oder fehlerhaften Traces bevorzugen. Schwanzbasiertes Sampling — erfasst zuerst den vollständigen Trace und entscheidet dann, ob er behalten wird — erfasst 100% der Fehler und sampelt nur 10% des gesunden Traffics.
Exemplare verknüpfen Prometheus-Histogramm-Beobachtungen mit spezifischen Tempo-TraceIds, ermöglichen Einzel-Klick-Navigation von einem P99-Latenzspike direkt zu einem repräsentativen Trace.
Kubernetes mit dem OTel Operator
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: otel-instrumentierung
spec:
exporter:
endpoint: http://otel-agent:4317
propagators: [tracecontext, baggage]
sampler:
type: parentbased_traceidratio
argument: "0.1"
nodejs:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:latest
python:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:latest
Annotieren Sie ein Deployment, um den Node.js Agent automatisch zu injizieren:
annotations:
instrumentation.opentelemetry.io/inject-nodejs: "true"
Backends und Vergleich
| Backend | Signale | Speicherung |
|---|---|---|
| Jaeger | Nur Traces | Cassandra/Elasticsearch |
| Prometheus | Nur Metriken | Lokales TSDB |
| Grafana Loki | Nur Logs | Objektspeicher |
| Grafana Tempo | Nur Traces | Objektspeicher |
| SigNoz | Traces + Metriken + Logs | ClickHouse |
| Plattform | Vendor Lock-in | Kostenmodell |
|---|---|---|
| OpenTelemetry + Grafana | Keiner | Kostenlos (selbst gehostet) |
| Datadog | Hoch | Pro Host + Aufnahme |
| New Relic | Mittel | Pro GB aufgenommen |
| Dynatrace | Sehr hoch | Pro Host-Einheit |
| Elastic APM | Mittel | Pro GB |
Praktisches Beispiel: Node.js + Python mit Grafana Stack
Eine Zwei-Dienste-Konfiguration: ein Node.js API-Gateway ruft einen Python-Bestelldienst auf. Alle Telemetrie fließt durch einen einzelnen Collector zu Tempo, Prometheus und Loki, visualisiert in Grafana.
services:
collector:
image: otel/opentelemetry-collector-contrib:latest
volumes:
- ./collector-config.yaml:/etc/otel/config.yaml
ports: ["4317:4317", "4318:4318", "9464:9464"]
node-api:
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317
- OTEL_SERVICE_NAME=node-api
python-bestellungen:
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317
- OTEL_SERVICE_NAME=python-bestellungen
In Grafana: Explore öffnen → Tempo → nach service.name=node-api suchen → auf einen Trace klicken → Exemplar-Link verwenden, um die korrelierte Prometheus P95-Metrik zu sehen → Loki-Link anklicken, um die exakte Log-Zeile dieser Anfrage zu sehen.
Fallstricke und Sonderfälle
Uhrendrift — Verteilte Traces sind auf synchronisierte Uhren angewiesen. NTP-Drift über 1ms verursacht Span-Reihenfolgeprobleme in der UI. Verwenden Sie chrony oder cloud-native Zeitsynchronisierung.
Tail Sampling erfordert TraceId-konsistentes Routing — Wenn Sie mehrere Collector-Gateway-Replicas mit tail_sampling betreiben, müssen alle Spans desselben Trace an dieselbe Instanz gelangen. Verwenden Sie den loadbalancing-Exporter mit routing_key: traceId.
Kardinalitätsexplosion — Verwenden Sie niemals hochkardinalige Werte (Benutzer-IDs, Bestell-IDs) als Metrik-Label-Werte. OTel-Attribute auf Spans sind bei jeder Kardinalität sicher; Metrik-Dimensionen nicht.
SDK-Initialisierungsreihenfolge — In Node.js muss das SDK start() abgeschlossen sein, bevor ein instrumentiertes Modul per require() geladen wird. Verwenden Sie --require zum Laden der Tracing-Datei.
Zusammenfassung
- OpenTelemetry bietet eine einzige, herstellerneutrale API, ein SDK und ein Netzwerkprotokoll (OTLP) für Traces, Metriken und Logs
- Der OTel Collector entkoppelt Anwendungen von Backends; verwenden Sie Agents (DaemonSet), die ein Gateway (Deployment) mit Tail Sampling in der Produktion speisen
- Auto-Instrumentierung fügt Traces ohne Codeänderungen hinzu; manuelle Instrumentierung fügt Geschäftskontext mit
startActiveSpanundcreateCounter/createHistogramhinzu - Exemplare verknüpfen Prometheus-Metrik-Beobachtungen mit Tempo-TraceIds für Einzel-Klick-Drill-Down
- Der Grafana Stack (Tempo + Prometheus + Loki + Grafana) ist die beliebteste Open-Source-OTel-Backend-Kombination