장애 대응 실무 가이드 · Part 5

여러 로그를 시간축으로 합치기

서버마다 따로 쌓인 로그에서 사건의 순서를 세우기

작성 기준2026년 7월

이 파트에서 다루는 내용

한 대만 봐서는 안 보인다시각 맞추기첫 오류 찾기요청 관통상관관계 착각로그가 없을 때
01

이 파트는 로그를 합치는 일을 다룹니다

로그가 어디에 쌓이고 어떤 명령으로 따라 보는지는 터미널·서버 코스에서 다룹니다. 스택트레이스 한 장을 읽고 원인 예외를 찾는 것도 그쪽입니다.

여기서 다루는 것은 그다음입니다. 장애는 한 대에서만 일어나지 않습니다. 웹서버, 여러 대의 애플리케이션 서버, 배치, DB, 외부 연동이 각각 자기 로그를 남깁니다. 이걸 하나의 시간축에 올려놓고 무엇이 먼저였는지 세우는 것이 이 파트입니다.

순서를 세우면 원인과 결과가 갈립니다. 이게 안 되면 결과를 붙잡고 몇 시간을 씁니다.

터미널·서버 코스
읽는 기술

로그 위치, 실시간 추적, 검색과 필터, 스택트레이스 해석. 명령어 중심입니다.

이 파트
합치는 기술

여러 출처의 로그를 시간순으로 정렬하고, 무엇이 원인이고 무엇이 파생인지 가릅니다.

02

시각을 맞추는 것이 먼저입니다

여러 서버의 로그를 합칠 때 가장 먼저 확인할 것은 시계가 맞는지입니다. 몇 초만 어긋나도 인과가 뒤집혀 보입니다.

실제로 서버 시간이 동기화되지 않은 환경을 종종 만납니다. 특히 고객사 폐쇄망에서 시간 서버가 없거나 막혀 있는 경우입니다.

  • 타임존이 섞이는 경우가 있습니다. 애플리케이션은 KST인데 인프라 로그는 UTC인 식입니다. 9시간 차이를 인지하지 못하면 엉뚱한 시간대를 봅니다.
  • 로그 시각의 정밀도를 확인합니다. 초 단위까지만 남기면 같은 초 안의 순서를 알 수 없습니다. 밀리초까지 남기도록 포맷을 잡아 두는 것이 좋습니다.
  • 외부 시스템 로그를 받을 때는 그쪽 시각 기준인지 우리 기준인지 확인합니다.
  • 정렬한 결과는 별도 파일로 만들어 둡니다. 원인 규명 보고서에 그대로 쓰입니다.
시각 확인bash
# 각 서버에서 현재 시각과 타임존 확인
date
timedatectl                    # 동기화 상태까지 확인

# 컨테이너 안팎이 다를 수 있습니다
docker exec <container> date

# 애플리케이션이 인식하는 타임존 (JVM 기준)
jcmd <PID> VM.system_properties | grep user.timezone

서버 시각이 다르면 각 로그의 오차를 메모해 두고 보정해서 읽습니다. 장애 대응 중에 시간을 맞추면 그 순간부터 로그가 또 어긋나므로, 대응이 끝난 뒤 정리합니다.

03

마지막 오류가 아니라 첫 오류입니다

Part 3에서 짚었던 내용을 실제로 찾는 방법입니다. 장애가 나면 오류가 연쇄적으로 번져서 로그가 수천 줄씩 쌓입니다. 눈에 띄는 것은 가장 많이 반복된 오류나 가장 마지막 오류인데, 둘 다 대개 결과입니다.

찾아야 할 것은 그 시간대에 처음 등장한 오류입니다. 그리고 그것이 정말 처음인지 확인하려면 기준선이 필요합니다.

시간 오름차순 정렬
기본

장애 발생 추정 시각 전후 10분을 잘라 시간순으로 봅니다. 여기서 처음 나타난 오류가 후보입니다.

기준선과 비교
핵심

운영 로그에는 평소에도 오류가 있습니다. 어제 같은 시각대 로그와 비교해 새로 등장한 종류인지 확인합니다.

Caused by 체인
터미널 코스

예외 하나 안에서도 최하단 원인 예외를 봅니다. 읽는 방법은 터미널·서버 코스에서 다룹니다.

반복 횟수의 함정
주의

가장 많이 찍힌 오류가 원인인 경우는 드뭅니다. 최초 1건이 원인이고 나머지 9999건이 결과인 경우가 훨씬 많습니다.

오류 종류별 최초 발생 시각 뽑기bash
# 오류 종류별로 처음 나타난 시각을 봅니다
grep -E "ERROR|Exception" application.log \
  | awk '{print $1, $2, $NF}' \
  | sort -k3,3 -k1,2 \
  | awk '!seen[$3]++'

