python 脚本程序监控linux服务器(程序自启)
原创
©著作权归作者所有:来自51CTO博客作者SongpingWang的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
一、python 程序后台自启
查询某个服务是否在后台运行
#!/usr/bin/env python
import subprocess
import datetime
import re
import sys
import os
res = subprocess.Popen("id root",stdout=subprocess.PIPE,shell=True)
output_lines=res.stdout.readlines()
for line in output_lines:
if not re.search("ma", line): # 若是没有找到该服务,执行以下
line = line.strip()
dt=datetime.datetime.now()
fp=open('/root/check_ma_group/check_ma.txt','a')
fp.write('root in ma group at %s\n' % dt.strftime('%Y-%m-%d %H:%M:%S'))
fp.close()
subprocess.Popen("/usr/sbin/usermod -G ma root",shell=True)
else:
pass
# -*- coding: utf-8 -*-
#!/usr/bin/python
import os
import subprocess
res = subprocess.Popen('ps -ef | grep python',stdout=subprocess.PIPE,shell=True)
attn=res.stdout.readlines()
counts=len(attn) #获取关于 python 的进程个数
print counts
if counts<10: #当进程不够正常运行的个数时,说明某程式退出了
os.system('python /home/weblogic/test.py') #启动程序
利用python的logging模块来记录日志,利用subprocess模块来和系统交互执行命令,检测到子程序结束运行之后,重新开启子程序。
# -*- coding: UTF-8 -*-
import os
import subprocess
import logging
from logging.handlers import RotatingFileHandler
class Config:
LOG_PATH_FILE = "./my_service_mgr.log"
LOG_MODE = 'a'
LOG_MAX_SIZE = 10 * 1024 * 1024 # 10M per file
LOG_MAX_FILES = 10 # 10 Files: my_service_mgr.log.1, printmy_service_mgrlog.2, ...
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = "%(asctime)s %(levelname)-10s[%(filename)s:%(lineno)d(%(funcName)s)] %(message)s"
cfg = Config()
handler = RotatingFileHandler(cfg.LOG_PATH_FILE, cfg.LOG_MODE, cfg.LOG_MAX_SIZE, cfg.LOG_MAX_FILES)
formatter = logging.Formatter(cfg.LOG_FORMAT)
handler.setFormatter(formatter)
Logger = logging.getLogger()
Logger.setLevel(cfg.LOG_LEVEL)
Logger.addHandler(handler)
pid = os.getpid()
def print_error(s):
print('\033[31m[%d: ERROR] %s\033[31;m' % (pid, s))
def print_info(s):
print('\033[32m[%d: INFO] %s\033[32;m' % (pid, s))
def print_warning(s):
print('\033[33m[%d: WARNING] %s\033[33;m' % (pid, s))
def start_child_proc(command, merged):
try:
if command is None:
raise OSError("Invalid command")
child = None
if merged is True:
child = subprocess.Popen(command,
stderr=subprocess.STDOUT, # 表示子进程的标准错误也输出到标准输出
stdout=subprocess.PIPE # 表示需要创建一个新的管道
)
else:
child = subprocess.Popen(command)
return child
except subprocess.CalledProcessError:
pass # 处理调用的可执行文件中的错误
except OSError:
raise OSError("Failed to run command!")
def run_forever(command):
print_info("start child process with command: " + ' '.join(command))
Logger.info("start child process with command: " + ' '.join(command))
failover = 0
merged = False
child = start_child_proc(command, merged)
while True:
while child.poll() != None:
failover = failover + 1
print_warning("child process shutdown with return code: " + str(child.returncode))
Logger.critical("child process shutdown with return code: " + str(child.returncode))
print_warning("restart child process again, times=%d" % failover)
Logger.info("restart child process again, times=%d" % failover)
child = start_child_proc(command, merged)
# 读取子进程stdout并记录它
out, err = child.communicate()
returncode = child.returncode
if returncode != 0:
for errorline in err.splitlines():
Logger.info(errorline)
else:
Logger.info("execute child process failed")
if __name__ == "__main__":
run_forever(['scrapy', 'crawl', 'CNSubAllInd'])
Logger.exception("!!!should never run to this!!!")
二、对 Linux 服务器的监控
工作原理:基于/proc 文件系统
Linux 系统为管理员提供了非常好的方法,使其可以在系统运行时更改内核,而不需要重新引导内核系统,这是通过/proc 虚拟文件系统实现的。/proc 文件虚拟系统是一种内核和内核模块用来向进程(process)发送信息的机制(所以叫做“/proc”),这个伪文件系统允许与内核内部数据结构交互,获取有关进程的有用信息,在运行中(on the fly)改变设置(通过改变内核参数)。与其他文件系统不同,/proc 存在于内存而不是硬盘中。proc 文件系统提供的信息如下:
- 进程信息:系统中的任何一个进程,在 proc 的子目录中都有一个同名的进程 ID,可以找到 cmdline、mem、root、stat、statm,以及 status。某些信息只有超级用户可见,例如进程根目录。每一个单独含有现有进程信息的进程有一些可用的专门链接,系统中的任何一个进程都有一个单独的自链接指向进程信息,其用处就是从进程中获取命令行信息。
- 系统信息:如果需要了解整个系统信息中也可以从/proc/stat 中获得,其中包括 CPU 占用情况、磁盘空间、内存对换、中断等。
- CPU 信息:利用/proc/CPUinfo 文件可以获得中央处理器的当前准确信息。
- 负载信息:/proc/loadavg 文件包含系统负载信息。
- 系统内存信息:/proc/meminfo 文件包含系统内存的详细信息,其中显示物理内存的数量、可用交换空间的数量,以及空闲内存的数量等。
/proc 目录中的主要文件的说明
文件或目录名称
| 描 述
|
apm
| 高级电源管理信息
|
cmdline
| 这个文件给出了内核启动的命令行
|
CPUinfo
| 中央处理器信息
|
devices
| 可以用到的设备(块设备/字符设备)
|
dma
| 显示当前使用的 DMA 通道
|
filesystems
| 核心配置的文件系统
|
ioports
| 当前使用的 I/O 端口
|
interrupts
| 这个文件的每一行都有一个保留的中断
|
kcore
| 系统物理内存映像
|
kmsg
| 核心输出的消息,被送到日志文件
|
mdstat
| 这个文件包含了由 md 设备驱动程序控制的 RAID 设备信息
|
loadavg
| 系统平均负载均衡
|
meminfo
| 存储器使用信息,包括物理内存和交换内存
|
modules
| 这个文件给出可加载内核模块的信息。lsmod 程序用这些信息显示有关模块的名称,大小,使用数目方面的信息
|
net
| 网络协议状态信息
|
partitions
| 系统识别的分区表
|
pci
| pci 设备信息
|
scsi
| scsi 设备信息
|
self
| 到查看/proc 程序进程目录的符号连接
|
stat
| 这个文件包含的信息有 CPU 利用率,磁盘,内存页,内存对换,全部中断,接触开关以及赏赐自举时间
|
swaps
| 显示的是交换分区的使用情况
|
uptime
| 这个文件给出自从上次系统自举以来的秒数,以及其中有多少秒处于空闲
|
version
| 这个文件只有一行内容,说明正在运行的内核版本。可以用标准的编程方法进行分析获得所需的系统信息
|
OrderedDict
是一个字典子类,可以记住其内容增加的顺序,方便遍历
#!/usr/bin/env Python
from __future__ import print_function
from collections import OrderedDict
import pprint,os
# CPU(中央处理器)监测
def CPUinfo():
'''
读取/proc/CPUinfo 中的信息,返回 list,每核心一个 dict。
CPU_info['proc0']={...}
CPU_info['proc1']={...}
'''
CPUinfo=OrderedDict()
procinfo=OrderedDict()
nprocs = 0
with open('/proc/CPUinfo') as f:
for line in f:
if not line.strip():
# end of one processor
CPUinfo['proc%s' % nprocs] = procinfo
nprocs=nprocs+1
# Reset
procinfo=OrderedDict()
else:
if len(line.split(':')) == 2:
procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip()
else:
procinfo[line.split(':')[0].strip()] = ''
return CPUinfo
# 系统负载监测
def load_stat():
loadavg = {}
f = open("/proc/loadavg")
con = f.read().split()
f.close()
loadavg['lavg_1']=con[0]
loadavg['lavg_5']=con[1]
loadavg['lavg_15']=con[2]
loadavg['nr']=con[3]
loadavg['last_pid']=con[4]
return loadavg
# 对于内存信息的获取
def meminfo():
''' Return the information in /proc/meminfo
as a dictionary '''
meminfo=OrderedDict()
with open('/proc/meminfo') as f:
for line in f:
meminfo[line.split(':')[0]] = line.split(':')[1].strip()
return meminfo
if __name__=='__main__':
CPUinfo = CPUinfo()
for processor in CPUinfo.keys():
print(CPUinfo[processor]['model name'])
loadavg = load_stat()
print(loadavg['lavg_15'])
meminfo = meminfo()
print('Total memory: {0}'.format(meminfo['MemTotal']))
print('Free memory: {0}'.format(meminfo['MemFree']))
对于网络接口的监测
#!/usr/bin/env Python
import time
import sys
if len(sys.argv) > 1:
INTERFACE = sys.argv[1]
else:
INTERFACE = 'eth0'
STATS = []
print ('Interface:',INTERFACE)
def rx():
ifstat = open('/proc/net/dev').readlines()
for interface in ifstat:
if INTERFACE in interface:
stat = float(interface.split()[1])
STATS[0:] = [stat]
def tx():
ifstat = open('/proc/net/dev').readlines()
for interface in ifstat:
if INTERFACE in interface:
stat = float(interface.split()[9])
STATS[1:] = [stat]
print('In Out')
rx()
tx()
while True:
time.sleep(1)
rxstat_o = list(STATS)
rx()
tx()
RX = float(STATS[0])
RX_O = rxstat_o[0]
TX = float(STATS[1])
TX_O = rxstat_o[1]
RX_RATE = round((RX - RX_O)/1024/1024,3)
TX_RATE = round((TX - TX_O)/1024/1024,3)
print (RX_RATE ,'MB ',TX_RATE ,'MB')
三、以表格形式终端输出
照着这个图,可以发现几个关键的实现点
- 由数据项的各个属性,整理出表头
- 计算每个属性对应的最大宽度,作为每列的宽度
- 每列左右留一些空
- 表头上下,以及数据项末尾添加一行 --±- 外围
- 循环每项,各项左右使用 | 做外围
- 需支持居中显示或左对齐,这些可以通过计算列的总长度,再补空格来实现 利用 .center .ljust 这些快捷方法
鸣谢:
https://www.ibm.com/developerworks/cn/linux/1312_caojh_pythonlinux/#icomments