guardia-itsm/scripts/sm/log/log_analysis.sh
DESKTOP-TKLFCPRython 64c27c3509 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

192 lines
8.1 KiB
Bash

#!/bin/bash
# ============================================================
# GUARDiA SM | log_analysis.sh
# 대상: 다목적 서버 로그 분석 스크립트
# 파라미터: LOG_FILES="/app/logs/app.log /var/log/messages"
# ANALYZE_HOURS=1 (최근 N시간)
# ERROR_PATTERN="ERROR|FATAL|Exception|OOM|killed"
# WARN_PATTERN="WARN|WARNING|timeout|refused"
# TOP_N=10 (상위 N개 오류 패턴)
# LOG_SIZE_WARN_MB=500 ROTATE_CHECK=true
# ============================================================
set -euo pipefail
LOG_FILES=${LOG_FILES:-""}
ANALYZE_HOURS=${ANALYZE_HOURS:-1}
ERROR_PATTERN=${ERROR_PATTERN:-'ERROR|FATAL|Exception|OutOfMemory|killed process|Caused by'}
WARN_PATTERN=${WARN_PATTERN:-'WARN|WARNING|timeout|refused|connection reset|too many'}
TOP_N=${TOP_N:-10}
LOG_SIZE_WARN_MB=${LOG_SIZE_WARN_MB:-500}
ROTATE_CHECK=${ROTATE_CHECK:-true}
OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]"
SEP="─────────────────────────────────────────"
RESULT=0
echo "======================================================"
echo " GUARDiA SM 점검 | 로그 분석 | $(hostname -s)"
echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')"
echo " 분석 범위: 최근 ${ANALYZE_HOURS}시간"
echo "======================================================"
# 로그 파일이 미지정인 경우 자동 탐색
if [ -z "$LOG_FILES" ]; then
LOG_FILES=""
for AUTO_LOG in \
/opt/tomcat/logs/catalina.out \
/app/was/logs/catalina.out \
/opt/wildfly/standalone/log/server.log \
/opt/jeus/logs/*.log \
/var/log/httpd/error_log \
/var/log/nginx/error.log \
/var/log/messages \
/var/log/syslog; do
ls $AUTO_LOG 2>/dev/null | while read F; do
[ -r "$F" ] && LOG_FILES="${LOG_FILES} ${F}"
done
done
fi
if [ -z "${LOG_FILES// }" ]; then
echo " ${WARN} 분석할 로그 파일이 없음 (LOG_FILES 환경변수 설정 필요)"
exit 1
fi
# ── 각 로그 파일 분석 ─────────────────────────────────────
FILE_NUM=0
for LOGFILE in $LOG_FILES; do
[ -r "$LOGFILE" ] || continue
FILE_NUM=$(( FILE_NUM + 1 ))
FILESIZE_MB=$(du -m "$LOGFILE" 2>/dev/null | awk '{print $1}' || echo 0)
echo
echo "[$SEP] 파일 ${FILE_NUM}: ${LOGFILE}"
echo " 파일 크기: ${FILESIZE_MB} MB 수정: $(stat -c '%y' "$LOGFILE" 2>/dev/null | cut -c1-19 || echo 'N/A')"
# 파일 크기 경고
if [ "${FILESIZE_MB:-0}" -gt "$LOG_SIZE_WARN_MB" ]; then
echo " ${WARN} 로그 파일 크기 과다 (${FILESIZE_MB}MB > ${LOG_SIZE_WARN_MB}MB) — 로테이션 권고"
[ $RESULT -lt 1 ] && RESULT=1
fi
# 최근 라인 수 결정 (파일이 크면 더 많이)
TAIL_LINES=5000
[ "$FILESIZE_MB" -gt 100 ] && TAIL_LINES=10000
RECENT=$(tail -${TAIL_LINES} "$LOGFILE" 2>/dev/null || echo "")
if [ -z "$RECENT" ]; then
echo " ${WARN} 내용을 읽을 수 없음"
continue
fi
# 총 라인 수
TOTAL_LINES=$(echo "$RECENT" | wc -l)
echo " 분석 라인 수: ${TOTAL_LINES} (최근 ${TAIL_LINES}줄)"
# ── 에러 집계 ─────────────────────────────────────────
ERR_COUNT=$(echo "$RECENT" | grep -cE "$ERROR_PATTERN" || echo 0)
WARN_COUNT=$(echo "$RECENT" | grep -cE "$WARN_PATTERN" | grep -v -cE "$ERROR_PATTERN" || echo 0)
if [ "${ERR_COUNT:-0}" -gt 50 ]; then
echo " ${CRIT} 에러 ${ERR_COUNT}건 감지 (임계: 50)"
RESULT=2
elif [ "${ERR_COUNT:-0}" -gt 0 ]; then
echo " ${WARN} 에러 ${ERR_COUNT}건 감지"
[ $RESULT -lt 1 ] && RESULT=1
else
echo " ${OK} 에러 없음"
fi
echo " 경고 수: ${WARN_COUNT}"
# ── 상위 에러 패턴 ────────────────────────────────────
if [ "${ERR_COUNT:-0}" -gt 0 ]; then
echo
echo " [상위 에러 패턴 (Top ${TOP_N})]"
echo "$RECENT" | grep -E "$ERROR_PATTERN" | \
sed 's/[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}//g' | \
sed 's/[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}//g' | \
sed 's/\[.*\]//g' | \
sort | uniq -c | sort -rn | head "${TOP_N}" | \
awk '{count=$1; $1=""; printf " %5d회 %s\n", count, substr($0,2,100)}' || true
echo
echo " [최근 에러 5건]"
echo "$RECENT" | grep -E "$ERROR_PATTERN" | tail -5 | sed 's/^/ /'
fi
# ── OOM 감지 ──────────────────────────────────────────
OOM=$(echo "$RECENT" | grep -iE "OutOfMemoryError|out of memory|java heap space|GC overhead" | tail -5 || echo "")
if [ -n "$OOM" ]; then
echo
echo " ${CRIT} OOM 이벤트 감지:"
echo "$OOM" | sed 's/^/ /'
RESULT=2
fi
# ── 예외 스택트레이스 감지 ────────────────────────────
EXCEPTIONS=$(echo "$RECENT" | grep -cE "^(Caused by:|at [a-z].*\()" || echo 0)
echo " 스택트레이스 관련 라인: ${EXCEPTIONS}"
# ── HTTP 에러 코드 집계 (웹 로그 형식 감지) ───────────
HTTP5XX=$(echo "$RECENT" | grep -cE '" 5[0-9]{2} ' || echo 0)
HTTP4XX=$(echo "$RECENT" | grep -cE '" 4[0-9]{2} ' || echo 0)
if [ "${HTTP5XX:-0}" -gt 0 ] || [ "${HTTP4XX:-0}" -gt 0 ]; then
echo
echo " [HTTP 에러 코드 집계]"
echo " 5xx 에러: ${HTTP5XX}"
echo " 4xx 에러: ${HTTP4XX}"
[ "${HTTP5XX:-0}" -gt 10 ] && echo " ${WARN} 5xx 에러 과다" && [ $RESULT -lt 1 ] && RESULT=1
fi
# ── 주요 키워드 타임라인 (마지막 발생 시각) ──────────
echo
echo " [주요 이벤트 마지막 발생 시각]"
for KW in "ERROR" "WARN" "OutOfMemory" "Connection refused" "timeout"; do
LAST=$(echo "$RECENT" | grep -i "$KW" | tail -1 | cut -c1-30 || echo "")
[ -n "$LAST" ] && printf " %-20s: %s\n" "$KW" "$LAST"
done
done
[ "$FILE_NUM" -eq 0 ] && echo " ${WARN} 읽을 수 있는 로그 파일 없음"
# ── 시스템 로그 (dmesg) ───────────────────────────────────
echo
echo "[$SEP] 시스템 커널 메시지 (최근 1시간)"
DMESG=$(dmesg --since="1 hour ago" 2>/dev/null | \
grep -iE "error|oom|kill|fault|panic|blocked for" | tail -10 || \
dmesg 2>/dev/null | tail -50 | grep -iE "error|oom|kill|fault" | tail -10 || echo "")
if [ -n "$DMESG" ]; then
echo " ${WARN} 커널 메시지:"
echo "$DMESG" | sed 's/^/ /'
[ $RESULT -lt 1 ] && RESULT=1
else
echo " ${OK} 이상 없음"
fi
# ── 로그 로테이션 상태 ───────────────────────────────────
if [ "$ROTATE_CHECK" = "true" ]; then
echo
echo "[$SEP] 로그 로테이션 설정"
if [ -f /etc/logrotate.conf ]; then
echo " ${OK} logrotate 설정 존재"
CRON_ROTATE=$(crontab -l 2>/dev/null | grep -i logrotate || \
ls /etc/cron.daily/logrotate 2>/dev/null && echo "cron.daily 설정" || echo "")
[ -n "$CRON_ROTATE" ] && echo " ${OK} logrotate 예약 실행: ${CRON_ROTATE}" || \
echo " ${WARN} logrotate cron 미설정"
else
echo " ${WARN} logrotate 설정 없음"
[ $RESULT -lt 1 ] && RESULT=1
fi
fi
# ── 요약 ─────────────────────────────────────────────────
echo
echo "======================================================"
case $RESULT in
0) echo " 최종 결과: ${OK} 로그 정상" ;;
1) echo " 최종 결과: ${WARN} 주의 항목 있음" ;;
2) echo " 최종 결과: ${CRIT} 심각한 오류 감지" ;;
esac
echo " 점검 완료: $(date '+%Y-%m-%d %H:%M:%S')"
echo "======================================================"
exit $RESULT