End-to-End-Tracing im Fintech: Vom Frontend bis zum OpenTelemetry-Collector
In verteilten Fintech-Systemen lassen sich Log-Einträge ohne traceId nicht mit der jeweiligen Nutzeraktion verknüpfen – etwa bei einem 500-Fehler während einer Geldüberweisung. Mit OpenTelemetry lässt sich ein durchgängiges Tracing vom Single-Page-Frontend über alle Backend-Services bis zum OpenTelemetry-Collector realisieren. Unsere TypeScript-Implementierung nutzt einen CompositeLogger und ein angepasstes fetch, um die Span-Hierarchie bei geschäftskritischen Abläufen wie Überweisungen zu bewahren.
Kernkonzepte von OpenTelemetry für Frontend-Entwickler
OpenTelemetry standardisiert die Erfassung von Observability-Daten: Traces, Spans, Events und Attribute.
- Trace — die übergeordnete Struktur, identifiziert durch eine
traceId, die verwandte Spans gruppiert. - Span — eine zeitlich begrenzte Operation mit Start- und Endzeitstempel; unterstützt Verschachtelung zur Darstellung der Aufrufhierarchie.
- Event — ein zeitgestempeltes Ereignis, das einem Span zugeordnet ist und beliebige benutzerdefinierte Attribute enthalten kann.
- Attribute — Schlüssel-Wert-Metadaten, die Filterung, Suche und kontextuelle Anreicherung ermöglichen.
Gemeinsam erlauben diese Bausteine, einen Nutzerklick lückenlos bis zu nachgelagerten Backend-Integrationen nachzuverfolgen.
Übersicht über die Observability-Architektur
Das Frontend sendet Traces über einen Audit-Microservice an den OpenTelemetry-Collector. Backend-Services – sowohl Produkt- als auch Plattformteams – leiten Telemetriedaten an Jaeger (Traces), Prometheus (Metriken) und Kibana (Logs) weiter. Grafana bietet zentrale Dashboards mit integrierter Sicht.
Wesentliche Vorteile dieser Architektur:
- Zentralisierte Datenaufnahme – das Frontend erhält keinen direkten Zugriff auf interne Observability-Infrastruktur.
- Schrittweiser Rollout pro Microservice, um Risiken zu minimieren.
- Die Verdeckung sensibler Daten ist zwingend vorgeschrieben – keine Option, sondern gesetzliche Pflicht.
Frontend-Implementierung: Die Logger-Schnittstelle
Die zentrale Abstraktion ist eine Logger-Schnittstelle für konsistentes, plattformübergreifendes Logging.
export interface Logger {
readonly name: string;
init?(options?: CompositeInitOptions | SentryInitOptions | AuditInitOptions): void;
logError(error: Error, context?: ErrorContextType | ErrorContextType[]): void;
logMessage?(message: string, context?: Record<string, unknown>): void;
}
CompositeLogger implementiert das Composite-Muster und leitet Ereignisse an mehrere zugrundeliegende Logger weiter (OpenTelemetry, Sentry, Audit).
export class CompositeLogger implements Logger {
public readonly name = "composite";
constructor(private readonly loggers: Logger[]) {}
init(options?: CompositeInitOptions): void {
this.loggers.forEach((logger) => {
logger.init?.(options?.[logger.name as keyof CompositeInitOptions]);
});
}
logError(error: Error, context?: ErrorContextType[]): void {
this.loggers.forEach((logger) => {
logger.logError(error, context);
});
}
logMessage(message: string, context?: Record<string, unknown>): void {
this.loggers.forEach((logger) => {
logger.logMessage?.(message, context);
});
}
startBusinessProcess(name: string, attributes?: Attributes): void {
this.loggers.forEach((logger) => {
if (logger.name === "otlp") {
(logger as OtlpLogger).startBusinessProcess(name, attributes);
}
});
}
addEvent(name: string, attributes?: Attributes): void {
this.loggers.forEach((logger) => {
if (logger.name === "otlp") {
(logger as OtlpLogger).addEvent(name, attributes);
}
});
}
}
React-Integration über Context
LoggerProvider und useLogger ermöglichen einen nahtlosen Zugriff auf den Logger innerhalb des gesamten Komponentenbaums.
import React, { createContext, useContext } from "react";
import { CompositeLogger } from "./composite-logger";
const LoggerContext = createContext<CompositeLogger | null>(null);
export const LoggerProvider: React.FC<{
logger: CompositeLogger;
children: React.ReactNode;
}> = ({ logger, children }) => (
<LoggerContext.Provider value={logger}>{children}</LoggerContext.Provider>
);
export const useLogger = (): CompositeLogger => {
const logger = useContext(LoggerContext);
if (!logger) {
throw new Error("Logger nicht im Context gefunden");
}
return logger;
};
OtlpLogger: fetch patchen und StackContextManager nutzen
OtlpLogger initialisiert den WebTracerProvider, patcht fetch, um Eltern-Spans automatisch zu propagieren, und nutzt StackContextManager, um den Verlust des asynchronen Kontexts im Browser zu beheben – sodass Kind-Spans korrekt an Geschäftsprozesse angehängt werden, ohne manuelles Kontext-Passing.
Beispiel: Geldüberweisungs-Flow:
startBusinessProcess('money-transfer')addEvent('form-step-1', {amount: 1000})fetchan das Backend – erbt automatisch den aktuellen Span-KontextlogErrorbei Integrationsfehler, inklusive vollständiger Trace-Herkunft
Vorteile der Implementierung
- MTTR-Reduktion um den Faktor 10 oder mehr, dank sofortiger Filterung nach
traceIdüber Frontend- und Backend-Logs hinweg. - Erweiterbarkeit: Neue Logger (z. B. Datadog, Honeycomb) lassen sich per npm einbinden – ohne Änderung am Anwendungscode.
- Strukturierte Korrelation: Konsistente Attribute ermöglichen präzise Zuordnung von Frontend- zu Backend-Ereignissen.
Jaeger-Visualisierungen zeigen den kompletten Pfad: Nutzerklick → API-Aufruf → Kafka → Plattform-Backend.
Wichtigste Erkenntnisse
- End-to-End-Tracing vereinheitlicht Frontend- und Backend-Logs mithilfe der
traceIdals einzige Quelle der Wahrheit. CompositeLoggerentlastet Entwickler von Komplexität und unterstützt gleichzeitig Telemetrie an mehrere Zielplattformen.- Gepatchtes
fetchgewährleistet eine korrekte Span-Hierarchie – auch bei asynchronen Netzwerkaufrufen. StackContextManagereliminiert Boilerplate für Client-seitiges Tracing in modernen JavaScript-Frameworks.- Datenverdeckung ist unverzichtbar für die regulatorische Compliance im Fintech-Umfeld.
— Editorial Team
Noch keine Kommentare.