Ihre Anwendung läuft, aber sind Sie sicher, dass Sie wissen, was im Inneren passiert?
\n\nStellen Sie sich vor: Sie haben einen Microservice in Go in der Produktion gestartet. Er stürzt nicht ab, liefert keine 500er-Fehler, aber Benutzer beschweren sich, dass die Seite "irgendwie langsam" lädt. Sie schauen ins Monitoring – CPU 30%, Speicher in Ordnung. Was tun? Ohne Observability in Go sind Sie ein Kapitän ohne Karte und Kompass.
\n\nObservability (Beobachtbarkeit) ist nicht nur "Logs". Es sind die drei Säulen: Tracing, Metriken und Logs. Zusammen geben sie Ihnen die Superkraft zu verstehen, was im System passiert, selbst wenn Sie kein Problem erwarten. In diesem Artikel werden wir jeden dieser Aspekte anhand von Codebeispielen in Go durchgehen. Sie lesen nicht nur Theorie – Sie erhalten fertige Rezepte, die Sie noch heute implementieren können.
\n\nWarum Go die ideale Sprache für Observability ist?
\n\nGo wurde für Backend-Systeme entwickelt, bei denen Leistung und Zuverlässigkeit wichtig sind. Die Standardbibliothek (net/http, database/sql) kann bereits Metriken liefern und Kontexte für Tracing unterstützen. Und das Ökosystem OpenTelemetry Go und Prometheus Go macht die Implementierung von Observability einfach und elegant.
Aber das Wichtigste: In Go gibt es keine "Magie". Sie schreiben Code, der ohne Schmerz gemessen, getracet und geloggt werden kann. Lassen Sie uns sehen, wie das gemacht wird.
\n\nTracing in Go: OpenTelemetry in Aktion
\n\nTracing (Trace-Verfolgung) ist die Geschichte einer einzelnen Anfrage vom Eintritt in das System bis zum Austritt. Es zeigt, wie lange jeder Schritt gedauert hat: Datenbankabfrage, Aufruf einer externen API, Datenverarbeitung. In Go basiert Tracing auf Kontexten (context.Context).
Einrichtung des OpenTelemetry SDK
\n\nPakete installieren:
\ngo get go.opentelemetry.io/otel \\\n go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \\\n go.opentelemetry.io/otel/sdk/trace\n\nJetzt den Tracer initialisieren:
\n\npackage main\n\nimport (\n "context"\n "log"\n "go.opentelemetry.io/otel"\n "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"\n "go.opentelemetry.io/otel/sdk/trace"\n)\n\nfunc initTracer() {\n exporter, err := otlptracehttp.New(context.Background())\n if err != nil {\n log.Fatal(err)\n }\n\n tp := trace.NewTracerProvider(\n trace.WithBatcher(exporter),\n trace.WithSampler(trace.AlwaysSample()),\n )\n otel.SetTracerProvider(tp)\n}\n\nErstellen eines Spans im HTTP-Handler
\n\nSo sieht Tracing in echtem Code aus:
\n\nfunc userHandler(w http.ResponseWriter, r *http.Request) {\n tracer := otel.Tracer("user-service")\n ctx, span := tracer.Start(r.Context(), "getUser")\n defer span.End()\n\n // Simulation einer Datenbankabfrage\n user, err := getUserFromDB(ctx, r.URL.Query().Get("id"))\n if err != nil {\n span.RecordError(err)\n span.SetStatus(codes.Error, err.Error())\n http.Error(w, err.Error(), 500)\n return\n }\n\n span.SetAttributes(\n attribute.String("user.id", user.ID),\n attribute.Int64("user.age", int64(user.Age)),\n )\n\n // Verschachtelter Span für externen Aufruf\n _, childSpan := tracer.Start(ctx, "callAnalyticsAPI")\n defer childSpan.End()\n\n callAnalyticsAPI(user)\n \n w.Write([]byte("OK"))\n}\n\nJeder Span enthält Name, Start- und Endzeit, Attribute und Status. In Jaeger oder Grafana Tempo sehen Sie die vollständige Karte der Anfrage.
\n\nPraktischer Tipp
\nVergessen Sie nicht, den Kontext durch die gesamte Anwendung zu reichen. In Go geschieht dies automatisch, wenn Sie context.Context in den Funktionssignaturen verwenden. OpenTelemetry Go übernimmt den Kontext automatisch aus der HTTP-Anfrage, wenn Sie Middleware verwenden.
Metriken: Prometheus und Export in Go
\n\nMetriken sind Zahlen, die den Zustand des Systems anzeigen: RPS, Latenz, Anzahl der Fehler, Aus