Observability in TypeScript: Vom Black-Box-System zur transparenten Architektur
\n\nStellen Sie sich vor, Ihre TypeScript-Anwendung sei ein komplexer Mechanismus aus tausenden Zahnrädern. Alles läuft perfekt – bis etwas kaputt geht. Und dann erhalten Sie die Nachricht: „Die Website ist langsam.“ Wo suchen Sie nach dem Problem? Datenbank? API? Oder ist einfach einer der Microservices ausgefallen?
\n\nOhne Observability (Beobachtbarkeit) werden Sie raten müssen wie ein Schamane mit seiner Rassel. Mit Observability sehen Sie das gesamte Bild: wo die Leistung eingebrochen ist, welche Anfrage den Fehler verursacht hat und warum Speicher ausgelaufen ist.
\n\nIn diesem Artikel werden wir die drei Säulen der Observability – Tracing, Metriken und Logs – behandeln und lernen, wie man sie in TypeScript-Anwendungen anhand realer Beispiele implementiert. Sie erfahren, wie Sie Ihre Anwendung von einer Black Box in ein transparentes System verwandeln, das in Minuten diagnostiziert werden kann.
\n\nWarum Observability für TypeScript-Anwendungen kritisch ist
\n\nTypeScript ist nicht nur ein Aufsatz zu JavaScript. Es ist eine Sprache, in der Backends für hochlastige Systeme, Microservices und sogar CLI-Tools geschrieben werden. Und je komplexer das System, desto wichtiger ist es zu verstehen, was darin passiert.
\n\nTraditionelles Logging ist gut, aber nicht ausreichend. Wenn Sie 50 Microservices haben, werden Logs zu weißem Rauschen. Sie benötigen:
\n\n- \n
- Tracing – um den Weg einer einzelnen Anfrage durch alle Dienste zu verfolgen. \n
- Metriken – um zu sehen, dass der RAM wie Hefeteig wächst. \n
- Strukturierte Logs – um nicht die Nadel im Heuhaufen zu suchen. \n
Lassen Sie uns dies in eine echte Anwendung implementieren.
\n\nTracing in TypeScript: OpenTelemetry in der Praxis
\n\nTracing (Trace-Verfolgung) ist die Lebensgeschichte einer einzelnen Anfrage. Sie sehen, wie viel Zeit jeder Schritt benötigt hat: von der HTTP-Anfrage bis zur Datenbankabfrage. In TypeScript ist OpenTelemetry der De-facto-Standard.
\n\nInstallation und Konfiguration von OpenTelemetry
\n\nnpm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-jaeger\n\nErstellen wir eine Datei tracing.ts zur Initialisierung des Trackings:
import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { JaegerExporter } from '@opentelemetry/exporter-jaeger';\nimport { Resource } from '@opentelemetry/resources';\nimport { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';\n\nconst jaegerExporter = new JaegerExporter({\n endpoint: 'http://localhost:14268/api/traces',\n serviceName: 'my-typescript-app',\n});\n\nconst sdk = new NodeSDK({\n resource: new Resource({\n [SemanticResourceAttributes.SERVICE_NAME]: 'my-typescript-app',\n [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',\n }),\n traceExporter: jaegerExporter,\n instrumentations: [getNodeAutoInstrumentations()],\n});\n\nsdk.start();\n\n\nJede HTTP-Anfrage, jeder Datenbankaufruf wird nun automatisch getraced. Sie sehen in der Jaeger UI (oder Grafana Tempo) die vollständige Aufrufkarte.
\n\nManuelle Erstellung von Spans
\n\nAuto-Instrumentierung ist großartig, aber manchmal müssen Sie eigene Markierungen hinzufügen. Zum Beispiel die Ausführungszeit komplexer Geschäftslogik messen:
\n\nimport { trace } from '@opentelemetry/api';\n\nconst tracer = trace.getTracer('business-logic');\n\nasync function processOrder(orderId: string): Promise<void> {\n const span = tracer.startSpan('process-order', {\n attributes: { 'order.id': orderId },\n });\n\n try {\n // Ihre Auftragsverarbeitungslogik\n await validateOrder(orderId);\n await chargePayment(orderId);\n await sendConfirmation(orderId);\n\n span.setStatus({ code: 1 }); // OK\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus