📑 목차
증상 분류: 로그는 있는데 원인을 못 찾는 상황들
장애가 났는데 로그는 분명히 쌓여 있다.
그런데도 “무슨 요청이 문제였는지”, “어디서 늦어졌는지”, “같은 오류가 몇 번 반복됐는지”가 잡히지 않는 경우가 많다.
- 상황 1: 운영에서 오류가 터졌는데, 검색 결과가 너무 많아 관련 로그를 좁히지 못한다
- 상황 2: 에러 메시지는 보이지만 어떤 입력값과 어떤 흐름에서 발생했는지 연결되지 않는다
- 상황 3: 느려졌다는 민원이 들어오지만, 지연이 DB인지 외부 API인지 애매하다
- 상황 4: 같은 오류처럼 보이는데 실제로는 원인이 다른데도 한 덩어리로 뭉개진다
- 상황 5: 로그 레벨을 조정해도 “찾을 수 없는 로그” 문제는 그대로 남는다
이런 증상은 대개 레벨 선택이 아니라, 로그 한 줄에 “무엇을 식별하고 무엇을 측정할지”가 빠져서 생긴다.

원인 후보 3가지: 연결 실패, 분류 실패, 시간 정보 부재
로그가 쓸모 없어지는 원인은 단순히 “로그를 적게 남겼다”가 아니다.
대개 아래 세 가지가 겹친다.
원인 후보 1) 요청 단위로 연결할 키가 없다
요청 ID는 한 사용자의 요청이 서비스 내부에서 어떤 흐름을 탔는지 묶어주는 식별자다.
핵심 특징은 로그를 “시간순 나열”이 아니라 “한 요청 묶음”으로 재구성할 수 있다는 점이다.
주의점은 중간 시스템(게이트웨이, 백엔드, 작업 큐)을 거치면서도 같은 ID가 유지되도록 전달 규칙이 필요하다는 점이다.
원인 후보 2) 오류가 ‘문장’으로만 남아 분류가 안 된다
에러 코드는 오류를 분류하기 위한 짧은 규격 값이다.
핵심 특징은 같은 코드끼리 모아서 발생 빈도, 재현 조건, 영향도를 빠르게 파악할 수 있다는 점이다.
주의점은 코드가 너무 세분화되면 운영에서 묶기 어려워지고, 너무 뭉뚱그리면 원인 분리가 안 된다는 점이다.
원인 후보 3) 지연 시간이 없거나 위치가 불명확하다
지연 시간은 요청이 얼마나 걸렸는지 수치로 남기는 필드다.
핵심 특징은 “느리다”를 감정이 아니라 데이터로 바꾸는 데 있다.
주의점은 전체 시간만 찍으면 병목이 어디인지 모호해질 수 있으므로, 구간별 측정(핸들러, DB, 외부 호출 등)과 함께 쓰는 방향이 유리하다는 점이다.
필드 설계 비교표: ‘메시지 중심 로그’ vs ‘필드 중심 로그’
운영에서 로그를 찾는 방식은 보통 “검색 → 필터링 → 묶기 → 비교” 흐름으로 진행된다.
필드가 없으면 검색과 필터링이 막히고, 결국 사람이 눈으로 훑는 작업으로 되돌아간다.
| 구분 | 메시지 중심 로그 | 필드 중심 로그 |
|---|---|---|
| 검색 난이도 | 문장 표현이 달라지면 놓치기 쉽다 | 필드 값으로 안정적으로 필터링된다 |
| 원인 추적 | 요청 흐름 연결이 어려워 시간 소모가 크다 | request_id로 한 요청의 흔적을 묶을 수 있다 |
| 오류 분류 | 같은 오류라도 문장 차이로 뭉개진다 | error_code로 그룹화·집계가 쉽다 |
| 성능 진단 | “느림”이 정량화되지 않는다 | latency_ms로 느린 요청만 골라 볼 수 있다 |
여기서 말하는 필드 중심 로그는 “문장을 버리라”가 아니라, 문장에만 의존하지 말고 필드를 함께 남기라는 뜻이다.
YES/NO 체크리스트: 지금 로그가 운영에 쓸 수 있는지 판단하기
아래 체크리스트는 실제 운영 상황에서 “바로 쓸 수 있는 로그인가”를 빠르게 가르는 용도다.
- YES: 동일한 장애가 발생했을 때 request_id로 관련 로그를 한 묶음으로 바로 모을 수 있다
- YES: error_code 기준으로 발생 횟수와 영향 범위를 집계할 수 있다
- YES: latency_ms로 상위 지연 요청만 뽑아보고, 느린 경로를 특정할 수 있다
- NO: “에러가 났다”는 문장만 있고, 어떤 요청/어떤 사용자/어떤 경로인지 연결이 되지 않는다
- NO: 오류 문구가 상황마다 달라져 검색어가 계속 바뀌고, 누락이 반복된다
- NO: 지연 시간 값이 없어서 “느린 요청”을 필터링할 수 없다
NO가 여러 개라면 레벨 조정보다 필드 보강이 먼저다.

