소프트웨어는 거짓말할 수 없는 일기를 써요. 일이 일어나는 순간 바로 한 줄을 추가하고, 절대 되돌아가 고치지 않기 때문이에요. 그 일기가 로그입니다.
멈추지 않는 영수증 프린터를 상상해 보세요. 긴 테이프를 바닥에 쏟아내면서, 무언가 일어날 때마다 정확한 시각을 찍어 한 줄씩 인쇄해요. 요약하지 않고, 정리하지 않고, 무엇이 중요한지 판단하지도 않아요. 그냥 순서대로 기록할 뿐이에요. 요청이 들어왔다, 결제가 이루어졌다, 바로 여기서 오류가 발생했다, 완료됐다. 하나의 사건, 한 줄, 영원히.
그것이 로그예요. 프로그램이 실제로 한 일을 타임스탬프와 함께, 순서대로, 추가 전용으로 기록한 것이에요. '추가 전용(append-only)'이 핵심입니다. 새 줄은 항상 맨 아래에만 추가되고, 이미 쓰인 내용은 절대 바뀌지 않아요. 이 점이 로그를 수정 없는 증인으로 만들어 줘요. 나중에 기억을 더듬어 쓴 이야기가 아니라, 현장에서 실시간으로 기록된 일기예요. 무언가 망가졌을 때 믿을 수 있는 건 이 생중계 기록이에요. 몰래 지워질 수 없었으니까요.
실제로 어떻게 쓰냐고요. 문제가 생겼을 때 추측하며 앉아 있지 않아도 돼요. 테이프를 문제가 발생한 시점까지 스크롤하면 소프트웨어가 그때 무엇을 하고 있었는지 읽을 수 있어요. 디버깅의 절반은 그거예요. 로그에서 그 순간을 찾아내고, 모든 게 틀어지기 직전의 줄을 읽는 거예요.
연결해두면 기억하기 쉬운 개념 두 가지:
- 트레이스는 요청 하나가 여러 처리 단계를 거친 전체 여정이고, 로그는 한 처리 단계의 전체 테이프예요. '여기서 무슨 일이 있었나'를 볼 때는 로그를 보고, '이 요청이 어디까지 갔나'를 따라갈 때는 트레이스를 꺼내요. 확대 수준이 다를 뿐, 목표는 같아요.
- 프로그램이 충돌하면서 자신의 상황을 출력할 때, 그 내용은 보통 로그에 쌓여요. 스택 트레이스와 로그는 경쟁 관계가 아니에요. 로그는 흔적들이 쌓이는 장소예요.
에이전트가 개입되는 순간 로그가 더욱 중요해지는 이유가 있어요. 에이전트는 화면도 없고 지켜보는 사람도 없이 실행돼요. 헤드리스로 돌리는 목적 자체가 그것이니까요. 그래서 로그는 내가 자는 동안 에이전트가 무엇을 했는지 볼 수 있는 유일한 창이에요. '로그를 확인해 보세요'는 그냥 에이전트가 밟은 모든 단계의 테이프를 순서대로 읽으라는 말이에요. 에이전트가 새벽 2시에 잘못된 방향으로 가버렸다면, 정확히 어디서 그랬는지 알려주는 영수증이 로그예요.
솔직히 짚어둘 점이 있어요. 로그는 거기에 쓰인 것만큼만 유용해요. 너무 적으면 정작 필요한 것에 대해 침묵하고, 너무 많으면 중요한 줄이 노이즈 속에 묻혀요. 좋은 로깅이란 무슨 일이 있었는지 재구성할 수 있을 만큼만 기록하는 거예요. 그 이상은 필요 없어요.
로그는 소프트웨어가 작동하면서 찍어내는 영수증 테이프예요. 타임스탬프가 붙은 한 줄씩, 절대 수정하지 않아요. 문제가 생겼을 때 추측하지 않아도 돼요. 스크롤을 되감아 실제로 일어난 일을 읽으면 되니까요.