로그-트레이스 상관관계(Log-Trace Correlation)

[!tldr] 한줄 요약 로그에 dd.trace_iddd.span_id를 주입하여 같은 요청의 로그와 트레이스를 양방향으로 연결하는 메커니즘이며, JSON 로그 + DD_LOGS_INJECTION=true 또는 tracer.get_log_correlation_context()로 설정한다.

핵심 내용

왜 필요한가

분산 시스템에서 장애가 발생하면 로그에서 에러 메시지를, 트레이스에서 요청 흐름을 각각 확인한다. 하지만 둘이 연결되지 않으면 "이 에러가 어떤 요청 흐름에서 발생한 건지" 수동으로 시간대와 서비스를 맞춰 찾아야 한다.

로그-트레이스 상관관계를 설정하면:

sequenceDiagram
    participant App as 애플리케이션
    participant Tracer as dd-trace
    participant Logger as 로깅 프레임워크
    participant Agent as Datadog Agent
    participant DD as Datadog 백엔드

    App->>Tracer: 요청 처리 시작 (Span 생성)
    Tracer->>Logger: trace_id, span_id 주입 (MDC)
    App->>Logger: logger.info("Payment processed")
    Logger->>Agent: JSON 로그 (dd.trace_id 포함)
    Tracer->>Agent: Span 데이터
    Agent->>DD: 로그 + 트레이스 전송
    DD->>DD: dd.trace_id로 로그 ↔ 트레이스 매칭

주입되는 속성 5가지

속성설명예시
dd.trace_id요청 전체를 식별하는 Trace ID"1234567890abcdef"
dd.span_id개별 작업 단위를 식별하는 Span ID"fedcba0987654321"
dd.env환경 (env 태그)"production"
dd.service서비스명 (service 태그)"checkout-api"
dd.version서비스 버전 (version 태그)"1.2.3"

이 5가지가 통합 서비스 태깅과 연결되어 로그, 트레이스, 메트릭을 하나로 묶는 핵심 역할을 한다.

Trace ID 형식

형식길이기본값설정
128-bit (W3C)32자 hexO (ddtrace 2.x~)기본
64-bit (Datadog)16자 hexDD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED=false

128-bit ID의 하위 64-bit에 랜덤값을 넣어 64-bit 라이브러리와의 하위 호환을 유지한다.

설정 방법

방법 1: 자동 주입 (표준 logging 모듈)

DD_LOGS_INJECTION=true 환경변수 하나로 활성화. dd-trace가 로깅 프레임워크의 MDC(Mapped Diagnostic Context)에 자동 주입한다.

import logging
logging.basicConfig(format='%(message)s')
logger = logging.getLogger(__name__)

# ddtrace-run으로 실행하면 자동으로 dd.trace_id 등이 주입됨
# DD_LOGS_INJECTION=true ddtrace-run python app.py

방법 2: 수동 주입 (tracer.get_log_correlation_context())

커스텀 JSON 로깅을 사용할 때 직접 트레이스 컨텍스트를 가져와 머지한다.

from ddtrace import tracer

ctx = tracer.get_log_correlation_context()
# {"dd.trace_id": "...", "dd.span_id": "...", "dd.env": "...", "dd.service": "...", "dd.version": "..."}

log_dict = {"message": "Payment processed", "order_id": 123}
log_dict.update(ctx)
logger.info(json.dumps(log_dict))

JSON vs Plain Text

방식자동 상관관계추가 설정
JSON 로그O (자동)dd.trace_id가 최상위 레벨에 있으면 됨
Plain textXLog Pipeline에서 Grok 파싱 + Trace Remapper 필요

[!warning] JSON이 아니면 자동 인식 불가 [dd.trace_id=abc123]처럼 plain text로 남기면 Datadog이 자동으로 인식하지 못한다. Pipeline에서 Grok Parser로 값을 추출하고 Trace Remapper로 예약 속성에 매핑해야 한다. JSON 출력이 압도적으로 간편하다.

지원 언어별 자동 주입

언어프레임워크주입 방식
JavaLogback, Log4j2, SLF4JMDC 자동 주입
Pythonlogging, loguru, structlogLogRecord/extra 패치
Node.jsWinston, Pino, BunyanJSON 필드 자동 추가
GoLogrus컨텍스트 필드 주입
.NETSerilog, NLog, log4netLogContext 주입
RubyLograge자동 태그 추가
PHPMonolog프로세서로 주입

Loguru에서의 설정

ddtrace는 loguru를 공식 지원한다.

serialize=True 사용 시 (가장 간단):

from loguru import logger
# ddtrace-run으로 실행하면 dd.* 속성이 자동 포함
logger.add("app.log", serialize=True)

커스텀 JSON 로깅 시 (수동 머지):

from ddtrace import tracer

# 기존 JSON 로그 dict에 트레이스 컨텍스트를 머지
log_dict = json.loads(context.json())
log_dict.update(tracer.get_log_correlation_context())
logger.info(json.dumps(log_dict, default=str))

[!tip] loguru 알려진 이슈 ddtrace-run + loguru 조합에서 기본 sink(stderr)에는 dd 속성이 안 붙고, logger.add()새 sink를 추가한 이후부터 정상 동작하는 경우가 있다. (GitHub #7988)

OpenTelemetry 연동

OTel SDK를 사용하는 경우, Logging Bridge가 trace_idspan_id를 자동 캡처한다. Datadog은 dd-trace 형식(dd.trace_id)과 OTel 형식(trace_id) 모두 자동 인식한다.

상관관계가 안 될 때 체크리스트

  1. 로그가 JSON 형식인지 확인
  2. dd.trace_id가 JSON 최상위 레벨에 있는지 확인
  3. Datadog의 Reserved Attributes에서 dd.trace_id가 Trace ID로 매핑되어 있는지 확인 (기본값)
  4. 통합 서비스 태깅 (DD_ENV, DD_SERVICE, DD_VERSION) 환경변수가 설정되어 있는지 확인
  5. 로그와 트레이스가 같은 Datadog 계정으로 수집되는지 확인
  6. 로그의 타임스탬프가 트레이스 시간 범위 내에 있는지 확인

예시

import json
import logging
from ddtrace import tracer

logging.basicConfig(format='%(message)s')
logger = logging.getLogger(__name__)

# 수동 주입 방식: 커스텀 JSON 로깅에 트레이스 컨텍스트 머지
def log_with_trace(message: str, **extra):
    log_dict = {"message": message, **extra}
    log_dict.update(tracer.get_log_correlation_context())
    logger.info(json.dumps(log_dict))

log_with_trace("Payment processed", order_id=123)
# 출력:
# {"message": "Payment processed", "order_id": 123,
#  "dd.trace_id": "1234567890abcdef", "dd.span_id": "fedcba0987654321",
#  "dd.env": "production", "dd.service": "checkout-api", "dd.version": "1.2.3"}

[!example] Datadog UI에서의 연결 Log Explorer에서 위 로그를 클릭하면 "View Trace" 버튼이 나타나고, 해당 요청의 Flame Graph로 바로 이동할 수 있다.

참고 자료

관련 노트