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
  • kubectl konfiguriert, 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

BackendSignaleSpeicherung
JaegerNur TracesCassandra/Elasticsearch
PrometheusNur MetrikenLokales TSDB
Grafana LokiNur LogsObjektspeicher
Grafana TempoNur TracesObjektspeicher
SigNozTraces + Metriken + LogsClickHouse
PlattformVendor Lock-inKostenmodell
OpenTelemetry + GrafanaKeinerKostenlos (selbst gehostet)
DatadogHochPro Host + Aufnahme
New RelicMittelPro GB aufgenommen
DynatraceSehr hochPro Host-Einheit
Elastic APMMittelPro 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 startActiveSpan und createCounter/createHistogram hinzu
  • 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

Verwandte Artikel