#!/bin/bash
# ============================================================
# GUARDiA SM | system_health.sh
# 대상: 모든 Linux 서버
# 내용: CPU / 메모리 / 디스크 / 네트워크 I/O / 로드 평균
# 파라미터: DISK_WARN=80 DISK_CRIT=90 MEM_WARN=85 CPU_WARN=90
# ============================================================
set -euo pipefail
DISK_WARN=${DISK_WARN:-80}; DISK_CRIT=${DISK_CRIT:-90}
MEM_WARN=${MEM_WARN:-85};   CPU_WARN=${CPU_WARN:-90}
SEP="─────────────────────────────────────────"
OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]"
RESULT=0   # 0=OK 1=WARN 2=CRIT

echo "======================================================"
echo " GUARDiA SM 점검 | 시스템 리소스 | $(hostname -s)"
echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')"
echo "======================================================"

# ── 1. CPU 로드 ───────────────────────────────────────────
echo; echo "[$SEP] 1. CPU / 로드 평균"
CORES=$(nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo)
LOAD1=$(awk '{print $1}' /proc/loadavg)
LOAD5=$(awk '{print $2}' /proc/loadavg)
LOAD15=$(awk '{print $3}' /proc/loadavg)
# CPU 사용률 (1초 샘플)
CPU_IDLE=$(top -bn2 -d0.5 | grep "Cpu(s)" | tail -1 | awk '{for(i=1;i<=NF;i++) if($i~/%id/) print $(i-1)}' | tr -d ',')
CPU_USE=$(echo "100 - ${CPU_IDLE:-0}" | bc 2>/dev/null || echo "N/A")
echo " CPU 코어 수  : ${CORES}"
echo " 로드 평균    : ${LOAD1} / ${LOAD5} / ${LOAD15}  (1/5/15분)"
echo " CPU 사용률   : ${CPU_USE}%"
LOAD_THRESH=$(echo "$CORES * 2" | bc)
if awk "BEGIN{exit !($LOAD5 > $LOAD_THRESH)}" 2>/dev/null; then
    echo " 로드 상태    : ${CRIT} 로드 평균이 코어 수 2배 초과 (${LOAD5} > ${LOAD_THRESH})"
    RESULT=2
elif awk "BEGIN{exit !($LOAD5 > $CORES)}" 2>/dev/null; then
    echo " 로드 상태    : ${WARN} 로드 평균이 코어 수 초과 (${LOAD5} > ${CORES})"
    [ $RESULT -lt 1 ] && RESULT=1
else
    echo " 로드 상태    : ${OK}"
fi

# ── 2. 메모리 ────────────────────────────────────────────
echo; echo "[$SEP] 2. 메모리"
MEM_TOTAL=$(awk '/MemTotal/{print $2}' /proc/meminfo)
MEM_AVAIL=$(awk '/MemAvailable/{print $2}' /proc/meminfo)
MEM_FREE=$(awk '/MemFree/{print $2}' /proc/meminfo)
MEM_BUFCACHE=$(( $(awk '/Buffers/{print $2}' /proc/meminfo) + $(awk '/^Cached:/{print $2}' /proc/meminfo) ))
MEM_USED=$(( MEM_TOTAL - MEM_AVAIL ))
MEM_PCT=$(( MEM_USED * 100 / MEM_TOTAL ))
SWAP_TOTAL=$(awk '/SwapTotal/{print $2}' /proc/meminfo)
SWAP_FREE=$(awk '/SwapFree/{print $2}' /proc/meminfo)
SWAP_USED=$(( SWAP_TOTAL - SWAP_FREE ))
echo " 전체 메모리  : $(( MEM_TOTAL / 1024 )) MB"
echo " 사용 메모리  : $(( MEM_USED / 1024 )) MB  (${MEM_PCT}%)"
echo " 가용 메모리  : $(( MEM_AVAIL / 1024 )) MB"
echo " 버퍼/캐시    : $(( MEM_BUFCACHE / 1024 )) MB"
[ $SWAP_TOTAL -gt 0 ] && echo " 스왑 사용    : $(( SWAP_USED / 1024 )) MB / $(( SWAP_TOTAL / 1024 )) MB"
if [ $MEM_PCT -ge $((MEM_WARN + 10)) ]; then
    echo " 메모리 상태  : ${CRIT} ${MEM_PCT}% 사용 중"
    RESULT=2
