End-to-end trasování v fintechu: od frontendu po OpenTelemetry Collector
V distribuovaných fintechových systémech nejsou logy bez traceId schopny propojit chybu 500 s konkrétní akcí uživatele. OpenTelemetry umožňuje end-to-end trasování od jednostránkové aplikace (SPA) na frontendu až po backendy prostřednictvím OpenTelemetry Collectoru. Implementace v TypeScriptu s CompositeLoggerem a patchováním fetchu zachovává hierarchii spanů pro podnikové procesy, například převody peněz.
Základní koncepty OpenTelemetry pro frontendové vývojáře
OpenTelemetry standardizuje sběr dat pro observability: traces, spany, události a atributy.
- Trace — kořenová struktura s unikátním traceId pro seskupení spanů.
- Span — časový úsek s časem zahájení a ukončení; podporuje vnořování.
- Událost — časově označená akce s atributy a odkazem na konkrétní span.
- Atribut — dvojice klíč-hodnota pro filtrování a vyhledávání.
Tyto primitivy umožňují postavit hierarchický pohled od kliknutí uživatele až po integrace na backendu.
Architektura systému observability
Frontend odesílá trasy prostřednictvím Audit Microservice do OpenTelemetry Collectoru. Backendy (produktové i platformní) agregují data do Jaegeru (traces), Prometheusu (metriky) a Kibany (logy). Grafana poskytuje vizualizaci.
Výhody této architektury:
- Centrální sběr dat bez přímého přístupu frontendu k platformní infrastruktuře.
- Postupné nasazení po jednotlivých mikroslužbách.
- Obfuskace citlivých dat je povinná.
Implementace na frontendu: rozhraní Logger
Základní abstrakce je rozhraní Logger pro jednotný způsob logování.
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 implementuje vzor Kompozitor (Composite), který předává události více loggerům najedou (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);
}
});
}
}
Integrace s Reactem prostřednictvím kontextu
LoggerProvider a useLogger zajišťují přístup k loggeru v celém stromu komponent.
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 nenalezen v kontextu");
}
return logger;
};
OtlpLogger: patchování fetchu a StackContextManager
OtlpLogger inicializuje WebTracerProvider, patchuje fetch pro zachování rodičovského spanu. StackContextManager řeší problém asynchronních volání v prohlížeči – automaticky přiřazuje dílčí spany k podnikovému procesu bez nutnosti ručního předávání kontextu.
Příklad podnikového procesu „převod peněz“:
startBusinessProcess('money-transfer').addEvent('form-step-1', {amount: 1000}).- Volání
fetchna backend v rámci aktuálního spanu. logErrorpři selhání integrace.
Výhody nasazení
- Snížení MTTR desítkykrát díky filtrování podle traceId.
- Flexibilita: nové loggery lze přidat pomocí npm bez změn v produkčním kódu.
- Strukturovaná data pro korelaci mezi frontendem a backendem.
Vizualizace v Jaegeru ukazuje kompletní cestu: kliknutí → API → Kafka → platformní backend.
Klíčové body
- End-to-end trasování spojuje logy frontendu a backendu pomocí společného
traceId. - CompositeLogger skrývá složitost před vývojáři a podporuje více backendových služeb.
- Patchování fetchu zajišťuje správnou hierarchii spanů i v asynchronních voláních.
- StackContextManager minimalizuje boilerplate pro trasování na straně klienta.
- Obfuskace dat je povinná kvůli dodržování regulací v oblasti fintechu.
— Editorial Team
Zatím žádné komentáře.