Warum Sie gerade heute Ihren Log‑Ansatz über Bord werfen sollten
„Ich schaue einfach in die Log‑Datei, da finden sich alle Probleme.“ – Dieser Satz klingt fast schon wie ein Mantra im IT‑Support, schlägt aber bei genauer Betrachtung ein drückendes Loch in die Service‑Verfügbarkeit. Der Grund? Logs sind ein eindimensionales, nachträgliches Tagebuch. Sie erzählen, was passiert ist, aber nicht warum und wie ein einzelner Request durch das System fließt. In einer Welt, in der Microservices, Container‑Orchestrierung und serverlose Funktionen das Rückgrat moderner Anwendungen bilden, reicht das nicht mehr aus. Heute zeige ich Ihnen, warum ein Observability‑Ansatz – also die Kombination aus Metrics, Logs und Tracing – unverzichtbar ist, und wie Sie mit konkreten Tools und Konfigurationen sofort loslegen können.
1. Grundlagen: Monitoring vs. Observability
Erklärung
Monitoring bezeichnet das Sammeln und Auswerten von Metriken (CPU‑Auslastung, Latenz, Fehlerraten). Es beantwortet Fragen wie „Ist das System gesund?“. Observability geht einen Schritt weiter: Es fragt „Was genau macht das System gerade?“. Das Kernprinzip ist, dass ein System dann beobachtbar ist, wenn man anhand von drei Säulen – Metrics, Logs und Traces – alles notwendige Wissen gewinnen kann, um ein Problem zu verstehen und zu beheben.
Konkretes Beispiel
Nehmen wir einen einfachen HTTP‑Endpoint, der in einem Kubernetes‑Pod läuft. Ohne Tracing sehen Sie in Grafana vielleicht eine steigende Fehlerrate:
# prometheus.yml (Auszug)
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
regex: my‑service
action: keep
Durch das Dashboard erkennen Sie einen Anstieg von http_requests_total{status="500"}. Das ist ein Hinweis, aber nichts, das Ihnen sagt, welcher Service‑Aufruf die Fehler erzeugt.
Persönliche Einschätzung
Ich habe in über 500 Incident‑Reports gesehen, wie schnell Teams im Log‑Dschungel ersticken. Sobald ein Tracing‑Layer hinzugefügt wird, verschwindet das Rätselraten. Man erkennt sofort, welcher Service‑Pfad die Anomalie erzeugt – und das in Sekunden statt Minuten.
2. Beispiel 1 – Loki + Promtail + Grafana: Logs strukturiert erfassen
Erklärung
Loki ist ein log‑zentriertes, skalierbares System von Grafana Labs, das Logs nicht indexiert, sondern über Labels sucht – ähnlich wie Prometheus Metriken. Promtail ist ein Agent, der Log‑Dateien sammelt und an Loki sendet. Der große Vorteil: Logs bleiben im Dateisystem, aber sind zugleich in Grafana quer über Labels auffindbar.
Konkrete Konfiguration
Promtail‑Config (promtail.yaml)
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/**/*.log
Loki‑Compose (docker‑compose.yml)
version: '3.7'
services:
loki:
image: grafana/loki:2.9.1
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:2.9.1
volumes:
- /var/log:/var/log
- /etc/promtail.yaml:/etc/promtail.yaml
command: -config.file=/etc/promtail.yaml
grafana:
image: grafana/grafana:10.2.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
depends_on:
- loki
Nachdem die Container laufen (docker compose up -d), können Sie in Grafana ein Explore‑Panel öffnen, das Labels wie job="varlogs" nutzt, um schnell relevante Logs zu filtern.
Persönliche Einschätzung
Die Kombination aus Loki und Promtail ist für mich das Mikro‑Logging‑Paradigma. Im Vergleich zu traditionellen ELK‑Stacks spart man enorm Ressourcen, weil keine vollständige Indexierung nötig ist. Der Trade‑off: Man verliert die Möglichkeit, Volltext‑Suche über alle Logs hinweg zu betreiben – aber das ist meistens ein kalkulierbarer Preis, wenn man stattdessen gezielte Labels nutzt.
3. Beispiel 2 – Jaeger Tracing in einem Go‑Microservice
Erklärung
Jaeger ist ein Open‑Source‑Distributed‑Tracing‑System, das Spans sammelt und visualisiert. Jeder Span repräsentiert einen einzelnen Schritt eines Requests (z. B. Datenbank‑Aufruf). Durch das Propagation‑Header‑Schema (z. B. traceparent) kann man Requests über mehrere Services hinweg nachverfolgen.
Konkrete Implementierung (Go)
package main
import (
"context"
"log"
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/sdk/trace"
)
func initTracer() func(context.Context) error {
// Jaeger‑Collector läuft auf localhost:14268
exp, err := jaeger.New(jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"))
if err != nil {
log.Fatalf("Jaeger exporter error: %v", err)
}
tp := trace.NewTracerProvider(trace.WithBatcher(exp))
otel.SetTracerProvider(tp)
return tp.Shutdown
}
func handler(w http.ResponseWriter, r *http.Request) {
ctx, span := otel.Tracer("my‑service").Start(r.Context(), "handler")
defer span.End()
// Simulierter DB‑Call
dbCall(ctx)
w.Write([]byte("ok"))
}
func dbCall(ctx context.Context) {
_, span := otel.Tracer("my‑service").Start(ctx, "db‑query")
defer span.End()
// hier würde ein echter DB‑Aufruf stattfinden
}
func main() {
shutdown := initTracer()
defer shutdown(context.Background())
http.HandleFunc("/", handler)
log.Println("Listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Jaeger‑Docker‑Compose
version: '3.7'
services:
jaeger:
image: jaegertracing/all-in-one:1.53
ports:
- "16686:16686" # UI
- "14268:14268" # Collector
Nach Start (docker compose up -d) können Sie im Jaeger‑UI (http://localhost:16686) sehen, wie ein einzelner Request über handler → db‑query spannt.
Persönliche Einschätzung
Der Aufwand, ein paar Zeilen OpenTelemetry‑Code zu schreiben, zahlt sich durch die Visibilität aus, die Sie erhalten. In meinem letzten Projekt haben wir dank Jaeger einen Datenbank‑Deadlock innerhalb von 30 Sekunden isoliert – ein Problem, das mit Log‑Analyse über Stunden hinweg verborgen geblieben wäre.
4. Beispiel 3 – OpenTelemetry Collector als zentraler Hub
Erklärung
Der OpenTelemetry Collector (OTel‑Collector) ist ein universeller Agent, der Logs, Metrics und Traces aus unterschiedlichen Quellen entgegennimmt, transformiert und an verschiedene Backends weiterleitet. Er lässt sich leicht per Docker oder als Daemonset in Kubernetes betreiben.
Konkrete Konfiguration (collector-config.yaml)
receivers:
otlp:
protocols:
grpc:
http:
exporters:
prometheus:
endpoint: "0.0.0.0:9090"
jaeger:
endpoint: "jaeger:14250"
loki:
endpoint: "http://loki:3100/api/prom/push"
service:
pipelines:
traces:
receivers: [otlp]
exporters: [jaeger]
metrics:
receivers: [otlp]
exporters: [prometheus]
logs:
receivers: [otlp]
exporters: [loki]
Docker‑Compose
version: '3.7'
services:
otel-collector:
image: otel/opentelemetry-collector:0.92.0
command: ["--config", "/etc/collector-config.yaml"]
volumes:
- ./collector-config.yaml:/etc/collector-config.yaml
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
jaeger:
image: jaegertracing/all-in-one:1.53
ports:
- "16686:16686"
loki:
image: grafana/loki:2.9.1
ports:
- "3100:3100"
prometheus:
image: prom/prometheus:2.48.0
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
Starten Sie das Stack (docker compose up -d). Jede Anwendung, die OTLP nutzt (z. B. das Go‑Beispiel oben), sendet automatisch Traces, Metrics und Logs an den Collector, der sie weiterleitet.
Persönliche Einschätzung
Der OTel‑Collector ist mein Einheitswerkzeug für Observability. Er reduziert die Komplexität drastisch, weil Sie nur ein einziges Deployment pflegen müssen, das alles nach außen transportiert. Der wichtigste Tipp: Export‑Only‑Pipelines nutzen, um Traffic zu minimieren – kein Service will unnötige Daten ans Netzwerk schicken.
5. Häufige Fehler beim Aufbau eines Observability‑Stacks
- Nur Logs sammeln – Das führt schnell zu Datenflut ohne Kontext. Kombinieren Sie immer mit Metriken und Traces.
-
Unzureichende Label‑Strategie – Ohne konsistente Labels (z. B.
service,environment) wird das Filtern in Loki und Prometheus zu einem Rätsel. - Zu viele Exporter – Jeder Exporter erhöht Netzwerk‑ und CPU‑Last. Beginnen Sie mit einem Ziel (z. B. Grafana Cloud) und erweitern Sie nur bei Bedarf.
- Fehlende Sampling‑Strategie – Traces können bei hohem Traffic explosiv wachsen. Setzen Sie Sampling‑Raten (z. B. 1 % bei Produktions‑Traffic) im Collector.
- Keine Alert‑Definitionen – Beobachtbarkeit ist wertlos, wenn Sie nicht automatisch auf Anomalien reagieren. Definieren Sie Alerts in Prometheus für Latenzspikes, Fehlerraten und ungewöhnliche Log‑Muster.
6. Fazit & konkreter nächster Schritt
Ein reiner Log‑Ansatz ist heute nur noch ein Relikt aus der Ära monolithischer Anwendungen. Durch die Kombination von Metrics, Logs und Tracing erhalten Sie ein vollständiges Bild: Was passiert? (Metrics), Was wurde geschrieben? (Logs) und Wie hat ein Request das System durchlaufen? (Tracing). Der Wechsel kostet initial etwas Aufwand, zahlt sich aber durch schnellere Fehlerdiagnose, geringere MTTR und besseres Ressourcen‑Management aus.
Ihr konkreter nächster Schritt:
- Deployen Sie den OpenTelemetry Collector (Beispiel‑YAML) auf Ihrem ersten Kubernetes‑Cluster.
- Instrumentieren Sie mindestens einen Service mit OpenTelemetry‑SDK (z. B. das Go‑Beispiel).
- Installieren Sie Loki, Jaeger und Grafana via Helm (
helm install loki grafana/loki-stack,helm install jaeger jaegertracing/jaeger). - Erstellen Sie ein Dashboard in Grafana, das Metriken, Logs (via Loki) und Traces (via Jaeger) nebeneinander anzeigt.
- Definieren Sie Ihren ersten Alert in Prometheus (
alert: HighErrorRate ...).
Damit haben Sie ein echtes Observability‑Fundament, das Ihnen morgen schon hilft, die meisten Incidents mit ein paar Klicks zu lösen – statt in Log‑Dateien zu waten.
Top comments (0)