Volver al inicio

Trazado de OpenTelemetry en Fintech desde el Frontend

El artículo describe la implementación de OpenTelemetry para trazado de extremo a extremo en un sistema fintech. Implementación de CompositeLogger en TypeScript con parcheo de fetch e integración con React. Arquitectura con Collector, Jaeger y Prometheus acelera el análisis de incidentes.

Trazado de OpenTelemetry: Experiencia del Equipo de Fintech
Advertisement 728x90

Trazado de extremo a extremo en fintech: desde el frontend hasta el colector de OpenTelemetry

En sistemas fintech distribuidos, los registros sin un traceId no permiten vincular un error 500 con la acción del usuario. OpenTelemetry habilita el trazado de extremo a extremo —desde el frontend de una SPA hasta los servicios backend— mediante el Colector de OpenTelemetry. Nuestra implementación en TypeScript utiliza un CompositeLogger y una versión modificada de fetch para preservar la jerarquía de spans en flujos críticos para el negocio, como las transferencias de dinero.

Conceptos clave de OpenTelemetry para desarrolladores frontend

OpenTelemetry estandariza la recopilación de datos de observabilidad: trazas, spans, eventos y atributos.

  • Traza — la estructura raíz, identificada por un traceId, que agrupa spans relacionados.
  • Span — una operación con marca temporal de inicio y finalización; admite anidamiento para reflejar la jerarquía de llamadas.
  • Evento — una ocurrencia con marca de tiempo vinculada a un span, con atributos personalizables.
  • Atributo — metadatos en formato clave-valor que permiten filtrado, búsqueda y enriquecimiento contextual.

Juntos, estos elementos permiten rastrear un clic del usuario hasta las integraciones backend subyacentes.

Google AdInline article slot

Visión general de la arquitectura de observabilidad

El frontend envía trazas mediante un Microservicio de Auditoría al Colector de OpenTelemetry. Los servicios backend —tanto de equipos de producto como de plataforma— redirigen la telemetría a Jaeger (trazas), Prometheus (métricas) y Kibana (registros). Grafana ofrece paneles unificados.

Ventajas clave de esta arquitectura:

  • Ingesta centralizada: el frontend no accede directamente a la infraestructura interna de observabilidad.
  • Implementación gradual por microservicio, minimizando riesgos.
  • La ofuscación de datos sensibles es obligatoria, no opcional.

Implementación frontend: la interfaz Logger

La abstracción fundamental es una interfaz Logger para garantizar un registro consistente y multiplataforma.

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 implementa el patrón Compuesto, reenviando eventos a múltiples registradores subyacentes (OpenTelemetry, Sentry, Auditoría).

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);
      }
    });
  }
}

Integración con React mediante Context

LoggerProvider y useLogger ofrecen acceso fluido al registrador en todo el árbol de componentes.

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("No se encontró ningún registrador en el contexto");
  }
  return logger;
};

OtlpLogger: modificación de fetch y uso de StackContextManager

OtlpLogger inicializa el WebTracerProvider, modifica fetch para propagar automáticamente los spans padres y aprovecha StackContextManager para resolver la pérdida de contexto asíncrono en navegadores —asegurando que los spans hijos se adjunten correctamente a los procesos comerciales sin necesidad de pasar manualmente el contexto.

Google AdInline article slot

Ejemplo: flujo de transferencia de dinero:

  • startBusinessProcess('transferencia-dinero')
  • addEvent('paso-formulario-1', {monto: 1000})
  • Llamada fetch al backend —hereda automáticamente el contexto del span actual
  • logError ante un fallo de integración, conservando toda la línea de traza

Beneficios de la implementación

  • Reducción del MTTR en 10 veces o más, gracias al filtrado instantáneo basado en traceId en registros frontend y backend.
  • Extensibilidad: nuevos registradores (por ejemplo, Datadog o Honeycomb) se integran vía npm —sin cambios en el código de la aplicación.
  • Correlación estructurada: atributos consistentes permiten emparejar con precisión eventos frontend y backend.

Las visualizaciones en Jaeger muestran el recorrido completo: clic del usuario → llamada API → Kafka → backend de plataforma.

Conclusiones clave

  • El trazado de extremo a extremo une los registros frontend y backend usando el traceId como única fuente de verdad.
  • El CompositeLogger protege a los desarrolladores de la complejidad mientras soporta telemetría multi-destino.
  • La versión modificada de fetch garantiza una jerarquía precisa de spans, incluso en llamadas de red asíncronas.
  • El StackContextManager elimina el código repetitivo necesario para el trazado cliente en frameworks JavaScript modernos.
  • La ofuscación de datos es imprescindible para cumplir con la normativa regulatoria en el sector fintech.

— Editorial Team

Advertisement 728x90

Leer después