실전: 로그 분석 보고서
웹 서버를 운영하다 보면 매일 접근 로그가 쌓입니다. 트래픽이 갑자기 늘었는지, 어떤 URL이 가장 많이 호출됐는지, 에러가 얼마나 발생했는지 파악해야 합니다. 상용 분석 도구를 쓸 수도 있지만, awk와 sort, head를 조합하면 같은 정보를 스크립트 하나로 뽑아낼 수 있습니다.
샘플 로그 파일
Apache Combined Log Format 형식의 샘플 로그를 준비합니다. 실제 접근 로그와 동일한 형식입니다.
# 파일: /tmp/access.logcat > /tmp/access.log << 'EOF'192.168.1.10 - - [15/Mar/2024:08:05:11 +0900] "GET /index.html HTTP/1.1" 200 2048192.168.1.20 - - [15/Mar/2024:08:12:33 +0900] "GET /about.html HTTP/1.1" 200 1536192.168.1.30 - - [15/Mar/2024:08:35:55 +0900] "POST /api/login HTTP/1.1" 401 512192.168.1.10 - - [15/Mar/2024:09:01:22 +0900] "GET /dashboard HTTP/1.1" 200 4096192.168.1.40 - - [15/Mar/2024:09:15:44 +0900] "GET /index.html HTTP/1.1" 200 2048192.168.1.50 - - [15/Mar/2024:09:22:10 +0900] "GET /api/users HTTP/1.1" 200 8192192.168.1.30 - - [15/Mar/2024:09:45:30 +0900] "POST /api/login HTTP/1.1" 200 256192.168.1.60 - - [15/Mar/2024:10:02:15 +0900] "GET /index.html HTTP/1.1" 200 2048192.168.1.70 - - [15/Mar/2024:10:11:08 +0900] "GET /contact.html HTTP/1.1" 404 0192.168.1.80 - - [15/Mar/2024:10:25:42 +0900] "GET /api/items HTTP/1.1" 200 3072192.168.1.10 - - [15/Mar/2024:10:33:19 +0900] "DELETE /api/users/5 HTTP/1.1" 500 128192.168.1.20 - - [15/Mar/2024:10:50:05 +0900] "GET /dashboard HTTP/1.1" 301 0192.168.1.90 - - [15/Mar/2024:11:05:33 +0900] "GET /index.html HTTP/1.1" 200 2048192.168.1.10 - - [15/Mar/2024:11:18:47 +0900] "GET /api/users HTTP/1.1" 200 8192192.168.1.30 - - [15/Mar/2024:11:30:22 +0900] "POST /api/items HTTP/1.1" 201 512192.168.1.40 - - [15/Mar/2024:11:45:00 +0900] "GET /about.html HTTP/1.1" 200 1536192.168.1.50 - - [15/Mar/2024:12:02:11 +0900] "GET /index.html HTTP/1.1" 200 2048192.168.1.60 - - [15/Mar/2024:12:15:30 +0900] "GET /api/items HTTP/1.1" 404 0192.168.1.70 - - [15/Mar/2024:12:28:44 +0900] "GET /dashboard HTTP/1.1" 200 4096192.168.1.80 - - [15/Mar/2024:12:40:55 +0900] "GET /index.html HTTP/1.1" 200 2048EOF
로그 형식을 파악합니다.
192.168.1.10 - - [15/Mar/2024:08:05:11 +0900] "GET /index.html HTTP/1.1" 200 2048
$1 $2$3 $4 $5 $6 $7 $8 $9
$1: IP 주소$4: 날짜/시간 ([15/Mar/2024:08:05:11)$6: 요청 URL$9: HTTP 상태 코드$10: 응답 크기(바이트)
분석 스크립트
# 파일: /tmp/log_report.sh#!/bin/bash# Apache access.log 분석 보고서 생성# 사용법: ./log_report.sh [로그파일]LOG_FILE="${1:-/tmp/access.log}"if [[ ! -f "$LOG_FILE" ]]; then echo "오류: 로그 파일이 없습니다: $LOG_FILE" >&2 exit 1fiecho "============================================"echo " 웹 서버 접근 로그 분석 보고서"echo " 파일: $LOG_FILE"echo " 생성: $(date '+%Y-%m-%d %H:%M:%S')"echo "============================================"echo# ──────────────────────────────────────────# 1. 총 요청 수# ──────────────────────────────────────────echo "[ 1. 총 요청 수 ]"awk 'END { print " 총 요청:", NR "건" }' "$LOG_FILE"echo# ──────────────────────────────────────────# 2. HTTP 상태별 집계# ──────────────────────────────────────────echo "[ 2. HTTP 상태 코드별 집계 ]"awk '{ status[$9]++}END { printf " %-8s %6s\n", "상태코드", "건수" printf " %-8s %6s\n", "--------", "----" for (s in status) { printf " %-8s %6d\n", s, status[s] }}' "$LOG_FILE" | sort -k1echo# ──────────────────────────────────────────# 3. 시간대별 요청 분포# ──────────────────────────────────────────echo "[ 3. 시간대별 요청 분포 ]"awk '{ # $4 형식: [15/Mar/2024:08:05:11 # 8번째 문자부터 2글자가 시간(HH) hour = substr($4, 14, 2) hourly[hour]++}END { printf " %-6s %6s %s\n", "시간대", "요청수", "막대그래프" printf " %-6s %6s %s\n", "------", "------", "----------" for (h in hourly) { bar = "" for (i = 0; i < hourly[h]; i++) bar = bar "#" printf " %s시 %6d %s\n", h, hourly[h], bar }}' "$LOG_FILE" | sort -k1echo# ──────────────────────────────────────────# 4. 상위 10개 요청 URL# ──────────────────────────────────────────echo "[ 4. 상위 10개 요청 URL ]"awk '{ print $6 }' "$LOG_FILE" \ | sort \ | uniq -c \ | sort -rn \ | head -10 \ | awk '{ printf " %6d %s\n", $1, $2 }'echo# ──────────────────────────────────────────# 5. 상위 5개 접속 IP# ──────────────────────────────────────────echo "[ 5. 상위 5개 접속 IP ]"awk '{ print $1 }' "$LOG_FILE" \ | sort \ | uniq -c \ | sort -rn \ | head -5 \ | awk '{ printf " %6d %s\n", $1, $2 }'echo# ──────────────────────────────────────────# 6. 오류 요청 목록 (4xx, 5xx)# ──────────────────────────────────────────echo "[ 6. 오류 요청 (4xx, 5xx) ]"awk '$9 >= 400 { printf " %s %-6s %s\n", $1, $9, $6}' "$LOG_FILE"echo# ──────────────────────────────────────────# 7. 총 전송량# ──────────────────────────────────────────echo "[ 7. 총 전송량 ]"awk '{ total += $10 }END { if (total >= 1048576) printf " %.2f MB\n", total / 1048576 else if (total >= 1024) printf " %.2f KB\n", total / 1024 else printf " %d bytes\n", total}' "$LOG_FILE"echoecho "============================================"echo " 분석 완료"echo "============================================"
실행 결과
chmod +x /tmp/log_report.sh/tmp/log_report.sh /tmp/access.log
============================================
웹 서버 접근 로그 분석 보고서
파일: /tmp/access.log
생성: 2024-03-15 14:30:00
============================================
[ 1. 총 요청 수 ]
총 요청: 20건
[ 2. HTTP 상태 코드별 집계 ]
상태코드 건수
-------- ----
200 14
201 1
301 1
401 1
404 2
500 1
[ 3. 시간대별 요청 분포 ]
시간대 요청수 막대그래프
------ ------ ----------
08시 3 ###
09시 4 ####
10시 5 #####
11시 4 ####
12시 4 ####
[ 4. 상위 10개 요청 URL ]
6 /index.html
3 /dashboard
2 /about.html
2 /api/items
2 /api/users
2 /api/login
1 /contact.html
1 /api/items
1 /api/users/5
[ 5. 상위 5개 접속 IP ]
4 192.168.1.10
3 192.168.1.30
2 192.168.1.20
2 192.168.1.40
2 192.168.1.50
[ 6. 오류 요청 (4xx, 5xx) ]
192.168.1.30 401 /api/login
192.168.1.70 404 /contact.html
192.168.1.10 500 /api/users/5
192.168.1.60 404 /api/items
[ 7. 총 전송량 ]
43.00 KB
============================================
분석 완료
============================================
스크립트 핵심 포인트
필드 파싱. Apache 로그는 공백으로 구분되지만 날짜 필드에 공백이 없으므로 그냥 6, 10으로 접근할 수 있습니다. 필드 번호는 로그 형식에 따라 달라지므로 처음에 확인해야 합니다.
substr로 시간 추출. $4가 [15/Mar/2024:08:05:11 형식이므로 14번째 문자부터 2글자가 시간입니다. substr로 잘라냈습니다.
awk + sort + uniq 조합. awk로 필드만 뽑고, sort로 정렬하고, uniq -c로 중복 횟수를 세고, sort -rn으로 내림차순 정렬합니다. 이 네 명령어의 조합은 빈도 분석의 기본 패턴입니다.
텍스트 막대그래프. for (i = 0; i < count; i++) bar = bar "#" 패턴으로 간단한 시각화를 만들 수 있습니다. 큰 숫자에는 적합하지 않으므로 최대값으로 나눠 정규화하는 방법을 함께 쓰면 좋습니다.
단위 변환. 바이트를 KB나 MB로 변환할 때 if-else로 분기했습니다. 10진수(1000 단위)와 2진수(1024 단위) 중 상황에 맞는 단위를 선택하면 됩니다.
PART 07에서 sed와 awk를 모두 살펴봤습니다. sed는 텍스트를 변환하고 설정 파일을 자동으로 수정합니다. awk는 데이터를 집계하고 보고서를 만듭니다. 두 도구를 자유롭게 조합하면 별도의 프로그램 없이도 복잡한 텍스트 처리 파이프라인을 구성할 수 있습니다.