시작 절차와 규칙은 CONTRIBUTING.md를 따릅니다. 이 문서는 로그를 어떻게 남기고, 요청을 traceId로 잇는가의 기준입니다. 운영에서 로그를 보는 방법(Grafana·Loki)은 infra/docs/monitoring.md를 따릅니다.
- 로그는 운영에서 문제를 추적하기 위한 것입니다. 로그로 흐름 제어를 하지 않습니다.
- 모든 요청 로그와 오류 응답은 같은
traceId를 공유해 서로 연결됩니다(에러 처리 규약). - 민감정보를 남기지 않습니다 — 비밀번호, 토큰, 인증 헤더, 개인정보, DB 자격증명. 필요하면 마스킹합니다.
- 로그는 표준 출력(stdout) 으로 보냅니다. 파일로 직접 쓰지 않습니다. 컨테이너 로그를 인프라가 수집합니다(infra/backend-conventions).
traceId는 하나의 요청을 응답과 모든 로그에서 잇는 식별자입니다.
- 요청마다 하나를 확보하고, 요청 처리 동안 MDC에 넣어 모든 로그에 자동으로 실리게 합니다.
- 같은 값을 오류 응답 계약의
traceId필드에 사용합니다(에러 처리 규약). - 요청이 끝나면 MDC를 정리해, 재사용되는 스레드에 값이 새지 않게 합니다.
- 외부에서 온 상관관계 ID(
X-Request-Id)가 있으면 검증을 통과한 경우에만 그 값을 씁니다. 없거나 통과하지 못하면 새로 생성합니다.
클라이언트가 보낸 헤더를 그대로 쓰면 그 값이 로그 한 줄에 들어가는 통로가 됩니다. 개행을 섞으면 있지도 않은 로그 줄을 만들어 낼 수 있고(로그 위조), 길이 상한이 없으면 한 요청이 로그를 임의로 부풀립니다. 위의 "민감정보·개행 주입에 주의" 원칙이 적용되는 첫 번째 지점입니다.
global/web/TraceIdFilter가 허용 목록 방식으로 검사합니다.
| 항목 | 값 |
|---|---|
| 허용 문자 | 영숫자와 하이픈([A-Za-z0-9-]) — 제어문자·공백·구분자는 전부 거절 |
| 길이 | 1 ~ TraceIdFilter.MAX_LENGTH(64). UUID(36자)가 들어가는 크기 |
| 판정 | 부분 일치가 아니라 전체 일치. 일부만 맞는 값은 통과하지 못합니다 |
| 실패 시 | 요청을 실패시키지 않고 서버가 만든 UUID로 대체합니다 |
- 거절한 값을 로그에 남기지 않습니다. 남기는 순간 막으려던 주입 경로가 다시 열립니다.
- MDC·응답 헤더·오류 응답의
traceId에는 검증을 통과한 값만 실립니다. 세 곳이 항상 같은 값입니다. - 요청을 400으로 거절하지 않는 이유: 상관관계 ID는 부가 정보이고, 그 값이 이상하다고 정상 요청을 막을 이유가 없습니다.
| 레벨 | 용도 |
|---|---|
ERROR |
처리 실패로 사람이 조치해야 하는 상황. 처리되지 않은 예외, 외부 연동 실패 등 |
WARN |
당장 실패는 아니지만 비정상·주의가 필요한 상황 |
INFO |
운영상 의미 있는 사건(기동, 주요 상태 변화). 요청마다 남기지 않습니다 |
DEBUG |
개발·조사용 상세. 운영 기본 레벨에서는 출력되지 않습니다 |
- 예상된 도메인 오류(검증 실패, 404 등)는
ERROR로 남기지 않습니다. 정상 흐름의 일부입니다. - 처리되지 않은 예외(
500)는ERROR로 원인·스택을 남깁니다. 단, 이 정보는 로그에만 있고 응답 body에는 넣지 않습니다.
- 사람이 아니라 기계와 검색을 위해 남깁니다. 메시지에 안정적인 키워드를 포함해 Loki에서 필터할 수 있게 합니다.
- 예외를 로깅할 때는 예외 객체를 함께 넘겨 스택이 남게 합니다. 문자열로 이어붙이지 않습니다.
- 같은 사건을 여러 계층에서 중복으로 로깅하지 않습니다. 처리 지점에서 한 번 남깁니다.
- 로그 메시지에 사용자 입력을 그대로 넣을 때는 민감정보·개행 주입에 주의합니다.
수집된 로그는 Grafana의 Loki에서 조회합니다(상세는 infra/docs/monitoring.md).
{namespace="pinlog-prod", app="<서비스명>"}
# 에러만
{namespace="pinlog-prod", app="<서비스명>"} |= "ERROR"
- 헬스체크 요청 로그는 인프라에서 걸러집니다. 매 요청
INFO로그로 관측을 오염시키지 않습니다. - 특정 요청을 추적할 때는 응답으로 받은
traceId로 로그를 검색합니다.
- 로깅 자체를 단정하는 테스트는 최소화합니다. 대신 오류 응답의
traceId계약을 테스트해 로그 상관관계의 전제를 지킵니다(에러 처리 규약). - 민감정보가 로그로 나가지 않아야 하는 지점(인증 등)은, 그 값이 응답·로그 경로에 실리지 않는지 검증합니다.
- 요청마다
traceId를 MDC에 넣고 응답 계약과 같은 값을 쓴다 - 요청 종료 시 MDC를 정리한다
- 외부에서 온
traceId는 형식·길이를 검증하고, 통과하지 못하면 새로 생성한다 - 비밀번호·토큰·인증 헤더·개인정보를 로그에 남기지 않는다
- 예상된 도메인 오류를
ERROR로 남기지 않는다 - 예외는 객체로 넘겨 스택을 남기고, 응답 body에는 노출하지 않는다
- 로그는 stdout으로 보낸다