실전 예시: 요청 ID는 있는데도 추적이 끊기는 케이스
문제: 결제 오류가 간헐적으로 발생해 로그를 확인했지만, request_id로 검색하면 중간 구간부터 로그가 사라진다.
왜 발생: API 서버에서는 request_id를 찍었지만, 비동기 작업(큐/워커)으로 넘어가는 지점에서 ID가 전달되지 않아 흐름이 끊겼다.
어떤 선택이 적합: 큐 메시지에 request_id를 포함해 전달하고, 워커에서도 동일한 필드로 로그를 남기는 방식이 맞다.
잘못 쓰면 어떤 문제: 운영에서는 같은 장애를 매번 “재현 시도”에 의존하게 되고, 장애 대응 시간이 늘어난다.
확인/해결: 모니터링 도구에서 특정 request_id를 하나 고른 뒤, API 로그 → 큐 발행 로그 → 워커 처리 로그 순으로 검색해 연결이 끊기는 지점을 찾고, 끊긴 구간에 request_id 전달과 로깅을 추가한다.
단계별 확인 방법: 모니터링 도구에서 바로 따라 하는 절차
- 경로: 모니터링/로그 검색 화면 → 최근 오류 이벤트 선택 → 대표 로그 1건 열기
- 체크 포인트: 로그에 request_id, error_code, latency_ms가 동시에 있는지 확인한다.
- 경로: 로그 검색창 → request_id:값 으로 필터링 → 시간 범위 5~10분으로 축소
- 체크 포인트: 같은 request_id로 찍힌 로그가 “서비스 경계/비동기 구간”을 넘어 이어지는지 본다.
- 경로: error_code:값 으로 필터링 → 발생 횟수/분포 확인
- 체크 포인트: 같은 코드가 특정 경로(route)나 특정 외부 호출에서만 몰리는지 확인한다.
- 경로: latency_ms 기준 정렬(내림차순) 또는 임계값 필터 → 느린 요청 상위 N개 확인
- 체크 포인트: 느린 요청이 특정 서비스/특정 엔드포인트에 집중되는지 확인한다.
- 경로: 배포 이력/릴리스 노트 → 필드 추가 배포 후 동일 조건 재확인
- 체크 포인트: 검색·필터·묶기가 실제로 빨라졌는지 운영 시나리오로 검증한다.
결론
로그가 쓸모 없어지는 순간은 레벨이 아니라 “연결·분류·시간” 정보가 빠질 때 시작된다.
request_id는 흐름을 묶고, error_code는 오류를 나누고, latency_ms는 느림을 수치로 만든다.
운영에서 바로 쓰려면 필드 중심으로 설계하고, 모니터링 도구에서 검색·필터·정렬이 되는지로 검증해야 한다.
연계 주제 제안: 분산 트레이싱에서 스팬 ID와 요청 ID를 함께 운영하는 방법, 지연 시간 구간 분해(DB/외부 API/큐 대기) 측정 설계가 다음 단계로 이어지기 좋다.
FAQ
request_id는 어디에서 만들어야 하나?
요청이 시스템에 처음 들어오는 지점(게이트웨이 또는 첫 웹 서버)에서 생성하는 방식이 일반적이다.
중요한 점은 이후 모든 서비스와 비동기 작업까지 같은 값이 전달되도록 규칙을 고정하는 데 있다.
error_code는 어떤 수준으로 나누는 편이 좋은가?
운영에서 집계 가능한 수준으로 시작하는 편이 좋다.
예를 들어 “인증 실패/요청 형식 오류/외부 의존성 실패/DB 처리 실패”처럼 원인 범주가 갈리도록 잡고, 필요할 때만 세분화한다.
latency_ms는 전체 시간만 남기면 충분한가?
전체 시간만으로도 느린 요청을 선별하는 데는 도움이 된다.
다만 병목 위치를 빨리 찾으려면 DB 호출, 외부 API 호출, 큐 대기 같은 구간별 시간도 함께 남기는 편이 유리하다.
'전산학' 카테고리의 다른 글
| 마이크로서비스 전환이 실패하는 5가지 신호: 분리 기준·공유 DB·배포 복잡도 체크리스트 (0) | 2025.12.29 |
|---|---|
| 캐시가 오히려 느리게 만드는 순간: 캐시 무효화 실패와 ‘오래된 데이터’ 버그를 잡는 흐름 (0) | 2025.12.29 |
| 세션 스토리지와 로컬 스토리지: 전산학 브라우저 안에 데이터를 보관하는 여러 방식 (0) | 2025.12.28 |
| 스로틀링과 서킷 브레이커: 외부 시스템 장애가 내 서비스까지 망치지 않게 막는 기술 (0) | 2025.12.28 |
| 장애 로그에서 원인 찾기: 에러 코드와 스택 트레이스를 읽는 기본 방법 (0) | 2025.12.28 |