홈으로 돌아가기

프론트엔드에서 본 핀테크 OpenTelemetry 추적

이 기사는 핀테크 시스템에서 엔드투엔드 추적을 위한 OpenTelemetry 구현을 설명합니다. fetch 패칭과 React 통합을 포함한 TypeScript CompositeLogger 구현. Collector, Jaeger, Prometheus 아키텍처가 인시던트 분석을 가속화합니다.

OpenTelemetry 추적: 핀테크 팀 경험
Advertisement 728x90

핀테크에서의 엔드투엔드 추적: 프론트엔드부터 OpenTelemetry 컬렉터까지

분산형 핀테크 시스템에서는 traceId가 없는 로그로는 사용자의 액션과 연관된 500 에러를 정확히 추적할 수 없습니다. OpenTelemetry는 SPA 프론트엔드에서 백엔드 서비스까지 이어지는 엔드투엔드 추적을 OpenTelemetry 컬렉터를 통해 실현합니다. 당사의 TypeScript 구현은 CompositeLogger와 패치된 fetch API를 활용해 송금 등 비즈니스 핵심 흐름에서 스팬 계층 구조를 정확히 유지합니다.

프론트엔드 개발자를 위한 핵심 OpenTelemetry 개념

OpenTelemetry는 추적(Traces), 스팬(Spans), 이벤트(Events), 속성(Attributes) 등 관측 가능성을 위한 데이터 수집을 표준화합니다.

  • Trace(추적) — traceId로 식별되는 최상위 구조로, 관련된 여러 스팬을 그룹화하는 데 사용됩니다.
  • Span(스팬) — 시작 및 종료 타임스탬프를 갖는 시간 기반 작업으로, 호출 계층을 반영하기 위해 중첩이 가능합니다.
  • Event(이벤트) — 특정 스팬에 연결된 타임스탬프 기반 발생 사항으로, 사용자 정의 속성을 포함할 수 있습니다.
  • Attribute(속성) — 필터링, 검색, 맥락 강화를 위한 키-값 형태의 메타데이터입니다.

이러한 기본 요소들을 조합하면, 사용자의 클릭 하나가 하위 백엔드 연동까지 전 과정을 추적할 수 있습니다.

Google AdInline article slot

관측 가능성 아키텍처 개요

프론트엔드는 감사용 마이크로서비스(Audit Microservice)를 거쳐 OpenTelemetry 컬렉터로 추적 데이터를 전송합니다. 백엔드 서비스(제품 및 플랫폼 팀 모두)는 Jaeger(추적), Prometheus(지표), Kibana(로그)로 텔레메트리를 라우팅하며, Grafana에서 통합 대시보드를 제공합니다.

이 아키텍처의 주요 장점:

  • 중앙 집중식 수집: 프론트엔드가 내부 관측 인프라에 직접 접근하지 않음.
  • 마이크로서비스 단위 점진적 도입: 리스크 최소화.
  • 민감 정보 익명화는 의무사항이며 선택 사항이 아님.

프론트엔드 구현: 로거 인터페이스

일관된 크로스플랫폼 로깅을 위한 핵심 추상화는 Logger 인터페이스입니다.

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는 컴포지트 패턴을 적용해 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 통합: Context 활용

LoggerProvideruseLogger 훅을 통해 컴포넌트 트리 전체에서 로거에 간편하게 접근할 수 있습니다.

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("컨텍스트 내에서 로거를 찾을 수 없습니다");
  }
  return logger;
};

OtlpLogger: fetch 패치 및 StackContextManager 활용

OtlpLoggerWebTracerProvider를 초기화하고, 부모 스팬을 자동으로 전파하도록 fetch를 패치합니다. 또한 브라우저 환경에서 발생하는 비동기 컨텍스트 소실 문제를 해결하기 위해 StackContextManager를 활용해, 별도의 수동 컨텍스트 전달 없이도 자식 스팬이 비즈니스 프로세스에 정확히 연결되도록 보장합니다.

Google AdInline article slot

예시: 송금 흐름

  • startBusinessProcess('money-transfer')
  • addEvent('form-step-1', {amount: 1000})
  • 백엔드로의 fetch 호출 — 현재 스팬 컨텍스트를 자동 상속
  • 연동 실패 시 logError 호출 — 전체 추적 계층 구조 유지

구현 효과

  • MTTR(평균 복구 시간) 10배 이상 단축: 프론트엔드와 백엔드 로그를 traceId 기반으로 즉시 필터링 가능.
  • 확장성: Datadog, Honeycomb 등 신규 로거는 npm 설치만으로 바로 연동 가능 — 애플리케이션 코드 변경 불필요.
  • 구조화된 상관관계: 일관된 속성 정의로 프론트엔드-백엔드 이벤트 정확 매칭 가능.

Jaeger 시각화를 통해 사용자 클릭 → API 호출 → Kafka → 플랫폼 백엔드까지 완전한 경로를 확인할 수 있습니다.

핵심 요약

  • 엔드투엔드 추적traceId를 단일 진실의 원천으로 삼아 프론트엔드와 백엔드 로그를 통합합니다.
  • CompositeLogger는 복잡성을 숨기면서도 다중 목적지 텔레메트리 지원을 가능하게 합니다.
  • 패치된 fetch는 비동기 네트워크 호출에서도 정확한 스팬 계층 구조를 보장합니다.
  • StackContextManager는 현대 자바스크립트 프레임워크에서 클라이언트 측 추적을 위한 번거로운 부가 코드를 제거합니다.
  • 데이터 익명화는 핀테크 분야의 규제 준수를 위해 반드시 이행해야 하는 사항입니다.

— Editorial Team

Advertisement 728x90

다음 읽기