▶︎ 스크립트 설명
- 시스템 기본 정보 수집
- 호스트명, 작동날짜, 시스템 정보
- 마지막 리부팅으로부터 며칠째 운영인지 확인
- 크론탭에 등록된 사용자 작업 점검
- 커널 정보 확인
- 네트워크 인터페이스 조회
- 게이트웨이 정보
- 프로토콜 상태 정보
- 파일시스템 사용량 (용량)
- 파일시스템 사용량 (inode)
- 파일시스템 테이블 확인
- 마운트된 디스크 확인
- CPU 사용량
- 실메모리(RSS) 사용량 확인
- 디스크/메모리 IO 확인
- 해당일 사용자 로그인 정보
/var/log/messages
에서error|fail|warn
조회- 좀비 프로세스 조회
▶︎ 스크립트 작성
‣ 시스템 기본 정보 수집
- 호스트명, 작동날짜, 시스템 정보
• OS 지정
- 시스템 정보 수집 수행에 앞서 현재 시스템의 OS 정보를 파악
#!/usr/bin/bash
HOSTNAME=$(hostname)
UNAME=$(uname)
if [[ "$UNAME" == "Linux" ]]; then
SYSLOG="/var/log/syslog"
else
SYSLOG="/var/log/messages"
fi
RHELID="RedHatEnterpriseServer"
UBUNTUID="Ubuntu"
DEBIANID="Debian"
CENTOSID="CentOS"
• 라인 지정
line()
{
eval printf %.0s\= '{1..'${COLUMNS:-$(tput cols)}'}'; echo
}
eval
- 인자로 주어진 문자열을 셸 명령으로 평가. 여기서는
eval
을 사용해 뒤에 나오는 명령을 실행함.
- 인자로 주어진 문자열을 셸 명령으로 평가. 여기서는
printf %.0s\=
- 포맷에 따라 출력을 생성. 여기서
%.0s\=
는 빈 문자열(.0s
)을 0번 출력하라는 의미. 즉, 포맷 문자열 안에서%s
가 무시됨 - 대신
=
가 출력된다.
- 포맷에 따라 출력을 생성. 여기서
'{1..'${COLUMNS:-$(tput cols)}'}'
- 브레이스 확장을 사용해 특정 숫자까지의 범위를 생성
$COLUMNS
는 현재 터미널의 가로 크기를 나타내는 환경 변수이다. 만약COLUMNS
가 설정되어 있지 않다면$(tput cols)
를 사용해 터미널의 가로 크기를 가져온다.tput cols
는 현재 터미널의 가로 크기르 반환하는 명령이다.- 즉 1부터
CULUMNS
값까지의 숫자 시퀀스를 생성. 이 숫자 시퀀스는printf
에 의해 각 숫자마다=
문자를 출력하는데 사용됨.
• 섹션 구분
section()
{
line
printf "%*s\n" $(( (${#1}+$(tput cols)) /2 )) "$1"
line
}
"%*s\n"
: 해당 포맷 문자열은 다음을 의미함.%*s
: 가변 폭 필드 너비를 사용하여 문자열을 출력.*
는 필드 너비를 의미.s
는 문자열을 의미\n
: 줄바꿈 문자 출력
$(( (${#1} + $(tput cols)) /2 ))
: 필드 너비 계산${#1}
: 함수의 첫 번째 인자의 길이를 구함.$(tput cols)
: 터미널의 가로 크기 구함.${#1}
+$(tput cols)
: 인자의 길이와 터미널 가로 크기 더함.(${#1} + $(tput cols)) /2
: 이를 2로 나눠서 중앙에 정렬할 위치 계산
$1
: 함수의 첫 번째 인자를 출력할 문자열로 사용.
• 타이틀 출력
title()
{
eval printf %.0s\# '{1..'${COLUMNS:-$(tput cols)}'}'; echo
echo
section "LINUX SERVER STATUS CHECK"
echo -e "#### Author : jaehyojjang.dev"
echo -e "Release : 2024.02.04"
echo -e "Require : Root Permission"
echo
eval printf %.0s\# '{1..'${COLUMNS:-$(tput cols)}'}'; echo
}
• 날짜 출력
cur_date()
{
echo `date`
}
• 시스템 정보 출력
sysinfo()
{
echo "HOSTNAME : " "$HOSTNAME"
echo "CHECK DATE : " cur_date
echo "SYSTEM : " "$UNAME"
}
‣ 부팅 후 경과시간 출력
pmcheck()
{
UPTIME=`awk '{print int($1)}' /proc/uptime`
PMTIME=$((UPTIME / 86400))
line
echo 'UPTIME SINCE LAST REBOOT : ' ${PMTIME} 'days'
}
/proc/uptime
파일에서 부팅 후 경과 시간을 초 단위로 읽어와UPTIME
변수에 저장.UPTIME
값을 일(day) 단위로 변환하여PMTIME
변수에 저장.
‣ 크론탭에 등록된 사용자 작업 점검
croninfo()
{
section 'Crontab list'
echo `for user in $(grep /bin/bash /etc/passwd | cut -f1 -d:); do crontab -u $user -l; done`
echo 'tab content check'
}
‣ 커널 정보 출력
kernelchk()
{
line
echo 'Kernel version : '`uname -o -r -v`
}
‣ 네트워크 인터페이스 조회
networkchk()
{
section 'Network Interface check'
ifconfig
}
‣ 게이트웨이 정보
routechk()
{
section 'Default route'
route
}
‣ 프로토콜 정보
protocolinfo()
{
section 'Protocol statistics'
netstat -s
}
‣ 파일 시스템 사용량 조회
- 파일시스템 용량, inode, swap 정보 조회
fsinfo()
{
section 'File system information (human readable)'
df -h
section 'File system information (Inode)'
df -i
section 'Swap information'
swapon -s
}
‣ 파일 시스템 테이블 조회
diskinfo()
{
section "/etc/fstab entry"
cat /etc/fstab
section "Mounted disk"
mount -l
}
‣ CPU 사용량 조회
cpuusage()
{
section "CPU Usage"
index=0
mpstat -P ALL > ./cpu.txt
while read line; do
# 컬럼 제거
if [[ "$index" -gt 1 ]]; then
echo $line
fi
index=$(( $index +1 ))
done < ./cpu.txt
section "CPU Idle alert"
idle_limit=10.0
cpu_idle=$(mpstat 1 5 | tail -n 1 | awk '{print $NF}')
is_alert=$(echo "$cpu_idle < $idle_limit" | bc)
if [[ "$is_alert" -eq 1 ]]; then
date_str=$(date '+%Y/%m/%d %H:%M:%S')
echo "[$date_str] CPU %idle Alert: $cpu_idle(%)"
else
echo "No Alert"
fi
rm ./cpu.txt
}
is_alert
echo "$cpu_idle < $idle_limit"
: 비교식을 문자열로 만든다.| bc
:bc
명령을 사용하여 비교식을 평가함.bc
는 수치 비교를 수행하고, 결과를is_alert
변수에 저장.- 결과는
1(참)
또는0(거짓)
으로 출력된다.
‣ 실메모리 사용량 확인
memoryusage()
{
section "Memory Usage"
TOTAL=`free | grep ^Mem | awk '{print $2}'`
USED1=`free | grep ^Mem | awk '{print $3}'`
USED2=`free | grep ^-/+ | awk '{print $3}'`
NOMINAL=$((100*USED1/TOTAL))
ACTUAL=$((100*USED2/TOTAL))
echo NOMINAL=${NOMINAL}% ACTUAL=${ACTUAL}%
}
<br.
‣ 디스크/메모리 IO 확인
iousage()
{
section "IO Stat"
index=0
iostat ALL > ./ios.txt
while read line; do
if [[ "$index" -gt 1 ]]; then
echo "$line"
fi
index=$(( $index+1 ))
done < ./ios.txt
rm ./ios.txt
}
‣ 해당일 사용자 로그인 정보
lastchk()
{
section "Last log"
td=`date +"%a %b %e"`
echo $td
last | grep -i "$td"
}
‣ 로그 메시지 점검
/var/log/messages
에서error|fail|warn
추출
errorchk()
{
section "${SYSLOG} error check"
"$(cat $SYSLOG | grep -Ei "(fail|error|warn)")"
}
‣ 좀비 프로세스 조회
zombiechk()
{
section "Zombie process check"
NOZ="$(ps -ef | grep defunct | gre -v grep | wc -l)"
echo "Number of Zombie : $NOZ"
if [[ "$NOZ" -gt 0 ]]; then
section "Zombie process list"
ps -ef | grep 'defunct' | grep -v 'grep'
fi
}
‣ 스크립트 Usage 작성
- 스크립트의 원활한 사용을 위한 가이드 작성
usage()
{
echo "Usage : check_sys.sh [--save {filename} | --print] "
echo "Options : \"--save filename\" will save log to filename"
echo " \"--save \" will save log to systemchk_{TODAY}.log"
echo " \"--print\" will print log on screen"
echo " \"--help\" show this help screen"
}
▶︎ 전체 스크립트
HOSTNAME=`hostname`
UNAME=`uname`
if [ ${UNAME} == "Linux" ]
then
SYSLOG="/var/log/syslog"
else
SYSLOG="/var/log/messages"
fi
RHELID="RedHatEnterpriseServer"
UBUNTUID="Ubuntu"
DEBIANID="Debian"
CENTOSID="CentOS"
### 라인 지정
line()
{
eval printf %.0s\= '{1..'${COLUMNS:-$(tput cols)}'}'; echo
#eval printf %.0s\= '{1..'${COLUMNS:-80}'}'; echo
}
### 섹션 구분
section()
{
line
printf "%*s\n" $(((${#1}+$(tput cols))/2)) "$1"
line
}
### 제목 지정
title()
{
eval printf %.0s\# '{1..'${COLUMNS:-$(tput cols)}'}'; echo
echo
section "LINUX SERVER STATUS CHECK"
echo -e "#### Author : jaehyojjang.dev"
echo -e "Release : 2024.02.04"
echo -e "Require : Root Permission"
echo
eval printf %.0s\# '{1..'${COLUMNS:-$(tput cols)}'}'; echo
}
### 날짜 추출
cur_date()
{
echo `date`
}
### 시스템 정보 출력
sysinfo()
{
echo "HOSTNAME : " "$HOSTNAME"
echo "CHECK DATE : " cur_date
echo "SYSTEM : " "$UNAME"
}
### 부팅 후 경과시간 출력
pmcheck()
{
UPTIME=`awk '{print int($1)}' /proc/uptime`
PMTIME=$((UPTIME / 86400))
line
echo 'UPTIME SINCE LAST REBOOT : ' ${PMTIME} 'days'
}
### 크론탭 작업 목록 점검
croninfo()
{
section 'Crontab list'
echo `for user in $(grep /bin/bash /etc/passwd | cut -f1 -d:); do crontab -u $user -l; done`
echo 'tab content check'
}
### 커널 정보 출력
kernelchk()
{
line
echo 'Kernel version : '`uname -o -r -v`
}
### 네트워크 인터페이스 조회
networkchk()
{
section 'Network Interface check'
ifconfig
}
### 게이트웨이 정보
routechk()
{
section 'Default route'
route
}
### 프로토콜 정보
protocolinfo()
{
section 'Protocol statistics'
netstat -s
}
### 파일 시스템 사용량 조회
fsinfo()
{
section 'File system information (human readable)'
df -h
section 'File system information (Inode)'
df -i
section 'Swap information'
swapon -s
}
### 파일 시스템 테이블 조회
diskinfo()
{
section "/etc/fstab entry"
cat /etc/fstab
section "Mounted disk"
mount -l
}
### 시스템 정보 전체 출력 함수
basicchk()
{
sysinfo
pmcheck
kernelchk
kdumpchk
croninfo
networkchk
routechk
protocolinfo
diskinfo
fsinfo
}
### CPU 사용량 조회
cpuusage()
{
section "CPU Usage"
index=0
mpstat -P ALL > ./cpu.txt
while read line; do
# 컬럼 제거
if [[ "$index" -gt 1 ]]; then
echo $line
fi
index=$(( $index +1 ))
done < ./cpu.txt
section "CPU Idle alert"
idle_limit=10.0
cpu_idle=$(mpstat 1 5 | tail -n 1 | awk '{print $NF}')
is_alert=$(echo "$cpu_idle < $idle_limit" | bc)
if [[ "$is_alert" -eq 1 ]]; then
date_str=$(date '+%Y/%m/%d %H:%M:%S')
echo "[$date_str] CPU %idle Alert: $cpu_idle(%)"
else
echo "No Alert"
fi
rm ./cpu.txt
}
### 실 메모리 사용량 확인
memoryusage()
{
section "Memory Usage"
TOTAL=`free | grep ^Mem | awk '{print $2}'`
USED1=`free | grep ^Mem | awk '{print $3}'`
USED2=`free | grep ^-/+ | awk '{print $3}'`
NOMINAL=$((100*USED1/TOTAL))
ACTUAL=$((100*USED2/TOTAL))
echo NOMINAL=${NOMINAL}% ACTUAL=${ACTUAL}%
}
### 디스크/메모리 IO 확인
iousage()
{
section "IO Stat"
index=0
iostat ALL > ./ios.txt
while read line; do
if [[ "$index" -gt 1 ]]; then
echo "$line"
fi
index=$(( $index+1 ))
done < ./ios.txt
rm ./ios.txt
}
### 해당일 사용자 로그인 정보
lastchk()
{
section "Last log"
td=`date +"%a %b %e"`
echo $td
last | grep -i "$td"
}
### 로그 메시지 점검
errorchk()
{
section "${SYSLOG} error check"
"$(cat $SYSLOG | grep -Ei "(fail|error|warn)")"
}
### 좀비 프로세스 체크
zombiechk()
{
section "Zombie process check"
NOZ="$(ps -ef | grep defunct | gre -v grep | wc -l)"
echo "Number of Zombie : $NOZ"
if [[ "$NOZ" -gt 0 ]]; then
section "Zombie process list"
ps -ef | grep 'defunct' | grep -v 'grep'
fi
}
### 사용량 전부 출력 함수
usagechk()
{
cpuusage
memoryusage
iousage
vmstatchk
lastchk
zombiechk
errorchk
}
### USAGE
usage()
{
echo "Usage : check_sys.sh [--save {filename} | --print] "
echo "Options : \"--save filename\" will save log to filename"
echo " \"--save \" will save log to systemchk_{TODAY}.log"
echo " \"--print\" will print log on screen"
echo " \"--help\" show this help screen"
}
if [[ "$#" -lt 1 ]]; then
usage
else
case $1 in
"--save" )
if [[ -z "$2" ]]; then
filedate="$(date +'%Y%m%d-%H%M%S')"
file="${HOSTNAME}_$filedate.log"
elif [[ -f "$2" ]]; then
usage
echo "Already exists $2"
else
file=$2
fi
title >> "$file" 2>&1
basicchk >> "$file" 2>&1
usagechk >> "$file" 2>&1
;;
"--print" )
clear
title
basicchk
usagechk
;;
"--help" )
usage
exit
;;
esac
fi