← 개발 로그 목록

website: 백엔드 ERROR 로그 알람 런북 섹션 추가

/ 3분 분량 / 개발 로그

기존에 RUNBOOK.md에는 이메일 발송 실패 알람(1-6)에 대한 대응 절차가 이미 있었어서, 새 섹션도 그 형식을 그대로 따라가기로 했다. 경고가 뜬 상황이 뭘 의미하는지, 실제 영향 범위는 어디까지인지, 어떤 명령으로 원인을 확인하고, 어떻게 복구하는지 순서로 구성하는 틀이다. 굳이 새로운 문서 구조를 고민할 필요 없이 이미 검증된 포맷을 재사...

#405에서 만든 ErrorLogCountProd/Stage 알람에 대응 절차 문서가 빠져있어서, 기존 이메일실패 알람 형식에 맞춰 RUNBOOK.md에 추가한 PR이다.

#405에서 push-error-log-metric.py를 만들면서 ErrorLogCountProd/Stage 알람 자체는 이미 완성돼 있었는데, 알람이 울렸을 때 정작 어떻게 대응해야 하는지 적어둔 문서가 없었다. 알람 생성 시 body에 RUNBOOK.md의 특정 앵커(#alarm-error-log)를 참조하도록 설정해뒀기 때문에, 이 문서 작업은 알람보다 먼저 머지가 되어야 알람 body의 링크가 죽은 링크가 되지 않는 상황이었다.

내용을 채우면서 신경 쓴 부분은 "임계치가 왜 0인가"였다. 백엔드에는 GlobalExceptionHandler가 로그인 실패나 존재하지 않는 리소스 같은 흔한 예외 30여 개를 이미 처리하고 있고, 이런 것들은 애초에 ERROR 레벨로 로그를 안 남기게 설계돼 있다. 그래서 ERROR 로그가 한 건이라도 찍혔다는 건 LoggingErrorAttributes가 잡아내는, 말 그대로 예상 못한 버그(NPE, DB 에러 등)나 이메일 발송 실패 케이스라는 뜻이다. 이 배경을 모르고 런북만 보면 "임계치 0은 너무 민감한 거 아닌가" 싶을 수 있어서, 그 이유를 명시적으로 적어뒀다.

대응 절차는 실제 운영 명령 두 줄로 정리했다. 먼저 현재 활성 로그 파일을 찾고(배포 태그별로 파일이 나뉘어 있어서 가장 최근에 수정된 파일을 찾아야 함),

ssh likelion-oci 'ls -t ~/website/infra/logs/<prod|stage>/*.log | head -1'

그다음 그 파일에서 ERROR 줄과 스택트레이스를 확인하는 식이다.

ssh likelion-oci 'grep -A 20 " ERROR " ~/website/infra/logs/<prod|stage>/<파일>.log | tail -60'

여기서 "메일 발송 실패..." 메시지가 나오면 이미 있는 1-6절(이메일 실패 알람) 대응과 같이 봐야 한다는 것도 적었는데, 두 알람이 같은 원인으로 동시에 울릴 수 있는 케이스라 서로 참조하게 만드는 게 나중에 헷갈리지 않을 것 같았다.

복구 부분은 원인에 따라 세 갈래로 나눴다. 진짜 버그면 스택트레이스로 위치 특정해서 수정 배포, 이메일 관련이면 1-6절 참고, 순간적인 DB 락 경합 같은 일회성이면 재발 여부만 지켜보면 된다. 알람 자체는 마지막 ERROR 줄이 5분 쿼리 윈도우 밖으로 밀려나면(최대 5~10분) 자동으로 OK로 전환되니 별도 리셋은 필요 없다는 점도 이메일 알람 문서와 동일하게 명시했다.

곁들여서 .gitignore도 한 줄 손봤다. infra/scripts/에 파이썬 스크립트(push-error-log-metric.py 등)가 생기면서 로컬에서 실행할 때마다 __pycache__/가 생기는 게 눈에 띄어서, 이번 김에 Python 캐시 관련 패턴을 추가했다. 문서 작업 하다가 곁가지로 나온 자잘한 정리라 별도 PR로 쪼개지 않고 같이 묶었다.

머지는 문서 작업이라 오래 걸리지 않았고, PR 생성 후 30초 만에 됐다. 알람 body가 참조하는 앵커가 걸려있는 문서라 순서상 이게 먼저 들어가야 했던 게 이유다.