프로젝트 2: 로그 분석과 알림
두 번째 프로젝트는 로그 분석입니다. 서버는 쉬지 않고 로그를 생성합니다. 아무도 읽지 않는 로그는 에러가 터져도 아무것도 알려주지 않습니다.
이 스크립트는 주기적으로 로그 파일을 분석해 에러 패턴을 감지하고, 임계값을 넘으면 Slack으로 알림을 보냅니다. 중복 알림 방지와 일일 요약 리포트도 포함합니다.
요구사항
- grep으로 ERROR, CRITICAL, FATAL 패턴을 검색합니다.
- awk로 시간, IP, 메시지를 파싱합니다.
- 에러 빈도가 임계값을 넘으면 Slack Webhook으로 알림을 보냅니다.
- 마지막 분석 시점을 기록해서 중복 알림을 방지합니다.
- 매일 자정에 일일 요약 리포트를 생성합니다.
샘플 로그 데이터
테스트에 쓸 샘플 로그 파일을 만듭니다.
# 새 파일: /tmp/sample_app.logcat > /tmp/sample_app.log << 'EOF'2026-04-24 09:01:15 INFO [192.168.1.10] 사용자 로그인 성공: user12026-04-24 09:01:22 INFO [192.168.1.11] 페이지 요청: /dashboard2026-04-24 09:02:01 ERROR [192.168.1.20] 데이터베이스 연결 실패: connection timeout2026-04-24 09:02:10 WARN [192.168.1.21] 응답 지연: 2.3초2026-04-24 09:03:05 ERROR [192.168.1.20] 데이터베이스 연결 실패: connection timeout2026-04-24 09:03:12 CRITICAL [192.168.1.30] 디스크 사용률 95% 초과2026-04-24 09:04:00 INFO [192.168.1.12] 사용자 로그인 성공: user22026-04-24 09:05:01 ERROR [192.168.1.20] 데이터베이스 연결 실패: max connections reached2026-04-24 09:05:30 FATAL [192.168.1.40] 메모리 부족: OOM killer 실행됨2026-04-24 09:06:00 ERROR [192.168.1.20] API 인증 실패: invalid token2026-04-24 09:06:45 INFO [192.168.1.13] 파일 업로드 완료: report.pdfEOF
로그 분석 스크립트
#!/usr/bin/env bash# 새 파일: /home/ubuntu/scripts/log_monitor.shset -euo pipefail# ==============================================================# 설정# ==============================================================LOG_TARGET="/tmp/sample_app.log" # 감시할 로그 파일STATE_FILE="/tmp/log_monitor.state" # 마지막 분석 위치 저장REPORT_DIR="/tmp/log_reports" # 리포트 저장 위치ALERT_LOG="/tmp/log_monitor_alert.log" # 알림 기록# 임계값: 분당 이 수 이상 에러가 발생하면 알림ERROR_THRESHOLD=3# Slack Webhook URL (실제 URL로 교체)# SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"SLACK_WEBHOOK=""# ==============================================================# 유틸 함수# ==============================================================log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*"; }send_slack_alert() { local message="$1" if [[ -z "$SLACK_WEBHOOK" ]]; then log "[알림 시뮬레이션] $message" echo "$(date '+%Y-%m-%d %H:%M:%S') ALERT: $message" >> "$ALERT_LOG" return fi curl -s -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"$message\"}" \ "$SLACK_WEBHOOK" > /dev/null}# ==============================================================# 마지막 분석 위치 로드# ==============================================================LAST_LINE=0if [[ -f "$STATE_FILE" ]]; then LAST_LINE=$(cat "$STATE_FILE")fiTOTAL_LINES=$(wc -l < "$LOG_TARGET")NEW_LINES=$((TOTAL_LINES - LAST_LINE))if [[ $NEW_LINES -le 0 ]]; then log "새로운 로그 없음 (총 ${TOTAL_LINES}줄, 마지막 분석: ${LAST_LINE}줄)" exit 0filog "새 로그 ${NEW_LINES}줄 분석 시작"# ==============================================================# 새로 추가된 줄만 분석# ==============================================================NEW_LOG=$(tail -n "$NEW_LINES" "$LOG_TARGET")# 에러 레벨별 카운트ERROR_COUNT=$(echo "$NEW_LOG" | grep -cE "\b(ERROR)\b" || true)CRITICAL_COUNT=$(echo "$NEW_LOG" | grep -cE "\b(CRITICAL)\b" || true)FATAL_COUNT=$(echo "$NEW_LOG" | grep -cE "\b(FATAL)\b" || true)TOTAL_ERRORS=$((ERROR_COUNT + CRITICAL_COUNT + FATAL_COUNT))log "에러 통계 - ERROR: ${ERROR_COUNT}, CRITICAL: ${CRITICAL_COUNT}, FATAL: ${FATAL_COUNT}"# ==============================================================# 에러 상세 파싱 (awk)# ==============================================================if [[ $TOTAL_ERRORS -gt 0 ]]; then echo "" echo "=== 에러 상세 내역 ===" echo "$NEW_LOG" | awk ' /ERROR|CRITICAL|FATAL/ { timestamp = $1 " " $2 level = $3 ip = $4 # IP에서 대괄호 제거 gsub(/[\[\]]/, "", ip) # 메시지는 5번째 필드부터 끝까지 message = "" for (i = 5; i <= NF; i++) { message = message " " $i } printf "%-20s %-10s %-16s %s\n", timestamp, level, ip, message }' echo ""fi# ==============================================================# 임계값 초과 시 알림# ==============================================================if [[ $TOTAL_ERRORS -ge $ERROR_THRESHOLD ]]; then HOST=$(hostname) ALERT_MSG="[경고] ${HOST}: 최근 ${NEW_LINES}줄에서 에러 ${TOTAL_ERRORS}건 감지 " ALERT_MSG+="(ERROR:${ERROR_COUNT} CRITICAL:${CRITICAL_COUNT} FATAL:${FATAL_COUNT})" send_slack_alert "$ALERT_MSG" log "알림 발송: $ALERT_MSG"fi# ==============================================================# 상태 파일 업데이트 (다음 실행 시 중복 분석 방지)# ==============================================================echo "$TOTAL_LINES" > "$STATE_FILE"log "상태 저장: ${TOTAL_LINES}줄까지 분석 완료"# ==============================================================# 일일 요약 리포트 (자정에 실행 시)# ==============================================================HOUR=$(date '+%H')MINUTE=$(date '+%M')if [[ "$HOUR" == "00" && "$MINUTE" -lt "05" ]]; then mkdir -p "$REPORT_DIR" REPORT_FILE="${REPORT_DIR}/report_$(date '+%Y%m%d').txt" YESTERDAY=$(date -d "yesterday" '+%Y-%m-%d') { echo "===== 일일 로그 분석 리포트 =====" echo "날짜: $YESTERDAY" echo "분석 대상: $LOG_TARGET" echo "" echo "--- 에러 레벨별 현황 ---" grep "$YESTERDAY" "$LOG_TARGET" 2>/dev/null | \ awk '{print $3}' | sort | uniq -c | sort -rn echo "" echo "--- 에러 발생 IP 순위 ---" grep -E "$YESTERDAY.*(ERROR|CRITICAL|FATAL)" "$LOG_TARGET" 2>/dev/null | \ awk '{gsub(/[\[\]]/, "", $4); print $4}' | sort | uniq -c | sort -rn | head -5 echo "" echo "--- 주요 에러 메시지 ---" grep -E "$YESTERDAY.*(ERROR|CRITICAL|FATAL)" "$LOG_TARGET" 2>/dev/null | \ awk '{for(i=5;i<=NF;i++) printf $i" "; print ""}' | \ sort | uniq -c | sort -rn | head -10 } > "$REPORT_FILE" log "일일 리포트 생성: $REPORT_FILE"fi
crontab 등록
chmod +x /home/ubuntu/scripts/log_monitor.shcrontab -e
다음 줄을 추가합니다.
# 매 5분마다 로그 분석
*/5 * * * * /home/ubuntu/scripts/log_monitor.sh >> /tmp/log_monitor_run.log 2>&1
# 매일 자정 일일 리포트 생성
0 0 * * * /home/ubuntu/scripts/log_monitor.sh >> /tmp/log_monitor_run.log 2>&1
수동 실행 테스트
/home/ubuntu/scripts/log_monitor.sh
실행 결과입니다.
2026-04-24 09:15:00 새 로그 11줄 분석 시작
2026-04-24 09:15:00 에러 통계 - ERROR: 4, CRITICAL: 1, FATAL: 1
=== 에러 상세 내역 ===
2026-04-24 09:02:01 ERROR 192.168.1.20 데이터베이스 연결 실패: connection timeout
2026-04-24 09:03:05 ERROR 192.168.1.20 데이터베이스 연결 실패: connection timeout
2026-04-24 09:03:12 CRITICAL 192.168.1.30 디스크 사용률 95% 초과
2026-04-24 09:05:01 ERROR 192.168.1.20 데이터베이스 연결 실패: max connections reached
2026-04-24 09:05:30 FATAL 192.168.1.40 메모리 부족: OOM killer 실행됨
2026-04-24 09:06:00 ERROR 192.168.1.20 API 인증 실패: invalid token
2026-04-24 09:15:00 알림 발송: [경고] myserver: 최근 11줄에서 에러 6건 감지 (ERROR:4 CRITICAL:1 FATAL:1)
2026-04-24 09:15:00 상태 저장: 11줄까지 분석 완료
두 번째로 실행하면 새 로그가 없으므로 건너뜁니다.
2026-04-24 09:20:00 새로운 로그 없음 (총 11줄, 마지막 분석: 11줄)