본문 바로가기

로그가 ‘쓸모 없어지는’ 이유: 로그 레벨보다 중요한 필드(요청 ID·에러 코드·지연 시간) 설계

📑 목차

    증상 분류: 로그는 있는데 원인을 못 찾는 상황들

    장애가 났는데 로그는 분명히 쌓여 있다.

    그런데도 “무슨 요청이 문제였는지”, “어디서 늦어졌는지”, “같은 오류가 몇 번 반복됐는지”가 잡히지 않는 경우가 많다.

    • 상황 1: 운영에서 오류가 터졌는데, 검색 결과가 너무 많아 관련 로그를 좁히지 못한다
    • 상황 2: 에러 메시지는 보이지만 어떤 입력값과 어떤 흐름에서 발생했는지 연결되지 않는다
    • 상황 3: 느려졌다는 민원이 들어오지만, 지연이 DB인지 외부 API인지 애매하다
    • 상황 4: 같은 오류처럼 보이는데 실제로는 원인이 다른데도 한 덩어리로 뭉개진다
    • 상황 5: 로그 레벨을 조정해도 “찾을 수 없는 로그” 문제는 그대로 남는다

    이런 증상은 대개 레벨 선택이 아니라, 로그 한 줄에 “무엇을 식별하고 무엇을 측정할지”가 빠져서 생긴다.

     

    로그가 ‘쓸모 없어지는’ 이유: 로그 레벨보다 중요한 필드(요청 ID·에러 코드·지연 시간) 설계
    로그가 쓸모 없어지는 대표 패턴과 필요한 필드

     

    원인 후보 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, 에러 코드, 지연 시간이 있는지 확인하고 부족한 필드를 추가해 검증하는 단계형 흐름도이다.
    필드 중심 로그 설계 점검 흐름도

     

    실전 예시: 요청 ID는 있는데도 추적이 끊기는 케이스

    문제: 결제 오류가 간헐적으로 발생해 로그를 확인했지만, request_id로 검색하면 중간 구간부터 로그가 사라진다.

    왜 발생: API 서버에서는 request_id를 찍었지만, 비동기 작업(큐/워커)으로 넘어가는 지점에서 ID가 전달되지 않아 흐름이 끊겼다.

    어떤 선택이 적합: 큐 메시지에 request_id를 포함해 전달하고, 워커에서도 동일한 필드로 로그를 남기는 방식이 맞다.

    잘못 쓰면 어떤 문제: 운영에서는 같은 장애를 매번 “재현 시도”에 의존하게 되고, 장애 대응 시간이 늘어난다.

    확인/해결: 모니터링 도구에서 특정 request_id를 하나 고른 뒤, API 로그 → 큐 발행 로그 → 워커 처리 로그 순으로 검색해 연결이 끊기는 지점을 찾고, 끊긴 구간에 request_id 전달과 로깅을 추가한다.

    단계별 확인 방법: 모니터링 도구에서 바로 따라 하는 절차

    1. 경로: 모니터링/로그 검색 화면 → 최근 오류 이벤트 선택 → 대표 로그 1건 열기
    2. 체크 포인트: 로그에 request_id, error_code, latency_ms가 동시에 있는지 확인한다.
    3. 경로: 로그 검색창 → request_id:값 으로 필터링 → 시간 범위 5~10분으로 축소
    4. 체크 포인트: 같은 request_id로 찍힌 로그가 “서비스 경계/비동기 구간”을 넘어 이어지는지 본다.
    5. 경로: error_code:값 으로 필터링 → 발생 횟수/분포 확인
    6. 체크 포인트: 같은 코드가 특정 경로(route)나 특정 외부 호출에서만 몰리는지 확인한다.
    7. 경로: latency_ms 기준 정렬(내림차순) 또는 임계값 필터 → 느린 요청 상위 N개 확인
    8. 체크 포인트: 느린 요청이 특정 서비스/특정 엔드포인트에 집중되는지 확인한다.
    9. 경로: 배포 이력/릴리스 노트 → 필드 추가 배포 후 동일 조건 재확인
    10. 체크 포인트: 검색·필터·묶기가 실제로 빨라졌는지 운영 시나리오로 검증한다.

    결론

    로그가 쓸모 없어지는 순간은 레벨이 아니라 “연결·분류·시간” 정보가 빠질 때 시작된다.

    request_id는 흐름을 묶고, error_code는 오류를 나누고, latency_ms는 느림을 수치로 만든다.

    운영에서 바로 쓰려면 필드 중심으로 설계하고, 모니터링 도구에서 검색·필터·정렬이 되는지로 검증해야 한다.

    연계 주제 제안: 분산 트레이싱에서 스팬 ID와 요청 ID를 함께 운영하는 방법, 지연 시간 구간 분해(DB/외부 API/큐 대기) 측정 설계가 다음 단계로 이어지기 좋다.

    FAQ

    request_id는 어디에서 만들어야 하나?

    요청이 시스템에 처음 들어오는 지점(게이트웨이 또는 첫 웹 서버)에서 생성하는 방식이 일반적이다.

    중요한 점은 이후 모든 서비스와 비동기 작업까지 같은 값이 전달되도록 규칙을 고정하는 데 있다.

    error_code는 어떤 수준으로 나누는 편이 좋은가?

    운영에서 집계 가능한 수준으로 시작하는 편이 좋다.

    예를 들어 “인증 실패/요청 형식 오류/외부 의존성 실패/DB 처리 실패”처럼 원인 범주가 갈리도록 잡고, 필요할 때만 세분화한다.

    latency_ms는 전체 시간만 남기면 충분한가?

    전체 시간만으로도 느린 요청을 선별하는 데는 도움이 된다.

    다만 병목 위치를 빨리 찾으려면 DB 호출, 외부 API 호출, 큐 대기 같은 구간별 시간도 함께 남기는 편이 유리하다.