獲取程序佔用內存,cpu使用率,服務器ip,程序進程信息並定時生成xml文件

shell腳本編寫

由於工作原因,目前遇到一個問題,要求對程序所在服務器進行實時監控,主要監控程序的CPU利用率,程序的內存佔用率。剛開始考慮用代碼去寫,考慮了下,還得java,再結合linux命令,寫起來有點麻煩,於是想到了直接用shell編寫一個定時腳本。

需求

**文件編碼使用utf-8格式編碼。文件產生頻率爲每5分鐘產生一個文件,新產生的文件覆蓋上一次產生的文件。文件格式爲xml文件,格式樣例如下: **
在這裏插入圖片描述

編寫生成各字段要求的值

#!/bin/bash
#author weixg
#xml文件名
fileName="zhywgl_ywgl_waywgl.xml"
#系統程序名(進程名)
procName="FlowServer"
#版本號
procVersion="1.0"
#最近啓用時間
procStartTime=`ps -eo lstart,command| grep -v 'grep'| grep -w $procName | awk '{print($1" "$2" "$3" "$4" "$5);}'`
#程序接收流量速率
inputRate="-1"
#程序輸出流量速率
outputRate="-1"
#程序接收日誌量大小
inputLog="-1"
#程序輸出日誌量大小
outputLog="-1"
#統計週期,以分鐘爲單位
duration="5"
#提取本服務器的ip地址信息
IP=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"` 
#服務器用戶默認root
psUser=root
#查看進程是否存在
pid=`ps -ef | grep -w $procName | grep -v 'grep' | awk '{print $2;}'`
if [ "$pid" != "" ]; then 
   ProcAlive=1
else
   ProcAlive=0
fi
#cpu使用率
ProcCpu=`ps aux |grep -w $procName | grep -v 'grep'| awk '{print($3);}'`
#程序內存使用率
ProcMem=`ps aux |grep -w $procName | grep -v 'grep'| awk '{print($4);}'` 
#時間戳
Timestamp=`date +%s`
		
echo "fileName is $fileName"
echo "procName is $procName"
echo "procVersion is $procVersion"
echo "inputRate is $inputRate"
echo "outputRate is $outputRate"
echo "inputLog is $inputLog"
echo "outputLog is $outputLog"
echo "duration is $duration"
echo "pid is $pid"
echo "ProcAlive is $ProcAlive"
echo "ProcCpu is $ProcCpu"
echo "ProcMem is $ProcMem"
echo "IP is $IP"
echo "procStartTime is $procStartTime"
echo "Timestamp is $Timestamp"

提取本服務器的ip地址信息

