zioinfo-mail/workspace/guardia-itsm/scripts/sm/search/search_solr_sm.sh
DESKTOP-TKLFCPR\ython cfe2901a55 refactor(structure): consolidate all projects under workspace/
- itsm/    -> workspace/guardia-itsm/
- manager/ -> workspace/guardia-manager/
- app/     -> workspace/guardia-messenger/
- manual/  -> workspace/guardia-docs/

workspace/zioinfo-web/ unchanged.
git mv preserves full commit history.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:50:56 +09:00

152 lines
6.9 KiB
Bash

#!/bin/bash
# ============================================================
# GUARDiA SM | search_solr_sm.sh
# 대상: Apache Solr (7.x / 8.x / 9.x)
# 파라미터: SOLR_HOME=/opt/solr SOLR_HOST=localhost SOLR_PORT=8983
# SOLR_USER=solr SOLR_PASS=SolrRocks
# QUERY_TIME_WARN=1000
# ============================================================
set -euo pipefail
SOLR_HOME=${SOLR_HOME:-/opt/solr}
SOLR_HOST=${SOLR_HOST:-localhost}
SOLR_PORT=${SOLR_PORT:-8983}
SOLR_USER=${SOLR_USER:-""}
SOLR_PASS=${SOLR_PASS:-""}
QUERY_TIME_WARN=${QUERY_TIME_WARN:-1000}
SOLR_BASE="http://${SOLR_HOST}:${SOLR_PORT}"
OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]"
SEP="─────────────────────────────────────────"
RESULT=0
_solr() {
local URL="$1"
local AUTH=""
[ -n "$SOLR_USER" ] && AUTH="-u ${SOLR_USER}:${SOLR_PASS}"
curl -sk --max-time 10 $AUTH "${SOLR_BASE}${URL}" 2>/dev/null
}
echo "======================================================"
echo " GUARDiA SM 점검 | Apache Solr | $(hostname -s)"
echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')"
echo "======================================================"
# ── 1. 프로세스 ───────────────────────────────────────────
echo; echo "[$SEP] 1. Solr 프로세스"
SOLR_PROC=$(pgrep -f "solr\|start.jar" 2>/dev/null | wc -l || echo 0)
if [ "$SOLR_PROC" -gt 0 ]; then
SOLR_PID=$(pgrep -f "solr" | head -1)
echo " ${OK} Solr 실행 중 (PID: ${SOLR_PID})"
RSS_MB=$(awk '/VmRSS/{print $2}' /proc/${SOLR_PID}/status 2>/dev/null | \
awk '{printf "%d", $1/1024}' || echo "N/A")
echo " RSS 메모리: ${RSS_MB} MB"
else
echo " ${CRIT} Solr 프로세스 없음"
RESULT=2
fi
# ── 2. 포트 리스닝 ────────────────────────────────────────
echo; echo "[$SEP] 2. 포트 리스닝"
ss -tlnp 2>/dev/null | grep -q ":${SOLR_PORT} " && \
echo " ${OK} 포트 ${SOLR_PORT} LISTEN" || \
{ echo " ${CRIT} 포트 ${SOLR_PORT} LISTEN 없음"; RESULT=2; }
# ── 3. 시스템 정보 ────────────────────────────────────────
echo; echo "[$SEP] 3. Solr 시스템 정보"
if command -v curl &>/dev/null; then
SYS=$(_solr "/solr/admin/info/system?wt=json")
if [ -n "$SYS" ]; then
SOLR_VER=$(echo "$SYS" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(d.get('lucene',{}).get('solr-spec-version','?'))" 2>/dev/null)
UPTIME=$(echo "$SYS" | python3 -c \
"import sys,json; d=json.load(sys.stdin); ms=d.get('jvm',{}).get('jmx',{}).get('upTimeMS',0); \
h=ms//3600000; m=(ms%3600000)//60000; print(f'{h}h {m}m')" 2>/dev/null || echo "N/A")
echo " ${OK} Solr 버전: ${SOLR_VER}, 가동 시간: ${UPTIME}"
# JVM 힙
HEAP=$(echo "$SYS" | python3 -c \
"import sys,json; d=json.load(sys.stdin); jvm=d.get('jvm',{}).get('memory',{}).get('raw',{}); \
used=jvm.get('used',0)//1048576; max_=jvm.get('max',1)//1048576; \
pct=used*100//max_ if max_>0 else 0; print(f'used={used}MB max={max_}MB ({pct}%)')" 2>/dev/null)
echo " JVM 힙: ${HEAP}"
if echo "$HEAP" | grep -oP '\d+(?=%)' | awk '{exit !($1>=85)}'; then
echo " ${WARN} JVM 힙 사용률 85% 초과"
[ $RESULT -lt 1 ] && RESULT=1
fi
else
echo " ${CRIT} Solr 응답 없음"
RESULT=2
fi
fi
# ── 4. 코어/컬렉션 상태 ─────────────────────────────────
echo; echo "[$SEP] 4. 코어/컬렉션 상태"
if command -v curl &>/dev/null; then
CORES=$(_solr "/solr/admin/cores?wt=json&indexInfo=false")
if [ -n "$CORES" ]; then
CORE_LIST=$(echo "$CORES" | python3 -c "
import sys, json
d = json.load(sys.stdin)
status = d.get('status', {})
for name, info in status.items():
sz = info.get('index', {}).get('sizeInBytes', 0) // 1048576
docs = info.get('index', {}).get('numDocs', 0)
print(f' {name:20s} docs={docs:>10,d} size={sz}MB')
" 2>/dev/null || echo " 파싱 실패")
echo "$CORE_LIST"
CORE_COUNT=$(echo "$CORES" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(len(d.get('status',{})))" 2>/dev/null)
echo " 총 코어 수: ${CORE_COUNT}"
fi
fi
# ── 5. 쿼리 성능 통계 ────────────────────────────────────
echo; echo "[$SEP] 5. 쿼리 성능 통계"
if command -v curl &>/dev/null; then
# 첫 번째 코어의 성능 지표
FIRST_CORE=$(echo "$CORES" 2>/dev/null | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(list(d.get('status',{}).keys())[0])" 2>/dev/null || echo "")
if [ -n "$FIRST_CORE" ]; then
METRICS=$(_solr "/solr/${FIRST_CORE}/admin/mbeans?stats=true&cat=QUERYHANDLER&wt=json")
AVG_TIME=$(echo "$METRICS" | python3 -c "
import sys, json
d = json.load(sys.stdin)
beans = d.get('solr-mbeans', [])
for i in range(0, len(beans), 2):
if beans[i] == 'QUERYHANDLER':
handlers = beans[i+1] if i+1 < len(beans) else {}
for name, stats in handlers.items():
if '/select' in name:
qs = stats.get('stats', {})
avg = qs.get('avgTimePerRequest', 0)
rpc = qs.get('requests', 0)
print(f' /select: requests={rpc} avg={avg:.1f}ms')
" 2>/dev/null || echo " 쿼리 통계 없음")
echo "$AVG_TIME"
fi
fi
# ── 6. 로그 오류 ─────────────────────────────────────────
echo; echo "[$SEP] 6. 로그 오류"
for LOGDIR in "${SOLR_HOME}/server/logs" "${SOLR_HOME}/logs" "/var/log/solr"; do
if [ -d "$LOGDIR" ]; then
LOGFILE=$(ls -t "${LOGDIR}"/solr.log 2>/dev/null | head -1 || echo "")
if [ -n "$LOGFILE" ] && [ -r "$LOGFILE" ]; then
ERR=$(tail -1000 "$LOGFILE" | grep -cE "ERROR|WARN|Exception" || echo 0)
echo " 최근 오류/경고: ${ERR}건 (${LOGFILE})"
tail -1000 "$LOGFILE" | grep -E "ERROR|WARN" | tail -5 | sed 's/^/ /' || true
fi
break
fi
done
# ── 요약 ─────────────────────────────────────────────────
echo
echo "======================================================"
case $RESULT in
0) echo " 최종 결과: ${OK} Solr 정상" ;;
1) echo " 최종 결과: ${WARN} 주의 항목 있음" ;;
2) echo " 최종 결과: ${CRIT} 즉시 조치 필요" ;;
esac
echo " 점검 완료: $(date '+%Y-%m-%d %H:%M:%S')"
echo "======================================================"
exit $RESULT