# 평소와 비교: 어제 같은 시간대에 없던 오류 찾기
grep -oE "[A-Za-z.]+Exception" application.log.2026-07-28 | sort -u > /tmp/base.txt
grep -oE "[A-Za-z.]+Exception" application.log            | sort -u > /tmp/today.txt
comm -13 /tmp/base.txt /tmp/today.txt

마지막 comm 명령이 오늘만 새로 등장한 예외 종류를 보여 줍니다. 로그 포맷에 따라 열 위치를 조정해야 합니다. 명령 조합 자체는 터미널·서버 코스의 검색·조합 파트에서 다룹니다.

04

요청 하나를 처음부터 끝까지 봅니다

오류가 난 그 요청이 어디를 거쳐 왔는지 보면 원인이 드러납니다. 문제는 로그가 스레드별로 뒤섞여 쌓이기 때문에 한 요청만 골라내기가 어렵다는 것입니다.

요청 식별자가 있으면 간단합니다. 없으면 사실상 불가능합니다. 그래서 이건 장애가 나기 전에 준비해 둬야 하는 항목입니다.

  • 요청마다 고유 식별자를 만들어 모든 로그에 남기면, 그 값으로 검색하는 것만으로 요청 흐름이 나옵니다.
  • 여러 서버를 거치는 구조라면 식별자를 헤더로 전달해 이어 붙입니다. 이러면 서버 경계를 넘어서도 추적됩니다.
  • 식별자가 없다면 시각과 사용자 ID, URL 조합으로 근사합니다. 정확하지는 않지만 없는 것보다 낫습니다.
  • 스레드 이름으로 묶는 방법도 있습니다. 같은 요청은 같은 스레드에서 처리되므로, 짧은 시간 범위에서는 유효합니다.
  • 지금 없다면 이번 장애의 후속 과제로 넣습니다. 다음 장애의 대응 시간이 크게 줄어듭니다.
평소에 해 둘 것

요청 식별자와 밀리초 단위 시각, 이 두 가지만 로그 포맷에 있어도 장애 대응 시간이 절반으로 줄어듭니다. 장애가 난 뒤에 넣으면 이번 장애에는 쓸 수 없습니다. DB 코스 Part 14의 SQL 출처 태깅과 같은 성격의 사전 준비입니다.

05

동시에 일어났다고 원인은 아닙니다

장애 시각과 겹치는 무언가를 발견하면 그것을 원인으로 단정하기 쉽습니다. 배치가 돌고 있었다, 백업이 돌고 있었다, 다른 팀이 작업 중이었다.

겹친 것은 단서이지 결론이 아닙니다. 세 가지 가능성이 있습니다. 그것이 원인이거나, 그것도 같은 원인의 피해자이거나, 무관한 우연입니다.

그것이 원인
가능성 1

배치가 자원을 다 써서 온라인이 밀렸습니다. 검증하려면 배치를 멈췄을 때 회복되는지 봅니다.

둘 다 피해자
가능성 2

DB가 느려져서 배치도 밀리고 온라인도 밀렸습니다. 배치를 멈춰도 회복되지 않습니다.

무관한 우연
가능성 3

매일 같은 시각에 도는 배치라면 겹치는 것이 당연합니다. 평소에도 겹쳤는데 문제가 없었는지 확인합니다.

검증 질문
공통

"이것 없이도 장애가 났는가"와 "이것이 있었는데 장애가 안 난 날이 있는가". 두 질문으로 대부분 갈립니다.

06

로그가 없어서 못 찾는 경우

아무리 뒤져도 단서가 안 나오는 일이 있습니다. 이때는 로그 자체에 문제가 있는지 봅니다.

그리고 이번 장애에서 못 찾더라도, 다음에는 찾을 수 있게 만드는 것이 이 상황의 목표입니다.

예외를 삼킴
가장 흔함

catch 해 놓고 아무것도 안 하거나 메시지만 찍는 코드입니다. 원인 예외가 통째로 사라집니다.

로그 레벨
설정

운영에서 INFO 이상만 남기면 판단에 필요한 값이 안 보입니다. 필요한 지점만 선별해 올립니다.

로테이션으로 소실
시간 문제

장애 시 로그가 폭증하면 로테이션이 빨라져 정작 처음 부분이 사라집니다. Part 2에서 사본을 먼저 뜨라고 한 이유입니다.

구간 시간 미기록
측정 불가

어디서 시간을 썼는지 남기지 않으면 계층을 가를 수 없습니다. Part 3의 계층 가르기가 막힙니다.

못 찾았을 때의 결론

로그가 없어 원인을 못 찾았다면, 그 사실 자체가 원인 규명 보고서의 내용이 됩니다. 무엇이 없어서 못 찾았는지, 그래서 무엇을 보강했는지를 씁니다. Part 4의 원인 미규명 종료 보고가 이 경우에 해당합니다.

체크

이 파트 완료 기준