elif [ $MEM_PCT -ge $MEM_WARN ]; then
    echo " 메모리 상태  : ${WARN} ${MEM_PCT}% 사용 중"
    [ $RESULT -lt 1 ] && RESULT=1
else
    echo " 메모리 상태  : ${OK} ${MEM_PCT}%"
fi

# ── 3. 디스크 ────────────────────────────────────────────
echo; echo "[$SEP] 3. 디스크 사용량"
DF_OUT=$(df -h --output=source,size,used,avail,pcent,target 2>/dev/null | grep -v tmpfs | grep -v udev | grep -v "Filesystem")
echo "$DF_OUT" | head -1 | awk '{printf " %-20s %6s %6s %6s %5s  %s\n","마운트포인트","전체","사용","가용","사용%","장치"}'
echo "$DF_OUT" | while read line; do
    PCENT=$(echo "$line" | awk '{print $5}' | tr -d '%')
    MP=$(echo "$line" | awk '{print $6}')
    if [ -n "$PCENT" ] && [ "$PCENT" -ge $DISK_CRIT ] 2>/dev/null; then
        echo " ${CRIT} $line"
        echo "DISK_CRIT_FOUND" >/tmp/.guardia_disk_crit_$$
    elif [ -n "$PCENT" ] && [ "$PCENT" -ge $DISK_WARN ] 2>/dev/null; then
        echo " ${WARN} $line"
    else
        echo " ${OK}   $line"
    fi
done
[ -f /tmp/.guardia_disk_crit_$$ ] && { RESULT=2; rm -f /tmp/.guardia_disk_crit_$$; }

# ── 4. 주요 마운트 inode ─────────────────────────────────
echo; echo "[$SEP] 4. inode 사용률"
df -i 2>/dev/null | grep -v tmpfs | grep -v udev | tail -n +2 | while read line; do
    IPCT=$(echo "$line" | awk '{print $5}' | tr -d '%')
    if [ -n "$IPCT" ] && [ "$IPCT" -ge 90 ] 2>/dev/null; then
        echo " ${WARN} inode 부족: $line"
    fi
done
echo " inode 점검 완료"

# ── 5. 네트워크 I/O ──────────────────────────────────────
echo; echo "[$SEP] 5. 네트워크 인터페이스"
ip -s link show 2>/dev/null | awk '
/^[0-9]+:/{name=$2; gsub(/:$/,"",name)}
/RX:/{rx_bytes=0; getline; rx_bytes=$1}
/TX:/{tx_bytes=0; getline; tx_bytes=$1;
  if (name != "lo") printf " %-12s  RX: %s bytes  TX: %s bytes\n", name, rx_bytes, tx_bytes}' \
  | head -5

# ── 6. 상위 프로세스 (CPU) ──────────────────────────────
echo; echo "[$SEP] 6. CPU 상위 5개 프로세스"
ps aux --sort=-%cpu 2>/dev/null | awk 'NR==1{print " ",$0} NR>1 && NR<=6{printf " %-8s %5s%% %5s%%  %s\n",$1,$3,$4,substr($0,index($0,$11))}' 2>/dev/null || \
ps -eo user,pcpu,pmem,comm --sort=-pcpu 2>/dev/null | head -6 | awk '{printf " %-10s %5s%% %5s%%  %s\n",$1,$2,$3,$4}'

# ── 7. 열린 파일 수 ──────────────────────────────────────
echo; echo "[$SEP] 7. 파일 디스크립터"
OPEN_FILES=$(ls /proc/*/fd 2>/dev/null | wc -l)
MAX_FILES=$(cat /proc/sys/fs/file-max 2>/dev/null || echo "N/A")
echo " 열린 파일 수  : ${OPEN_FILES}"
echo " 시스템 최대   : ${MAX_FILES}"

# ── 8. 최근 커널 OOM ─────────────────────────────────────
echo; echo "[$SEP] 8. OOM / 커널 오류 (최근 1시간)"
OOM=$(dmesg --since="1 hour ago" 2>/dev/null | grep -i "oom\|out of memory\|killed process" | tail -5 || true)
if [ -n "$OOM" ]; then
    echo " ${WARN} OOM 이벤트 감지:"
    echo "$OOM" | sed 's/^/   /'
    [ $RESULT -lt 1 ] && RESULT=1
else
    echo " ${OK} OOM 없음"
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
