Claude Code & OpenTelemetry: Observability und Tracing professionell einrichten

Eine App, die läuft, ist gut. Eine App, bei der du weißt warum sie läuft — und sofort siehst, wenn etwas nicht mehr rund läuft — ist besser. Observability ist der Unterschied zwischen Raten und Wissen. OpenTelemetry (kurz OTel) ist heute der Standard dafür: ein vendor-neutrales SDK für Traces, Metrics und Logs, das in jede Infrastruktur passt.

Das Problem: OTel-Setup ist repetitiv. Dieselben Pakete installieren, dieselben Exporter konfigurieren, dieselbe Boilerplate für jeden Service. Claude Code beschleunigt genau diesen Teil erheblich — nicht weil es die Konzepte vereinfacht, sondern weil es den gesamten Kontext deines Projekts sieht und die Konfiguration passend dazu erzeugt.

Claude Code Mastery — Observability, Agents, Hooks auf Deutsch

Nicht nur OTel: der Kurs zeigt, wie du Claude Code wirklich produktiv einsetzt — für professionelle Entwicklungsabläufe, autonome Agents und skalierbare Workflows. Einmalig bezahlt, kein Abo.

Zum Kurs — Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht

1. Warum Observability kein Nice-to-have ist

Distributed Systems scheitern auf Arten, die kein einzelner Log und kein einzelner Fehler sichtbar macht. Ein Request geht durch API Gateway, Auth-Service, User-Service und Datenbank — und irgendwo auf dem Weg wird er 300 ms langsamer als gestern. Ohne Tracing weißt du nicht wo. Mit Logs weißt du, dass etwas passiert ist. Mit Distributed Tracing siehst du genau welcher Span in welchem Service die Latenz verursacht.

Die drei Säulen moderner Observability:

OpenTelemetry liefert das SDK für alle drei — und bleibt dabei vom Backend unabhängig. Ob Jaeger, Tempo, Datadog oder Honeycomb: das SDK bleibt gleich, nur der Exporter wechselt.

2. OTel SDK Setup: Node.js

Für eine Node.js-App (Express, Fastify, NestJS) beginnt das Setup mit den Core-Paketen:

npm install @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/exporter-metrics-otlp-http

Die Instrumentation-Datei muss vor dem eigentlichen App-Code geladen werden:

// instrumentation.ts
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';

