Zpět na domů

OpenTelemetry trasování ve fintechu od frontendu

Článek popisuje zavádění OpenTelemetry pro skrzové trasování ve fintech systému. Implementace CompositeLogger v TypeScript s patchingem fetch a React integrací. Architektura s Collector, Jaeger a Prometheus urychluje analýzu incidentů.

Trasování OpenTelemetry: zkušenosti fintech týmu
Advertisement 728x90

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.

Google AdInline article slot

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í.

Google AdInline article slot
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.

Google AdInline article slot

Příklad podnikového procesu „převod peněz“:

  • startBusinessProcess('money-transfer').
  • addEvent('form-step-1', {amount: 1000}).
  • Volání fetch na backend v rámci aktuálního spanu.
  • logError př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

Advertisement 728x90

Číst dál