IP=/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"
分析下這個命令:
/sbin/ifconfig -a 查詢本機ip

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.3  netmask 255.255.240.0  broadcast 172.16.15.255
        inet6 fe80::5054:ff:fe68:1c8a  prefixlen 64  scopeid 0x20<link>
        ether 52:54:00:68:1c:8a  txqueuelen 1000  (Ethernet)
        RX packets 13295352  bytes 3943242853 (3.6 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 12367502  bytes 2298562223 (2.1 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 2898759  bytes 338158163 (322.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2898759  bytes 338158163 (322.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

/sbin/ifconfig -a|grep inet 過濾篩選出inet的值

        inet 172.16.0.3  netmask 255.255.240.0  broadcast 172.16.15.255
        inet6 fe80::5054:ff:fe68:1c8a  prefixlen 64  scopeid 0x20<link>
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>

/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1從上一步過濾去掉(反匹配)值爲127.0.0.1的信息

        inet 172.16.0.3  netmask 255.255.240.0  broadcast 172.16.15.255
        inet6 fe80::5054:ff:fe68:1c8a  prefixlen 64  scopeid 0x20<link>
        inet6 ::1  prefixlen 128  scopeid 0x10<host>

/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6 同上一步的作用一樣

       inet 172.16.0.3  netmask 255.255.240.0  broadcast 172.16.15.255

/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk ‘{print $2}’ 輸出第二位的值

     172.16.0.3

/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk ‘{print $2}’|tr -d “addr:” tr -d 的作用是刪除addr字符串,由於沒有,所以從上一步還是返回的ip值

     172.16.0.3

程序存活1</ ProcAlive >

#查看進程是否存在

pid=`ps -ef | grep -w $procName | grep -v 'grep' | awk '{print $2;}'`
if [ "$pid" != "" ]; then 
   ProcAlive=1
else
   ProcAlive=0
fi

$procName是變量名
ps -ef | grep -w $procName
查詢出進程
ps -ef | grep FlowServer

root      5596 15476  0 17:10 pts/1    00:00:00 grep --color=auto FlowServer
root     31207     1  0 Nov13 ?        00:07:05 java -jar /home/java/FlowServer-1.0.jar

過濾 -v (反匹配) 有 ‘grep’的
ps -ef | grep FlowServer | grep -v 'grep’

root     31207     1  0 Nov13 ?        00:07:05 java -jar /home/java/FlowServer-1.0.jar

ps -ef | grep -w FlowServer | grep -v ‘grep’ | awk '{print $2;} 輸出字符串第二位

31207

補充
算術比較運算符 詳情查看[:https://blog.csdn.net/ithomer/article/details/6836382]
(https://blog.csdn.net/ithomer/article/details/6836382)

-eq 等於 [ 3 -eq $mynum ]
-ne 不等於 [ 3 -ne $mynum ]
-lt 小於 [ 3 -lt $mynum ]
-le 小於或等於 [ 3 -le $mynum ]
-gt 大於 [ 3 -gt $mynum ]
-ge 大於或等於 [ 3 -ge $mynum ]

————————————————

程序cpu使用率0.43

#cpu使用率

ProcCpu=ps aux |grep -w $procName | grep -v 'grep'| awk '{print($3);}'

程序內存使用率0.5

#程序內存使用率

ProcMem=ps aux |grep -w $procName | grep -v 'grep'| awk '{print($4);}'

解析:
ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 125492  3696 ?        Ss   Nov04   3:14 /usr/lib/systemd/systemd -
root         2  0.0  0.0      0     0 ?        S    Nov04   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    Nov04   0:04 [ksoftirqd/0]
root     31207  0.0 15.1 3591284 587332 ?      Sl   Nov13   7:05 java -jar /home/java/FlowS

ps aux |grep -w $procName 過濾進程名的信息

root      8478  0.0  0.0 112708  1004 pts/1    S+   17:25   0:00 grep --color=auto -w FlowServer
root     31207  0.0 15.1 3591284 587332 ?      Sl   Nov13   7:05 java -jar /home/java/FlowServer-1.0.jar

ps aux |grep -w $procName | grep -v ‘grep’ 過濾取出含有‘grep’的數據

root     31207  0.0 15.1 3591284 587332 ?      Sl   Nov13   7:05 java -jar /home/java/FlowServer-1.0.jar

ps aux |grep -w $procName | grep -v ‘grep’| awk ‘{print($4);}’ 輸出第四位的數值

15.1

時間戳

Timestamp=date +%s 當前時間 格式爲時間戳

時間命令:date

向date命令傳遞參數適用‘+‘(加號),在傳遞的參數中

%Y表示年

%m表示月

%d表示天

%H表示小時(表示的時間是00-23)

%M表示分鐘

%S表示秒

%s(表示unix時間戳的秒數)

1.1例如 date +%Y-%m-%d

這個在我的機器上面的結果是:

在這裏插入圖片描述
date命令的輸出結果是對當前時間的以傳遞的參數進行格式化

1.2例如date +’%Y-%m-%d %H:%M:%S’
在這裏插入圖片描述

1.3獲取當前時間的unix時間戳

date +%s

在這裏插入圖片描述

1.4使用date命令獲取一個特定時間的unix時間戳

在這裏插入圖片描述

最近啓用時間

procStartTime=ps -eo lstart,command| grep -v 'grep'| grep -w $procName | awk '{print($1" "$2" "$3" "$4" "$5);}'

生成xml腳本

此編碼邏輯是從網上其他大神那裏找到的

#! /bin/bash
#author:weixg
#data:20191120
#filename:create_xml.sh

#從外部傳入的第一個參數作爲xml的文件名
outfile=/var/log/wg/zhywgl_ywgl_waywgl.xml
#xml中的縮進位
tabs=0

# ++++++++++++++++++++++++++++
# 組裝一個節點,輸出到文件
# 說一說傳參數時的這幾個區別:假如有下面這個腳本執行的命令
# /path/to/scriptname  opt1  opt2  opt3  opt4 
# $0: 的值是默認是腳本的名字,從$1-$4 開始就是參數的值
# $# :代表後接的參數『個數』
# $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每個變量是獨立的(用雙引號括起來); 
# $* :代表『 "$1c$2c$3c$4" 』,其中 c 爲分隔字節,默認爲空白鍵, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
# 在shell中我們可以也可以使用${}包含變量名,來調用變量
# ++++++++++++++++++++++++++++
put_head2(){
 echo '<?'${1}'?>' > $outfile
}

put(){
 echo '<'${*}'>' >> $outfile
}

# 這裏也是輸出一個xml的節點,只是比上面的節點有更多的設置
# ${@:2} 的意思:它的值就是由第二個參數開始到最後一個參數,爲什麼要這樣?有時可能你的第二個參數中有空格,shell接受參數是以空格計算的
put_tag(){
   echo '<'$1'>'${@:2}'</'$1'>' >> $outfile
}

 # 同樣是一個輸出節點函數,但是添加了CDATA,防止特殊字符造成xml解析失敗
 put_tag_cdata() {
     echo '<'$1'><![CDATA['${@:2}']]></'$1'>' >> $outfile
 }
 
 put_head(){
     put '?'${1}'?'
 }
 # 這是一個縮進的算法,自行理解
 out_tabs(){
     tmp=0
     tabsstr=""
     while [ $tmp -lt $((tabs)) ]
     do
         tabsstr=${tabsstr}'\t'
         tmp=$((tmp+1))
     done
     echo -e -n $tabsstr >> $outfile
 }
 
 tag_start(){
     out_tabs
     put $1
     tabs=$((tabs+1))
 }
 
 tag() {
     out_tabs
     if [ "$1" == 0 ]
     then
         put_tag $2 $(echo ${@:3})
     elif [ "$1" == 1 ]
     then
         put_tag_cdata $2 $(echo ${@:3})
     fi
 }
 
 tag_end(){
     tabs=$((tabs-1))
     out_tabs
     put '/'${1}
 }

調用方式如下

此處調用是在上面各字段生成的腳本中調用

source '/home/java/create_xml.sh'
put_head2 'xml version='1.0' encoding="GBK"'
tag_start 'Program'
put_tag 'ProcName' "$procName"
put_tag 'ProcVersion' "$procVersion"
put_tag 'ProcAlive' "$ProcAlive"
put_tag 'ProcStartTime' "$procStartTime"
put_tag 'IP' "$IP"
put_tag 'ProcCpu' "$ProcCpu"
put_tag 'ProcMem' "$ProcMem"
put_tag 'InputRate' "$inputRate"
put_tag 'OutputRate' "$outputRate"
put_tag 'InputLog' "$inputLog"
put_tag 'OutputLog' "$outputLog"
put_tag 'Duration' "$duration"
put_tag 'Timestamp' "$Timestamp"
tag_end 'Program'

echo `date +'%Y-%m-%d %H:%M:%S'`+"執行成功!">>/home/java/shLogs.txt

配置定時器

vi /etc/crontab

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
*/5 * * * * root /home/java/wangguan.sh 2> /home/java/log 2>&1

*/5 * * * * root /home/java/wangguan.sh 2> /home/java/log 2>&1

解析該命令:

*/5 * * * * :每五分鐘執行一次該腳本

root :爲用戶

/home/java/wangguan.sh :要執行的腳本

2 :表示標準錯誤,stderr。

> : 代表覆蓋形式寫入

/home/java/log :日誌地址

&1 :文件描述符 1,而1標識標準輸出,stdout。

2>&1: 將標準錯誤重定向到標準輸出

碰到的異常

在執行定時任務的時候,日誌中報出 Permission denied 沒有權限

上網查詢:
linux中,執行sh顯示Permission denied,是由於沒有權限的原因,爲了獲得權限,執行如下命令:

chmod 777 run.sh
其中“run.sh”是我要執行的文件,“chmod 777”是授權語句,“chmod 777 run.sh”的意思是對"run.sh"文件權限進行設置。

在修改定時文件後,要重啓定時服務

service crond start
報異常:Redirecting to /bin/systemctl start crond.service

出現Redirecting to /bin/systemctl start crond.service,
即service crond start 需要替換爲systemctl方式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章