转自:
Linux 服务器系统监控脚本 Shell - 今日头条(www.toutiao.com)
http://www.toutiao.com/i6373134402163048961/
本程序在CentOS 6 下运行成功 其它系统请自行修改参数
monitor_man.sh 主程序
check_http_log.sh Nginx的日志分析模块
check_server.sh 检查Nginx和MySQL的运行状态模块
system_monitor.sh 系统状态模块
一共4个脚本文件 放在一个目录下运行 每段代码都写了注释大家可以一句一句对着学习
######################################################
# File Name文件名: monitor_man.sh
#====================================================
#!/bin/bash
resettem=$(tput sgr0)
#resttem变量的值为 命令(屏幕终端重置回复屏幕默认颜色)
declare -A ssharray
#声明一个关联数组 变量名为ssharray
i=0
#定义一个i变量 值为0 一会儿写循环的时候使用
numbers=""
#定义一个numbers变量值为空值 是一个临时变量一会儿输出的时候会用到
for script_file in $(ls -I monitor_man.sh)
#循环 scrip_file变量的值为 查看文件目录 -I排除 monitor_man.sh的文件名
do
#做…执行
echo -e "\e[1;35m" "这个脚本:" "${i}" '==>' ${resettem} ${script_file}
#-e高亮显示 \e[1;35m 颜色格式 35m粉色 这个脚本 i的值 就是循环的次数 resettem的值 就是恢复屏幕颜色 script_file的值 就是目录下的文件名
grep -E "^\#Program function" ${script_file}
#匹配行 -E多个条件 脚本文件名变量 里面要有Program function这句话
grep -E "^\#程序功能" ${script_file}
#匹配行 -E多个条件 脚本文件名变量 里面要有 程序功能 这句话
ssharray[$i]=${script_file}
#把脚本文件名变量 赋给 关联数组 ssharray[$i]
numbers="${numbers} | ${i}"
#把每个i值 存到临时变量里面 我只需要用他来做一个显示
i=$((i+1))
#i+1目录下的脚本文件有几个就加几次(循环几次)不包括主控脚本monitor_man.sh文件
done
#完成
while true
#while循环 true永远为真(死循环)
do
#做…执行
read -p "请输入一个脚本的序号[ ${numbers} ]:" execshell
#用户输入 -p字符串 请输入一个脚本的序号 number为 i变量所有显示的值 用户输入的内容 赋给execshell变量
if [[ ! ${execshell} =~ ^[0-9]+ ]];then
#如果 这个变量的值 是以非0-9开头 那么
exit 0
#退出脚本 返回错误代码0
fi
#结束
/bin/sh ./${ssharray[$execshell]}
#如果execshell值是数字开头则执行 相应的脚本
done
#完成
######################################################
# File Name文件名: check_http_log.sh
#====================================================
#!/bin/bash
#Program function:Nginx's log analysis
#程序功能:Nginx的日志分析
#脚本实现功能介绍
#功能一:分析HTTP状态码在100-200、200-300、300-400-400-500、500以上的,五个区间的请求条数
#功能二:分析日志中HTTP状态码为404、500的请求条数
resettem=$(tput sgr0) #定义变量resettem 值为 tput sgr0 这个命令的意思是还原之前的屏幕设置 例如颜色
Logfile_path='/home/wwwlogs/access.log' #定义变量Logfile_path 值为Ningx的日志保存路径 lnmp安装的路径/home/wwwlogs/access.log 自己安装的路径一般是 /opt/logs/nginx/access.log
Check_http_status() #定义一个Check_http_status 的函数模块
{
Http_statu_codes=(`cat $Logfile_path | grep -i -o -E "HTTP\/1.[1|0]\" [0-9]{3}" | awk -F "[ ]+" '{
if($2>100 && $2<200)
{i++}
else if($2>=200 && $2<300)
{j++}
else if($2>=300 && $2<400)
{k++}
else if($2>=400 && $2<500)
{n++}
else if($2>=500)
{p++}
}END{
print i?i:0,j?j:0,k?k:0,n?n:0,p?p:0,i+j+k+n+p
}'
`)
#定义变量Http_statu_codes 值为 查看nginx日志文件的路径 匹配行 -i不区分大小写 -o精确输出(只输出想要的内容而不是输出整行) -E支持元字符 awk编程 -F定义可以输入字符串和正则表达式
#如果 输出的第二个变量大于100并且小于200
#i++ 就是说统计101到200之间的数字有多少个
#否则如果 输出的第二个变量大于等于200并且小于300
#j++ 就是说统计200到299之间的数字有多少个
#否则如果 输出的第二个变量大于等于300并且小于400
#k++ 就是说统计300到399之间的数字有多少个
#否则如果 输出的第二个变量大于等于400并且小于500
#n++ 就是说统计400到499之间的数字有多少个
#否则如果 输出的第二个变量大于等于500
#p++ 就是说冬季500及以上的数字有多少个
#END 结束如果
#打印输出 i?判断i是否存在 如果i存在就输出i :不存在就输出0 j k n p 存在就输出值 不存在就输出0 然后i+j+k+n+p就等于总共有多少行数据。
echo -e '\E[33m' "The number of http status[100+] http100+的状态数为:" ${resettem} ${Http_statu_codes[0]}
#显示 颜色 这个100+http的状态数是: ${resettem}清楚屏幕还原默认设置的变量 ${Http_statu_codes[0]} i++的结果数组
echo -e '\E[33m' "The number of http status[200+] http200+的状态数为:" ${resettem} ${Http_statu_codes[1]}
#显示 颜色 这个200+http的状态数是: ${resettem}清楚屏幕还原默认设置的变量 ${Http_statu_codes[1]} j++的结果数组
echo -e '\E[33m' "The number of http status[300+] http300+的状态数为:" ${resettem} ${Http_statu_codes[2]}
#显示 颜色 这个300+http的状态数是: ${resettem}清楚屏幕还原默认设置的变量 ${Http_statu_codes[2]} k++的结果数组
echo -e '\E[33m' "The number of http status[400+] http400+的状态数为:" ${resettem} ${Http_statu_codes[3]}
#显示 颜色 这个400+http的状态数是: ${resettem}清楚屏幕还原默认设置的变量 ${Http_statu_codes[3]} n++的结果数组
echo -e '\E[33m' "The number of http status[500+] http500+的状态数为:" ${resettem} ${Http_statu_codes[4]}
#显示 颜色 这个500+http的状态数是: ${resettem}清楚屏幕还原默认设置的变量 ${Http_statu_codes[4]} p++的结果数组
echo -e '\E[33m' "All request numbers 全部的http状态数为:" ${resettem} ${Http_statu_codes[5]}
#显示 颜色 这个全部http的状态数是: ${resettem}清楚屏幕还原默认设置的变量 ${Http_statu_codes[5]} i+j+k+n+p的结果数组
}
Check_http_code() #定义一个Check_http_code的函数模块
{
Http_Code=(`cat $Logfile_path | grep -i -o -E "HTTP\/1.[1|0]\" [0-9]{3}" | awk -v total=0 -F '[ ]+' '{
if ($2!="")
{code[$2]++;total++}
else
{exit}
}END{
print code[404]?code[404]:0,code[403]?code[403]:0,total
}'
`)
#定义变量Http_statu_codes 值为 查看nginx日志文件的路径 匹配行 -i不区分大小写 -o精确输出(只输出想要的内容而不是输出整行) -E支持元字符 awk编程 -v赋值一个用户定义变量 total变量的值赋为0 -F定义可以输入字符串和正则表达式
#如果第二个变量值不为空值
#code[$2] 就相当于 只里面有code100 code200 code404 每一个变量都计算一下有多少个 ;然后总共的值 有多少个
#否则
#$2为空值的话就退出
#结束如果
#打印输出 code[404]? 判断code[404]是否存在 如果code[404]存在就输出值 code[404]不存在就输出0 403存在输出值不存在输出0 toal变量的值
echo -e '\E[33m' "The number of http status[404] 这个404错误的状态数为:" ${resettem} ${Http_Code[0]}
echo -e '\E[33m' "The number of http status[403] 这个403错误的状态数为:" ${resettem} ${Http_Code[1]}
echo -e '\E[33m' "All request numbers全部的http状态数为:" ${resettem} ${Http_Code[2]}
}
Check_http_status
Check_http_code
echo -e '\E[32m' "帮助信息" ${resettem}
echo -e '\E[31m' "100+表示:信息,服务器收到请求,需要请求者继续执行操作" ${resettem}
echo -e '\E[31m' "200+表示:成功操作被成功接收并处理" ${resettem}
echo -e '\E[31m' "300+表示:重定向,需要进一步的操作以完成请求" ${resettem}
echo -e '\E[31m' "400+表示:客户端错位,请求包含语法错误或无法完成请求" ${resettem}
echo -e '\E[31m' "500+表示:服务器错误,服务器在处理请求的过程中发生了错误" ${resettem}
######################################################
# File Name文件名: check_server.sh
#====================================================
#!/bin/bash
#Program function:To check Nginx and Mysql 's running status.
#程序功能:检查Nginx和MySQL的运行状态
Resettem=$(tput sgr0) #定义Resettem变量 值为 恢复默认设置
Nginxserver='http://192.168.1.245/nginx_status' #定义Nginxserver变量 值为nginx服务器页面的地址
Mysql_Slave_Server='192.168.1.245' #定义Mysql_Slave_Server变量 值为Mysql服务器的IP地址
Mysql_User='root' #定义一个普通用户 值就是普通用户的用户名
Mysql_Pass='root' ##定义普通用户的密码 值就是普通用户的密码
###############################Nginx监控################################
Check_Nginx_Server() #定义一个 Check_Nginx_Server的函数模块
{
Status_code=$(curl -m 5 -s -w %{http_code} ${Nginxserver} -o dev/null)
#定义Status_code变量 值为curl命令 利用url规则在命令行下工作的命令 -m设置最大传输时间5秒 -s静音模式不做杂七杂八的输出 -w显示http对应的状态码 %{http_code}返回状态吗 ${Nginxserver}变量的 值为我服务器nginx服务器的地址 -o把输出写到 回收站中扔掉
if [ $Status_code -eq 000 -o $Status_code -ge 500 ]
#如果 Status_code的值 等于 000 -o或者 Status_code的值 大于等于 500
then
#那么
echo -e '\E[32m' "check http server error!检查HTTP服务器错误! Response status code is响应状态代码" $Resettem $Status_code
#显示 -e激活转义字符 '\E[32m'颜色 检查HTTP错误 Resettem颜色结束 Status_code错误代码的值
else
#否则
Http_content=$(curl -s ${Nginxserver} -o dev/null)
#定义Http_content变量 值为利用url规则 -s静音模式不做杂七杂八的输出 重新再发起一次请求
echo -e '\E[32m' "check http server ok!检查HTTP服务器正常! \n" $Resettem $Http_content
#显示 -e激活转义字符 '\E[32m'颜色 检查http服务正常 \n换行 Resettem恢复颜色变量 Http_content显示正常的返回值
fi
#if结束
}
###############################Mysql监控################################
Check_Mysql_Server() #定义一个 Check_Mysql_Server的函数模块
{
nc -z -w2 ${Mysql_Slave_Server} 3306 &>/dev/null #这个命令要先安装ncat(netcat)工具
#扫描网络命令 -z只做检查端口的测试 -w设置超时时间为 2秒 数据库ip地址变量 端口号 把错误的输出都扔到回收站
if [ $? -eq 0 ];then
#如果 返回值 变量 等于 0 就是为真 ;那么
echo -e '\E[32m' "Connect ${Mysql_Slave_Server} OK! 连接Mysql服务器${Mysql_Slave_Server} 成功!" $Resettem
#显示 连接Mysql服务器成功
if [ $? -eq 0 ];then
#如果 返回值 变量 等于 0 就是为真 ;那么
mysql -u${Mysql_User} -p${Mysql_Pass} -h${Mysql_Slave_Server} -e "show slave status\G" | grep "Slave_IO_Running" | awk '{if($2!="yes"){print "Slave thread not running!从线程没有跑起来 "; exit1}}'
#用myaql的客户端工具通过 普通用户名 密码 服务器IP 连接mysql然后 执行sql的管理语句:show slave status\G获取主从的状态信息 截取Slave_IO_Running行 awk如果第2个变量值不为 yes 打印从线程没有跑起来
if [ $? -eq 0 ];then
#如果 返回值 变量 等于 0 就是为为真 ;那么
mysql -u${Mysql_User} -p${Mysql_Pass} -h${Mysql_Slave_Server} -e "show slave status\G" | grep "Seconds_Behind_Master"
else
echo -e '\E[32m' "Connect ${Mysql_Slave_Server} error! 连接Mysql服务器 ${Mysql_Slave_Server} 失败!" $Resetteesettem
#显示 连接数据库服务器失败
fi
fi
fi
#if结束
}
Check_Nginx_Server #调用函数 一定要写
Check_Mysql_Server #调用函数 一定要写
######################################################
# File Name文件名: system_monitor.sh
#====================================================
#!/bin/bash
#Program function:A Shell Script to Monitor Network,Disk Usage,Uptime,Load Average and RAM Usage in Linux.
#程序功能:在Linux系统中的监控网络,磁盘使用情况,正常运行时间,平均负载和内存使用。
clear #清屏
if [[ $# -eq 0 ]] # $#这个程序的参数个数 整数1 -eq 整数2 判断整数1是否和整数2相等 相等为真
then
# Define Variable reset_terminal 定义变量reset_terminal
reset_terminal=$(tput sgr0) #定一个reset_terminal 值是 屏幕终端重置 还原默认颜色
######################系统环境显示##################################
# Check OS Type 检查系统类型
os=$(uname -o) #定义os变量 值为 uname -o命令 显示系统类型为GNU/Linux ( uname -a 显示系统所有以下行用到uname命令的状态信息)
echo -e '\E[32m' "Operating System Type操作系统类型:" $reset_terminal $os
# Check OS Release Verion and Name 检查系统版本和主机名
os_name=$(cat /etc/issue | grep -e "release") #查看 etc下的issue文件 截取行 -e指定截取里面有release的那一行
echo -e '\E[32m' "Check OS Release Verion and Name 系统版本和主机名:" $reset_terminal $os_name
# Check Architecture 检查CPU架构X86/X64
architecture=$(uname -m) #定义architecture变量 值为 uname -m命令 显示系统CPU架构
echo -e '\E[32m' "Processor Architecture 处理器构架:" $reset_terminal $architecture
# Check Kernel Release 检查系统内核版本
kernelrelease=$(uname -r) #定义kernelrelease变量 值为 uname -r命令 显示系统内核版本
echo -e '\E[32m' "Kernel Release 系统内核版本:" $reset_terminal $kernelrelease
# Check hostname 检查主机名
hostname=$(uname -n) #定义hostname变量 值为 uname -n命令 显示主机名 还有其他方法 set命令提取环境变量文件 set | grep HOSTNAME 截取HOSTNAME行的值就是主机名 echo $HOSTNAME显示环境变量的值
echo -e '\E[32m' "hostname 主机名:" $reset_terminal $hostname
# Check Internal Ip 检查内网IP
internalip=$(hostname -I) #定义intesnalip变量 值为 hostname -I命令 显示内网IP
echo -e '\E[32m' "internal ip 内网IP:" $reset_terminal $internalip
# Check External Ip 检查外网IP
externalip=$(curl -s http://ipecho.net/plain) #利用这个网址返回的我真是的外网IP最准确 因为截取ifcofig和配置文件都不保险可能被别人修改掉
echo -e '\E[32m' "external ip 外网IP:" $reset_terminal $externalip
# Check DNS 检查DNS地址
nameservers=$(cat /etc/resolv.conf | grep -E "\<nameserver[ ]+" | awk '{print $NF}') #查看etc下的resolv.conf配置文件 匹配行 -E支持元字符 截里面有nameserver的行 []+表示里面有多少个空格都匹配上 awk命令 NF表示默认是以空格做为分隔的 打印出最后一列
echo -e '\E[32m' "nameservers DNS域名服务器:" $reset_terminal $nameservers
# Check if connected to Internet or not 检查互联网是否连接
pine -c 2 baidu.com &>/dev/null && echo "Internet:连接正常" || echo "Internet:连接不正常" #利用平命令来判断 -c次数 2次 百度网 &>把结果放入回收站不显示 &&逻辑与前面为真 显示网络OK ||逻辑或 前面为假 显示网络NO
# Check Logged In Users 检查登录用户数
who > /tmp/who #who命令 查看当前登录哪些用户 把结果保存到一个tmp下的who文件里
echo -e '\E[32m' "logged In Users 当前登录的用户:" $reset_terminal && cat /tmp/who
rm -rf /tmp/who #在文件内容显示以后需要把文件删掉以免下次打开的时候脚本判断内容有误 同时也避免产生垃圾
######################n内存判断##################################
system_mem_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}END{print (total-free)/1024}' /proc/meminfo) #定义system_mem_usages 值为 用awk命令匹配MemTotal行 把第2个变量赋给total 匹配MemFree行 把第2个变量 赋给free END结束匹配 用total减去free再除以1024 就算出使用了多少MB的内存 total全部内存 free剩余内存
echo -e '\E[32m' "system memuserages 系统内存总使用量单位(MB):" $reset_terminal $system_mem_usages
apps_mem_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}/^Cached/{cached=$2}/Buffers/{buffers=$2}END{print (total-free-cached-buffers)/1024}' /proc/meminfo) #定义apps_mem_usages 值为 用awk命令匹配MemTotal行 把第2个变量赋给total 匹配MemFree行 把第2个变量赋给free 匹配以Cached开头^的行 把第2个变量赋给cached 匹配Buffers行 把第2个变量赋给buffers END结束匹配 用total减去free减去cached减去buffers再除以1024 就算出应用程序使用了多少MB的内存 total全部内存 free剩余内存 cached缓存 buffers预读内存
echo -e '\E[32m' "apps memuserages 应用程序内存使用量单位(MB):" $reset_terminal $apps_mem_usages
######################CPU负载情况################################
loadaverage=$(top -n 1 -b | grep "load average:" | awk '{print $10 $11 $12}') #定义loadaverage变量 值为 top命令 查看任务管理器 -n 1 读取1次 -b读取完整的信息 grep截取load average行 awk截取打印以空格为分界 第10 11 12个变量
echo -e '\E[32m' "load averages 处理器负载情况(小于1.0轻载,等于1.0满载,大于1.0超载):" $reset_terminal $loadaverage
#####################磁盘使用量##################################
diskaverage=$(df -h -P | grep -v -E 'Filesystem|tmpfs' | awk '{print $1 " " $5 " " $6}') #定义diskaverage变量 值为df -h 查看磁盘状态 -P使输出更加紧凑 grep匹配行 -v反选 -E元字符 过滤掉Filesystem行 和pfs行 awk截取 打印以空格为分界 第1 5 6个变量
echo -e '\E[32m' "disk averages 磁盘使用情况:" $reset_terminal $diskaverage
fi