리눅스 로그 보는 명령어 정리 — tail, less, journalctl, lnav
서버에서 장애 조사할 때 가장 먼저 손이 가는 도구들. tail로 따라가기, less로 탐색, journalctl로 systemd 로그 보기, lnav 같은 현대적 대안까지 정리.
Series
리눅스 명령어 시리즈- 1man이 너무 길 때 — tldr로 리눅스 명령어 빠르게 익히기
- 2파일 검색 명령어 정리 — find, grep, fd, ripgrep
- 3리눅스 로그 보는 명령어 정리 — tail, less, journalctl, lnav
- 4리눅스 프로세스·리소스 모니터링 — top, htop, ps, df 실전 정리
- 5리눅스 권한 정리 — chmod, chown, sudo와 그 너머
- 6리눅스 네트워크 디버깅 — ss, curl, dig, tcpdump 실전 정리
- 7SSH·SCP·Rsync — 원격 접속과 파일 동기화 한 묶음
- 8리눅스 텍스트 처리 — sed, awk, cut, sort, uniq, xargs 실전 정리
공부하게 된 계기
서버에서 뭔가 안 되면 가장 먼저 하는 일이 로그 보기다. 그런데 로그는 한두 GB짜리 파일인 경우도 흔하고, 실시간으로 계속 새 줄이 추가되기도 한다. cat으로 열었다간 터미널이 마비된다.
이 글은 로그를 다루는 흐름 순서로 정리한다 — 어디 있는지 찾고 → 보고 → 따라가고 → 필터링하고 → 분석하기.
1) 로그가 사는 곳
리눅스 로그는 보통 /var/log/ 아래에 있다.
| 경로 | 내용 |
|---|---|
/var/log/syslog 또는 /var/log/messages | 시스템 전반 |
/var/log/auth.log | 인증/로그인 (Ubuntu 계열) |
/var/log/secure | 인증 (RHEL 계열) |
/var/log/kern.log | 커널 메시지 |
/var/log/dmesg | 부팅 시점 커널 메시지 |
/var/log/nginx/access.log error.log | Nginx |
/var/log/apache2/ | Apache |
/var/log/journal/ | systemd journal (바이너리) |
systemd 시대(2015~)에 와서는 텍스트 파일 대신 journal이라는 바이너리 포맷에 모인다. journalctl로 본다 (뒤에서 다룸).
2) cat — 작은 파일에만
cat /var/log/syslog100MB짜리 파일에 cat을 쓰면 터미널이 한참 멈춘다. 로그에 cat을 쓰는 건 거의 항상 잘못된 선택이다. 다음 도구들이 있다.
3) head, tail — 앞/뒤 일부만
# 처음 10줄
head /var/log/syslog
# 처음 100줄
head -n 100 /var/log/syslog
# 마지막 10줄
tail /var/log/syslog
# 마지막 50줄
tail -n 50 /var/log/syslog대부분의 경우 로그는 시간 순으로 뒤가 최신이다. 그래서 tail이 훨씬 자주 쓰인다.
4) tail -f — 실시간 추적 (가장 자주 씀)
tail -f /var/log/nginx/access.log새 줄이 추가될 때마다 화면에 실시간으로 출력된다. 장애 재현 중일 때, 배포 직후 모니터링할 때 필수.
종료는 Ctrl+C.
-F는 더 안전하다
tail -F /var/log/app.log대문자 -F는 파일이 로테이션돼도 따라간다. 로그가 매일 자정에 app.log → app.log.1로 회전하는 경우, -f는 옛 파일을 계속 보고 있지만 -F는 새 app.log로 자동 전환한다.
여러 파일 동시에
tail -F /var/log/nginx/access.log /var/log/nginx/error.log각 줄 앞에 파일명이 붙는다. 두 로그를 동시에 봐야 할 때.
시작 위치 조정
# 마지막 1000줄부터 보기 시작
tail -n 1000 -F /var/log/app.log
# 특정 줄부터 끝까지
tail -n +500 /var/log/app.log5) less — 큰 파일 탐색의 정석
less /var/log/syslogcat과 다른 점:
- 페이지 단위로 한 화면씩 보여준다
- 검색, 점프, 따라가기 가능
- 파일을 메모리에 다 안 올린다 — GB 단위 파일도 즉시 열림
less 키 조작
| 키 | 동작 |
|---|---|
Space, f | 다음 페이지 |
b | 이전 페이지 |
g | 맨 처음 |
G | 맨 끝 |
/단어 | 단어 검색 (앞 → 뒤) |
?단어 | 단어 검색 (뒤 → 앞) |
n, N | 다음/이전 매치 |
&pattern | pattern 매치되는 줄만 표시 |
F | tail -f 모드 (Ctrl+C로 빠져나옴) |
q | 종료 |
less의 F 키 — 화면 맨 끝으로 가서 tail -f처럼 동작한다. tail -f로 보다가 위로 스크롤하고 싶을 때 Ctrl+C로 빠져나와 g로 처음으로 갔다가 다시 F로 돌아갈 수 있다. 한 도구 안에서 다 됨.
more보다 less
more는 옛 도구. less가 뒤로도 스크롤되고 검색도 강력하다. ("less is more"라는 농담의 어원.)
6) journalctl — systemd 로그
systemd가 깔린 모든 현대 리눅스(Ubuntu 16.04+, CentOS 7+, Debian 8+)에서는 가장 중요한 명령어다.
# 전체 (페이저로 자동 열림)
journalctl
# 마지막 100줄
journalctl -n 100
# 실시간 추적
journalctl -f
# 마지막 부팅부터
journalctl -b
# 특정 서비스
journalctl -u nginx
journalctl -u nginx -f # 그 서비스 실시간
# 특정 시간 범위
journalctl --since "2026-05-10 00:00" --until "2026-05-10 12:00"
journalctl --since "1 hour ago"
journalctl --since yesterday
# 우선순위 (err 이상만)
journalctl -p err우선순위 레벨: emerg (0) → alert → crit → err → warning → notice → info → debug (7).
자주 쓰는 조합
# 어떤 서비스가 30분 전부터 어떤 에러를 냈는지
journalctl -u my-app --since "30 min ago" -p err
# 부팅 직후 발생한 모든 메시지
journalctl -b -p warning
# 디스크 다 차지하는 로그 정리
sudo journalctl --vacuum-time=7d # 7일 이전 삭제
sudo journalctl --vacuum-size=500M # 500MB 넘는 부분 삭제7) dmesg — 커널 메시지
sudo dmesg
# 사람이 읽기 쉬운 시간 표시
sudo dmesg -T
# 실시간 추적
sudo dmesg -wUSB 꽂혔을 때, 디스크 IO 에러, OOM Killer 발동 등 커널 레벨의 메시지가 여기로 온다. 하드웨어 문제 의심될 때 가장 먼저 본다.
# OOM이 발동한 적 있는지
sudo dmesg -T | grep -i "out of memory"
# 디스크 에러
sudo dmesg -T | grep -i "i/o error"8) docker logs — 컨테이너 로그
요즘은 서비스가 컨테이너로 돌아가는 경우가 많다. 이 경우 journalctl이나 /var/log/를 봐도 정작 앱 로그는 안 보인다 — Docker가 따로 관리하기 때문이다.
기본 사용
# 컨테이너 ID 또는 이름 확인
docker ps
# 전체 로그
docker logs my-api
# 마지막 100줄
docker logs --tail 100 my-api
# 실시간 추적 (tail -F 같은 역할)
docker logs -f my-api
# 마지막 100줄부터 실시간 추적
docker logs --tail 100 -f my-api
# 타임스탬프 추가
docker logs -t my-api-f는 가장 자주 쓴다. 컨테이너가 종료돼도 마지막 로그는 남으니 사후 분석에도 유용.
시간 범위로 자르기
# 최근 10분
docker logs --since 10m my-api
# 특정 시각 이후
docker logs --since 2026-05-10T12:00:00 my-api
# 시각 범위
docker logs --since 1h --until 30m my-api--since/--until은 1h, 30m, 2025-01-01 같은 표현을 모두 받는다.
docker compose — 여러 서비스를 한번에
# 전체 서비스 로그 (현재 디렉토리의 compose 프로젝트)
docker compose logs
# 특정 서비스만
docker compose logs web
# 실시간 추적
docker compose logs -f
# 여러 서비스 동시에
docker compose logs -f web db
# 마지막 50줄부터 추적
docker compose logs --tail=50 -f서비스 이름별로 색깔이 다르게 표시돼서 어느 컨테이너에서 온 로그인지 한눈에 보인다.
실제 로그 파일은 어디 있나
JSON 파일 드라이버(기본)인 경우, 호스트의 다음 위치에 로그가 쌓인다.
/var/lib/docker/containers/<container-id>/<container-id>-json.log# 컨테이너 ID 알아내기
docker inspect --format='{{.Id}}' my-api
# 직접 tail
sudo tail -F /var/lib/docker/containers/<id>/<id>-json.logJSON 한 줄당 한 메시지 형식이라 그대로 읽기는 불편하다. jq를 거치면 깔끔.
sudo tail -F /var/lib/docker/containers/<id>/<id>-json.log | jq -r '.log'로그 드라이버가 journald라면
# 컨테이너 이름으로 검색
journalctl CONTAINER_NAME=my-api -f
# Compose 환경에서
journalctl CONTAINER_NAME=myproject-web-1 --since "10 min ago"운영 환경에서 systemd 통합을 선호하는 팀은 이 드라이버를 자주 쓴다. 그러면 journalctl의 모든 기능(시간 필터, 우선순위 등)을 그대로 쓸 수 있다.
로그가 디스크를 잡아먹을 때
기본 설정에서 Docker 로그는 무한히 커진다. 운영 중인 호스트가 갑자기 디스크 가득 찼다면 십중팔구 이거다.
# 컨테이너별 로그 크기 확인
sudo du -sh /var/lib/docker/containers/*/
# 실시간 디스크 점유 모니터링
docker system df -v해결은 daemon.json에 로그 회전 설정.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}이미 차오른 로그를 즉시 비우려면:
# 위험 — 컨테이너가 살아있는 상태에서 직접 truncate
sudo truncate -s 0 /var/lib/docker/containers/<id>/<id>-json.log또는 컨테이너를 재시작하면 새 파일로 시작된다.
grep과 조합
docker logs도 그냥 stdout이라 파이프가 다 된다.
# ERROR만
docker logs my-api 2>&1 | grep ERROR
# 실시간 ERROR 추적
docker logs -f my-api 2>&1 | grep --line-buffered ERROR
# 5xx 응답만 (Nginx 컨테이너)
docker compose logs nginx 2>&1 | awk '$9 ~ /^5/'docker logs는 stdout과 stderr 둘 다 출력한다. stderr가 따로 흘러서 grep에 안 잡히는 경우가 흔하다 — 그래서 2>&1로 합쳐주는 습관. docker logs my-api | grep error만 치면 stderr가 새는 걸 보고 한참 헤맨다.
자주 쓰는 한 줄 요약
# 컨테이너 들어가기 전 마지막 로그 빠르게 보기
docker logs --tail 50 my-api
# 배포 직후 모니터링
docker compose logs -f --tail=100 web
# 어제 뭐가 일어났나
docker logs --since 24h --until 12h my-api | grep -i error9) 필터링 — grep / awk 조합
대부분의 로그 작업은 결국 필터링이다.
grep 기본
# ERROR 포함 줄만
grep ERROR /var/log/app.log
# 대소문자 무시
grep -i error /var/log/app.log
# 앞뒤 컨텍스트 3줄
grep -B 3 -A 3 "ERROR" /var/log/app.log
grep -C 3 "ERROR" /var/log/app.log # 위와 같음
# 줄 번호
grep -n ERROR /var/log/app.log
# 매칭 카운트
grep -c ERROR /var/log/app.log
# 정규식
grep -E "ERROR|WARN" /var/log/app.logtail + grep — 실시간 필터
# 실시간으로 흐르는 로그에서 ERROR만
tail -F /var/log/app.log | grep --line-buffered ERROR--line-buffered는 꼭 필요하다. 안 붙이면 grep이 4KB씩 버퍼링해서 출력이 뚝뚝 끊긴다.
awk — 컬럼 단위 처리
Nginx access log를 예로 들면:
192.168.1.1 - - [10/May/2026:12:34:56 +0000] "GET /api/posts HTTP/1.1" 200 1234
# IP만 (1번째 컬럼)
awk '{print $1}' access.log
# IP별 카운트, 많은 순으로
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
# 5xx 응답만 (9번째 컬럼이 상태코드)
awk '$9 >= 500' access.log
# 응답 크기 합계 (10번째 컬럼)
awk '{sum += $10} END {print sum}' access.log10) lnav — 로그 전용 페이저
less보다 한 단계 위. 로그 포맷을 자동 인식해서 색깔 입히고 시간 파싱까지 해준다.
brew install lnav
sudo apt install lnavlnav /var/log/nginx/access.log
lnav /var/log/ # 디렉토리 통째로기능:
- 시간 기준으로 여러 파일 자동 머지
- SQL 쿼리로 로그 분석 (
;SELECT cs_uri FROM access_log WHERE sc_status >= 500;) - 자동 syntax 하이라이트
- 정규식 필터링
서버 장애 조사가 일상이라면 한 번 깔아둘 만하다.
11) multitail — 여러 로그 동시 보기
brew install multitail
sudo apt install multitail# 두 로그를 분할 화면으로
multitail /var/log/nginx/access.log /var/log/nginx/error.log
# 색깔 입혀서
multitail -cS apache /var/log/nginx/access.logtail -F file1 file2는 줄이 섞이지만, multitail은 화면을 분할해서 보여준다. 모니터링 대시보드 흉내.
실전 패턴 6개
A. 배포 직후 5분 모니터링
# systemd 서비스
journalctl -u my-app -f -p warning
# 파일 기반
tail -F /var/log/app.log | grep --line-buffered -E "ERROR|WARN"
# Docker Compose
docker compose logs -f --tail=100 webB. 30분 안에 발생한 5xx 응답 카운트
journalctl -u nginx --since "30 min ago" \
| awk '$9 ~ /^5/ {print $9}' | sort | uniq -cC. 디스크 갑자기 가득 참 — 무엇이 OOM 됐나
sudo dmesg -T | grep -i "killed process"
journalctl -k --since today | grep -i oomD. SSH 무차별 대입 시도 흔적
sudo journalctl _COMM=sshd | grep "Failed password" | awk '{print $NF}' | sort | uniq -c | sort -rnE. 특정 사용자의 활동 (Nginx)
grep "user-id-12345" /var/log/nginx/access.log | tail -100F. 어제 자정~6시 사이의 ERROR
journalctl --since "yesterday 00:00" --until "yesterday 06:00" -p err정리 — 어떤 걸 쓸까
일상: tail -F로 따라가기, less로 탐색, grep으로 필터링. 이 셋이면 90%.
systemd 환경: journalctl -u <service> -f가 첫 번째 손.
컨테이너 환경: docker logs -f 또는 docker compose logs -f <service>. stderr 합치는 2>&1 잊지 말 것.
커널/하드웨어 의심: sudo dmesg -T.
복잡한 분석: awk 한 줄짜리, 안 되면 lnav.
로그를 잘 보는 사람과 못 보는 사람의 차이는 장애 해결 시간으로 직결된다. 도구를 손에 익혀두자.
시리즈 정리
리눅스 명령어 시리즈도 이번 편으로 3편이다.
- 1편: tldr로 리눅스 명령어 빠르게 익히기
- 2편: 파일 검색 명령어 정리 — find, grep, fd, ripgrep
- 3편 (이 글): 로그 보는 명령어
다음 편이 있다면 — 프로세스/리소스 모니터링(top, htop, ps, iostat)이나 네트워크 디버깅(netstat, ss, tcpdump) 정도가 자연스러운 흐름이다.
참고 자료
man tail,man less,man journalctl,man dmesg- lnav 공식
- multitail 공식