본문 바로가기
Infra2026년 8월 17일6분 읽기

journald — systemd의 구조화 로깅 제대로 쓰기

YS
김영삼
조회 5
journald — systemd의 구조화 로깅 제대로 쓰기

journald는 systemd에 내장된 로그 수집 데몬으로, 서비스가 표준출력·표준에러로 뱉는 모든 로그와 커널·부팅 메시지를 구조화된 바이너리 저널로 모아 저장한다. 텍스트 파일에 한 줄씩 쌓던 방식과 달리, 각 로그에 메타데이터(필드)를 붙여 저장하기 때문에 "특정 서비스의 어제 에러만", "이 부팅 세션의 커널 메시지만" 같은 질의를 바로 던질 수 있다.

나는 한동안 journalctl을 그냥 "systemd판 tail"로만 썼다. 그러다 로그가 구조화돼 있다는 걸 제대로 이해하고 나니, grep으로 씨름하던 일들이 필터 옵션 몇 개로 끝났다. 이게 journald의 진짜 가치다.

텍스트 로그와 뭐가 다른가

전통적인 syslog는 로그를 사람이 읽는 한 줄 텍스트로 /var/log에 남긴다. 파싱하려면 정규식으로 다시 쪼개야 한다. journald는 반대로, 처음부터 키=값 필드의 집합으로 저장한다. 예를 들어 로그 한 건에 _SYSTEMD_UNIT=nginx.service, PRIORITY=3, _PID=1234 같은 필드가 자동으로 붙는다.

항목전통 syslogjournald
저장 형식평문 텍스트구조화 바이너리
필터링grep/awk필드 기반 질의
서비스 매핑수동 파싱자동(_SYSTEMD_UNIT)
변조 감지없음FSS 봉인 가능

실전 journalctl

구조화의 이점은 질의로 드러난다. 자주 쓰는 조합부터 손에 익히면 로그 뒤지는 시간이 확 준다.

# 특정 서비스 로그만, 실시간 추적
journalctl -u nginx.service -f
# 이번 부팅 세션의 에러(우선순위 3=err 이하)만
journalctl -b -p err
# 시간 범위로 자르기
journalctl --since "2026-08-19 09:00" --until "2026-08-19 10:00"
# 특정 필드로 직접 질의 (구조화의 진가)
journalctl _PID=1234
journalctl _SYSTEMD_UNIT=sshd.service _COMM=sshd
# JSON으로 뽑아 외부 도구로 넘기기
journalctl -u myapp -o json | jq '.MESSAGE'

내가 특히 좋아하는 건 -p(우선순위)와 -b(부팅) 조합이다. 서버가 이상하면 journalctl -b -p warning 한 방으로 이번 부팅의 경고 이상만 훑는다. 텍스트 로그였으면 여러 파일을 grep으로 헤맬 일이다.

디스크에 남기기: 휘발성 함정

기본 설정에서 journald가 로그를 /run(메모리)에만 저장하도록 돼 있으면, 재부팅하면 로그가 날아간다. 이걸 모르고 "어제 새벽 크래시 로그 좀 보자" 했다가 텅 빈 걸 보고 당황한 적이 있다. 영구 저장을 켜자.

# 영구 저장 디렉터리 생성 후 재시작
mkdir -p /var/log/journal
systemctl restart systemd-journald
# 저장 정책·용량은 설정 파일에서 (/etc/systemd/journald.conf)
# Storage=persistent
# SystemMaxUse=2G        # 저널 총 용량 상한
# MaxRetentionSec=1month # 보존 기간
운영 서버라면 Storage=persistent와 SystemMaxUse는 사실상 필수 설정이다. 안 잡아두면 로그가 휘발되거나, 반대로 디스크를 야금야금 다 먹어 정작 서비스가 멈추는 상황이 온다.

syslog와 함께, 혹은 중앙 수집으로

journald가 있다고 rsyslog가 사라진 건 아니다. 많은 배포판이 둘을 함께 돌린다. journald가 1차로 받고, 필요하면 rsyslog로 전달해 원격 로그 서버로 보내는 식이다. 요즘은 여기서 한 발 더 나가, journald의 구조화된 로그를 그대로 중앙 수집기(예: Loki, Elastic)로 흘려보내 여러 서버 로그를 한곳에서 질의한다. 이미 필드가 붙어 있으니 수집 쪽 파싱 부담이 적다는 게 큰 장점이다.

자주 묻는 질문

journalctl 출력이 너무 많은데 특정 서비스만 보려면?

journalctl -u 서비스명을 쓰면 됩니다. 여기에 -f(실시간), -p err(에러만), --since(시간)를 조합하면 원하는 로그만 정확히 뽑을 수 있습니다. 서비스 이름을 모르면 systemctl list-units로 확인하세요.

재부팅하면 로그가 사라지는데 정상인가요?

영구 저장이 꺼져 있으면 로그가 메모리에만 남아 재부팅 시 날아갑니다. /var/log/journal 디렉터리를 만들고 Storage=persistent로 설정하면 디스크에 보존됩니다. 운영 서버에서는 반드시 켜두는 걸 권장합니다.

저널이 디스크를 너무 많이 차지해요.

journalctl --vacuum-size=500M로 즉시 오래된 로그를 정리하거나, journalctl --vacuum-time=2weeks로 기간 기준 정리를 할 수 있습니다. 근본적으로는 journald.conf의 SystemMaxUse로 상한을 걸어두세요.

앱에서 구조화 필드를 직접 남길 수 있나요?

가능합니다. systemd-cat이나 각 언어의 sd-journal 라이브러리로 커스텀 필드를 붙여 로그를 보낼 수 있습니다. 다만 일반 stdout 로그도 journald가 자동으로 유닛·PID 등 핵심 메타데이터를 붙여주므로, 대개는 표준출력만 잘 써도 충분합니다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록