[CNCF Observability 01] OpenTelemetry: Metrics, Logs, Traces를 같은 요청으로 연결하기

이재인·2026년 10월 10일

CNCF

목록 보기
20/24
post-thumbnail

시바 일러스트

주문 화면에서 결제가 오래 걸린다고 가정해 보겠습니다. 먼저 요청 시간이 늘어난 구간을 찾고, 그때 발생한 사건과 실제 처리 순서를 확인하고 싶습니다. 이 글에서는 세 가지 기록의 역할과 서로 연결할 때 필요한 값을 알아봅니다.

기록마다 답하는 질문

OpenTelemetry는 프로그램의 활동을 나타내는 데이터를 수집하고 처리해 다른 시스템으로 보내는 도구와 규약의 모음입니다. Observability는 이런 기록을 통해 시스템 내부에서 일어난 일을 살펴보는 일입니다.

Metrics는 실행 중 측정한 숫자입니다. 예를 들어 1분 동안 발생한 결제 오류 수를 기록합니다. Logs는 특정 시점에 발생한 사건의 기록입니다. 결제 응답 시간 초과라는 메시지에 시간과 서비스 이름을 붙일 수 있습니다. Traces는 요청이 프로그램을 통과한 경로입니다. 주문 서비스가 결제 서비스를 호출한 순서를 따라갑니다. 각각의 역할은 OpenTelemetry Signals 문서에서 확인할 수 있습니다.

서비스 이름과 요청 번호

Resource는 데이터를 만든 대상을 설명하는 정보입니다. service.name=checkout은 주문 서비스를 가리킵니다. 여러 기록에 같은 서비스 이름을 붙이면 어느 서비스에서 발생했는지 모아서 살펴볼 수 있습니다. 이 이름은 초기 설정에서 명시하는 것이 권장됩니다. Resource 문서가 그 설정을 설명합니다.

서비스 하나는 여러 요청을 처리합니다. 그중 특정 요청을 연결하려면 Trace ID라는 경로 식별자가 필요합니다. Span은 시작과 끝이 있는 한 작업이며, Span ID는 그 작업의 식별자입니다. 요청 처리 중 남긴 Log에 두 식별자가 들어 있으면 Trace의 해당 작업으로 찾아갈 수 있습니다. Log의 두 필드는 선택 사항입니다. 기록을 만드는 시점에 요청 정보가 연결되어 있어야 합니다. Logs 데이터 모델은 이 조건을 명시합니다.

Resource: service.name = checkout
  ├─ Metrics: 1분 동안의 오류 수
  ├─ Log: payment timeout + Trace ID
  └─ Span: payment 작업 + Trace ID

Log의 Trace ID = Span의 Trace ID
  ↓
같은 요청의 기록으로 연결

Metrics의 합계에는 여러 요청이 들어갈 수 있습니다.

같은 주문 서비스의 세 기록을 모으고, Log와 Span의 Trace ID로 특정 요청을 연결합니다.

Metrics의 오류 수는 여러 요청을 합친 숫자일 수 있습니다. 서비스 이름만으로 특정 주문을 정할 수 있는 범위는 제한됩니다. 요청 단위 이동에는 Trace ID가 붙은 기록이나 별도로 구성한 연결 정보가 필요합니다.

가상의 조사 순서를 따라가 보겠습니다. 주문 서비스의 오류 수가 늘어난 분을 먼저 고릅니다. 이어서 같은 서비스와 시간 구간의 Log를 찾습니다. 그중 결제 시간 초과 메시지에 Trace ID가 있으면 같은 식별자의 Trace를 엽니다. 이제 결제 작업이 요청 경로의 어느 위치에 있는지 살펴볼 수 있습니다. 이 순서는 저장 시스템에서 필요한 필드를 검색할 수 있다고 가정한 예입니다.

기록을 연결해 읽으면 질문도 구체적으로 바뀝니다. 숫자에서는 오류가 언제 늘었는지 묻습니다. 사건 기록에서는 어떤 메시지가 남았는지 확인합니다. 요청 경로에서는 어떤 작업을 거쳤는지 따라갑니다. 각 답을 함께 놓고 확인할 다음 작업을 정할 수 있습니다.

같은 Trace ID를 찾아보기

아래 Python 코드는 직접 만든 기록 두 개에서 같은 식별자를 찾습니다. trace_id는 설명용 JSON 키입니다. OpenTelemetry 전송 형식과 저장 시스템의 필드 이름은 사용하는 구성에 따라 확인해야 합니다.

trace_id = "0123456789abcdef0123456789abcdef"
span = {"trace_id": trace_id, "name": "payment"}
logs = [
    {"trace_id": trace_id, "message": "payment timeout"},
    {"trace_id": "fedcba9876543210fedcba9876543210", "message": "order completed"},
]
matches = [x["message"] for x in logs if x["trace_id"] == span["trace_id"]]
print(matches)

실행 결과는 ['payment timeout']입니다. 첫 기록의 식별자가 Span과 같아서 선택됩니다. 두 번째 기록은 다른 요청의 식별자를 가지고 있습니다. Python 3.13.13에서 실행했으며, 데이터 연결 원리를 표현한 합성 예제입니다. OpenTelemetry 수집기를 실행한 결과는 별도 환경에서 확인해야 합니다.

확인 문제와 정답

  1. 1분 동안의 오류 수를 표현하는 기록은 무엇인가요?
  2. 같은 서비스에서 발생한 Log 두 개가 한 요청에 속하는지 무엇으로 확인하나요?
  3. 위 코드의 첫 Log에서 trace_id를 제거하면 무엇을 점검해야 하나요?

정답: 1은 Metrics입니다. 2는 요청을 가리키는 Trace ID입니다. 3은 Log 생성 시점에 요청 정보가 연결되는지, 저장 과정에서 필드가 유지되는지 확인해야 합니다. Resource의 서비스 이름은 데이터를 만든 대상을 알려 줍니다.

지금은 세 기록이 답하는 질문을 한 문장씩 적어 보세요. 다음 날에는 Log를 한 개 추가하고 같은 요청만 찾아보세요. 일주일 뒤에는 계획 주제인 Jaeger에서 Span의 부모 관계 읽기와 연결해 한 요청의 순서를 그려 보세요. 이 일정은 복습 제안입니다.

문서 확인일은 2026-10-09입니다. OpenTelemetry의 현행 개념 문서와 Logs 규격을 기준으로 설명했습니다.

profile
게으르게 일하기 위해 진지하게 고민하는 개발자

0개의 댓글