const sdk = new NodeSDK({
  serviceName: 'my-service',
  traceExporter: new OTLPTraceExporter({
    url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + '/v1/traces',
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + '/v1/metrics',
    }),
    exportIntervalMillis: 10000,
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

In package.json das Flag setzen, damit instrumentation.ts als erstes lädt:

"scripts": {
  "start": "node --require ./dist/instrumentation.js dist/index.js"
}

Claude Code-Tipp: Statt die Paketnamen aus dem Gedächtnis zu tippen, übergib Claude Code dein bestehendes package.json und frage nach dem vollständigen OTel-Setup passend zu deinem Framework. Es erkennt, ob du Express, Fastify oder NestJS nutzt, und schlägt die richtigen Instrumentations-Pakete vor.

3. OTel SDK Setup: Python

Für Python-Apps (FastAPI, Django, Flask) ist das Zero-Code-Instrumentation-Modell besonders praktisch:

pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install

opentelemetry-bootstrap scannt die installierten Pakete und installiert automatisch die passenden Instrumentations-Bibliotheken — für FastAPI, SQLAlchemy, httpx und andere.

Für manuelles Setup oder wenn du mehr Kontrolle willst:

# tracing.py
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource

resource = Resource(attributes={
    SERVICE_NAME: "my-python-service"
})

provider = TracerProvider(resource=resource)
exporter = OTLPSpanExporter(
    endpoint=f"{os.environ['OTEL_EXPORTER_OTLP_ENDPOINT']}/v1/traces"
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

4. Traces, Spans und Attribute

Auto-Instrumentierung erfasst HTTP-Requests und DB-Queries automatisch. Für eigene Businesslogik brauchst du manuelle Spans:

// Node.js
import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('order-service');

async function processOrder(orderId: string) {
  return tracer.startActiveSpan('processOrder', async (span) => {
    span.setAttribute('order.id', orderId);
    span.setAttribute('order.source', 'api');

    try {
      const result = await db.orders.findById(orderId);
      span.setAttribute('order.status', result.status);
      return result;
    } catch (err) {
      span.recordException(err as Error);
      span.setStatus({ code: SpanStatusCode.ERROR });
      throw err;
    } finally {
      span.end();
    }
  });
}

Gute Span-Attribute sind der Schlüssel zu nützlichem Tracing: Nutzer-ID, Tenant, Feature-Flag-Wert, Datenbankname — alles, wonach du später filtern willst. Claude Code hilft dabei, die sinnvollen Attribute für deine Domain zu identifizieren, wenn du es nach einem Review deines Domainmodells fragst.

5. Metrics: Counter und Histogramm

Metrics sind die aggregierten Zahlen, die du in Dashboards und Alerts brauchst. Die wichtigsten Typen:

// Node.js
import { metrics } from '@opentelemetry/api';

const meter = metrics.getMeter('order-service');

// Counter: monoton steigend (Requests, Errors, Events)
const requestCounter = meter.createCounter('http.requests.total', {
  description: 'Total number of HTTP requests',
});

// Histogram: Verteilung über Zeit (Latenz, Response-Size)
const latencyHistogram = meter.createHistogram('http.request.duration', {
  description: 'HTTP request duration in milliseconds',
  unit: 'ms',
  advice: { explicitBucketBoundaries: [5, 10, 25, 50, 100, 250, 500, 1000] },
});

// In der Request-Middleware:
requestCounter.add(1, { method: req.method, route: req.route?.path });
latencyHistogram.record(durationMs, { method: req.method, status: res.statusCode });

Hinweis zu Bucket-Grenzen: Die Standard-Bucket-Grenzen des OTel-SDK passen selten zu deiner App. Definiere sie explizit basierend auf deinen P50/P95/P99-Werten. Claude Code kann diese Grenzen vorschlagen, wenn du ihm deine historischen Latenzdaten zeigst.

6. Logs mit OpenTelemetry

OTel-Logs sind der neueste der drei Pfeiler — und der, der am meisten Mehrwert bringt wenn er mit Traces verknüpft ist. Ein Log-Eintrag mit der Trace-ID des zugehörigen Requests macht Debugging dramatisch einfacher.

// Node.js mit Winston + OTel Log Bridge
import { logs } from '@opentelemetry/api-logs';
import { SeverityNumber } from '@opentelemetry/api-logs';

const logger = logs.getLogger('order-service');

function logOrderEvent(orderId: string, event: string, traceId?: string) {
  logger.emit({
    severityNumber: SeverityNumber.INFO,
    severityText: 'INFO',
    body: `Order event: ${event}`,
    attributes: {
      'order.id': orderId,
      'event.type': event,
    },
  });
}

In der Praxis nutzen die meisten Teams ihre bestehende Logging-Library (Winston, Pino, structlog) und bridgen sie über den OTel Log Bridge API — so bleibt die bestehende Log-Infrastruktur erhalten und die Trace-IDs werden automatisch injiziert.

7. Jaeger und Tempo als Backend

Für lokale Entwicklung ist Jaeger die einfachste Option — ein einzelner Docker-Container:

docker run -d --name jaeger \
  -p 16686:16686 \
  -p 4318:4318 \
  jaegertracing/all-in-one:latest

Die Traces sind danach unter http://localhost:16686 sichtbar. Der OTLP-Endpoint für deine App: http://localhost:4318.

Für Produktions-Setups mit Grafana-Stack ist Tempo die bessere Wahl: native Integration mit Grafana, günstige Speicherung in Object Storage, und direkte Verknüpfung mit Loki (Logs) und Prometheus (Metrics) über Exemplars.

8. Auto-Instrumentierung richtig nutzen

Die Auto-Instrumentierungen für Node.js erfassen ohne weiteren Code:

Nicht alles davon ist sinnvoll in jedem Projekt. Claude Code kann gezielt helfen: zeig ihm deine package.json und frag, welche Auto-Instrumentation-Pakete für dein Stack relevant sind — und welche weggelassen werden können, um Overhead zu reduzieren.

9. Custom Exporter für spezielle Backends

Wenn dein Backend kein OTLP spricht (Legacy-System, proprietäres Monitoring), kannst du einen eigenen Exporter implementieren:

// Node.js Custom SpanExporter
import { SpanExporter, ReadableSpan } from '@opentelemetry/sdk-trace-base';
import { ExportResult, ExportResultCode } from '@opentelemetry/core';

class CustomExporter implements SpanExporter {
  export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {
    for (const span of spans) {
      // Spans in dein Format transformieren und senden
      this.sendToLegacySystem({
        traceId: span.spanContext().traceId,
        spanId: span.spanContext().spanId,
        name: span.name,
        duration: span.duration[0] * 1000 + span.duration[1] / 1e6,
        attributes: span.attributes,
      });
    }
    resultCallback({ code: ExportResultCode.SUCCESS });
  }

  shutdown(): Promise<void> {
    return Promise.resolve();
  }

  private sendToLegacySystem(data: Record<string, unknown>): void {
    // Implementierung spezifisch für dein Backend
  }
}

10. Grafana-Integration

Grafana ist das De-facto-Standard-Dashboard für OTel-Daten. Mit dem Grafana-Stack aus Tempo (Traces), Loki (Logs) und Prometheus/Mimir (Metrics) bekommst du Correlated Observability: du klickst in Grafana auf eine Trace, siehst direkt die zugehörigen Logs und Metrics im selben Zeitfenster.

Die minimale docker-compose.yml für lokale Entwicklung:

version: '3.8'
services:
  tempo:
    image: grafana/tempo:latest
    command: ["-config.file=/etc/tempo.yaml"]
    volumes:
      - ./tempo.yaml:/etc/tempo.yaml
    ports:
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
    volumes:
      - ./grafana/datasources:/etc/grafana/provisioning/datasources

Claude Code kann die komplette Konfiguration — tempo.yaml, Grafana-Datasource-YAML, Prometheus-Scrape-Config — für dein spezifisches Setup generieren. Es braucht dazu nur deinen Stack und die Service-Namen.


Zwei verwandte Artikel die auf diesem Thema aufbauen:


Claude Code Mastery — von OTel-Setup bis zum produktiven Agenten

Observability ist eine Stärke von Claude Code — aber nicht die einzige. Im Kurs lernst du Agents, MCP-Server, Hooks, Multi-Agent-Workflows und mehr. Vollständig auf Deutsch, einmalig bezahlt.

Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht

Kurs · Claude Code Mastery

Von Observability zum produktiven AI-Agenten

OTel. Debugging. Agents. MCP. Hooks. Multi-Agent-Workflows. Alles auf Deutsch, einmalig bezahlt — kein Abo, keine Plattformabhängigkeit.

Jetzt einsteigen → Kursübersicht ansehen →

Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht