使用Python写个小监控


Posted in Python onJanuary 27, 2016

1.入门

首先你得用过C/C++、java、Javascript等的一种,编程小白估计比较艰难,有一定编程经验的python小白相对简单些。

1.1 Hello World!

Python安装比较简单,到官网上下载安装包,一路下一步就可以了。因为我的服务器上安装的是2.6.6,所以我也下了这个版本。话说2.x的差别不是很大,如果想用3.x,可能下面的代码直接运行不过,不过也差不多,稍微改改即可。
新建一个文件,命名为hello.py。使用python的IDLE打开hello.py,写入以下代码:

print "Hello World!"

按F5,就可以看见输出结果了。

1.2 基本语法

每一行是一条语句。C语言是通过分号”;“;
通过缩进来组织代码块。C语言是通过大括号”{}“;
注释使用井号”#“。

1.3 数据类型、运算符、数据结构

运算符和C语言差不多,C语言有的基本上直接用就可以。
数据类型有数值型,字符串。数据结构有 list, tuple, dict, set。介绍一下tuple, 不能修改,通过索引进行查找。dict类似于map,存放键值对。来看例子,看看tuple使用:

>>> t=(1,2,[1,2])
>>> t[2]
[1, 2]

1.4 流程控制

Python中可以使用if elif else、for和 while 来实现流程控制。同样有 break 和 continue。有一点和C不同,如果有一个分支什么都不做,要使用 pass。例如

list=[0, 1, 2, 3, 4, 5]
for item in list:
  if item == 1:
    print item
  elif item in (2, 3, 4, 5):
    print "aha " + str(item)
  else:
    pass

运行结果是:
1
aha 2
aha 3
aha 4
aha 5

1.5 模块组织

有方法和类。

方法这样定义

def func(var):
   some code here

类和C++等有些不同

class MyClass(object):
  common = 1
  def __init__(self):
    self.myvariable = 5
  def myfunction(self, arg1, arg2):
    return self.myvariable

common变量相当于C++中用 static 修饰的变量,所有类通用;继承也非常简单,可以看看开始推荐的那篇文章。

1.6 异常处理

异常处理非常简单,直接贴代码了:

def some_function():
  try:
    # Division by zero raises an exception
    10 / 0
  except ZeroDivisionError:
    print "Oops, invalid."
  else:
    # Exception didn't occur, we're good.
    pass
  finally:
    # This is executed after the code block is run
    # and all exceptions have been handled, even
    # if a new exception is raised while handling.
    print "We're done with that."

1.7 工程组织

直接引用库,或者从库中引入某一个方法或变量。

import random
from time import clock

2. 数据库查询

既然是监控,免不了和数据库打交道。我使用的是PostgreSQL,所以就介绍一下python怎么调用postgres。

连接postgres首先要安装一个库psycopg2,Windows下直接下载安装即可,注意选对版本。我的服务器是CentOS,安装直接运行

yum install python-psycopg2

就OK了。

2.1 首先创建数据库连接

#get database connect
def get_con():  
  host = '127.0.0.1'
  port = "5432"
  database = 'platform'
  user = 'postgres'
  password = 'postgres'
  conn = psycopg2.connect(database=database, user=user, password=password, host=host, port=port)
  return conn

2.2 执行SQL语句

#执行sql查询
def query(conn, sql):
  cursor = conn.cursor()
  cursor.execute(sql)
  results = cursor.fetchall()
  #close cursor
  cursor.close()
  return results

2.3 然后就可以写具体业务了

def getUsers():
  conn = get_con()#open connect
  sql = """select *
     from t_user
     order by intime DESC
     limit 5"""
  items = query(conn , sql)
  print str(items)
  conn.close() #close connect

注意3个引号”””,就是普通字符串,不过可以换行。

3. 发送邮件

查询到数据之后不能及时通知管理员的话监控就没有意义了。所以我们通过邮件来通知,直接使用python的标准库 smtplib 就可以了。写个发送邮件的函数:

#发送邮件
def send_email(subject, content):
  sender = "yourmail@***.com"
  password = "******" #密码是看不见的哦
  receivers = [tq8117179#163.com] #本人真实邮箱,欢迎发邮件讨论技术问题
  host = "smtp.exmail.qq.com"
  port = 465
  msg = MIMEText(content,'html','utf-8')
  msg['From'] = sender
  msg['To'] = ",".join(receivers)
  msg['Subject'] = Header(subject, 'utf-8')
  try:
    smtp = smtplib.SMTP_SSL(host, port)
    smtp.login(sender, password)
    smtp.sendmail(sender, receivers, msg.as_string())
  except Exception, e:
    logger.error(e)
  logger.info(content)

4.日志

发送邮件时我们使用了logger,这个logger是怎么来的呢?新建一个log.py,代码如下

# coding=utf-8
import logging
import logging.handlers
logger = logging.getLogger('monitor')
logger.setLevel(logging.DEBUG)
filehandler = logging.handlers.TimedRotatingFileHandler( 
    "/mnt/log/monitor/monitor_log", 'midnight', 1, 7)
# 设置文件后缀名称
filehandler.suffix = "%Y%m%d.log"
formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s: %(message)s')
filehandler.setFormatter(formatter)
logger.addHandler(filehandler)
通过logging.getLogger(‘monitor')生成一个logger,然后配置一个文件处理器。
然后在我们监控程序中引用即可:

from log import logger

5. 把可配置信息放到配置文件中

如果我们添加一个管理员怎么办?如果我们的邮箱密码变了怎么办?直接修改python文件啊,哈哈。python不用编译直接改代码就好了,可是我们的程序以后要打包呢,所以最好写个配置文件,python的配置文件读取非常简单,使用python库 ConfigParser 即可:

config = None
#get config
def getConfig():
  global config
  if config is None:
    config = ConfigParser.ConfigParser()
    config.read("monitor.ini")
  return config

然后这样使用:

#get database connect
def get_con():  
  host = getConfig().get('db', 'host')
  port = getConfig().get('db', 'port')
  database = getConfig().get('db', 'database')
  user = getConfig().get('db', 'user')
  password = getConfig().get('db', 'password')
  conn = psycopg2.connect(database=database, user=user, password=password, host=host, port=port)
  return conn
#发送邮件
def send_email(subject, content):
  sender = getConfig().get('mail', 'sender')
  password = getConfig().get('mail', 'password')
  receivers = getConfig().get('mail', 'receivers').split(",")
  host = getConfig().get('mail', 'host')
  port = getConfig().getint('mail', 'port')
  msg = MIMEText(content,'html','utf-8')
  msg['From'] = sender
  msg['To'] = ",".join(receivers)
  msg['Subject'] = Header(subject, 'utf-8')
  try:
    smtp = smtplib.SMTP_SSL(host, port)
    smtp.login(sender, password)
    smtp.sendmail(sender, receivers, msg.as_string())
  except:
    logger.exception("Exception: ")
  logger.info(content)

配置文件是monitor.ini,内容如下:

#数据库配置
[db]
host = 127.0.0.1
port = 5432
database = platform
user = postgres
password = postgres
#邮件配置
[mail]
sender = yourmail@XXX.com
password = ******
#多个联系人用英文逗号隔开
receivers = tq8117179#163.com
host = smtp.exmail.qq.com
port = 465

6. 加点控制

我们每5分钟查一下数据,可是业务sql只能查询最近的几条,所以要加个时间段限制,弄个开始、结束时间。

start_time = "2015-10-1 16:24:24"
end_time = None
#update end_time, invoke before get new data
def update_end_time():
  global end_time
  now = time.mktime(datetime.now().timetuple())
  end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(now))
  return end_time
#update end_time, invoke after get new data
def update_start_time():
  global start_time
  global end_time
  start_time = end_time
  return start_time
getUsers可以改写成:

def getUsers (conn):
  global start_time
  global end_time
  sql = """select *
     from t_user
     where intime>=""" +"'"+start_time+"' and intime<"+"'"+end_time+"';"
  items = query(conn, sql)
  if items is not None and len(items)>0:
    count = len(items)
    tip = "又有"+str(count)+"个用户已经注册了。"+end_time
    send_email(tip, tip+"\n"+str(items))

然后写个统一的调度:

def task():
  #init end_time and start_time, must init end_time first!!!
  end_time = update_end_time()
  start_time = update_start_time()
  #init config
  getConfig()
  while True:
    conn = get_con()   #open connect
    end_time = update_end_time()
    ############## process ##############
    logger.info("query: "+end_time)
    getUsers (conn)
    #do some task else here
    ## end
    update_start_time()
    conn.close()#close connect
    time.sleep(5*60)
  #end of while
def run_monitor():
  monitor = threading.Thread(target=task)
  monitor.start()
if __name__ == "__main__":
  run_monitor()

在task这个函数的while中,首先更新end_time,也就是当前时间;执行完再把start_time更新成刚刚的end_time,这样就不会有漏网之鱼了。还有一个需要注意的地方,关键字global。 在python中,使用全局变量是需要global关键字进行声明的,否则会出问题。

7. 运行

打开linux 控制台,直接运行python monitor.py是可以运行的,可是shell一旦退出,任务也就停止了。于是我就选择了一个进程管理工具:Supervisor。Supervisor 在进程中断时还能自动重启。

7.1. 安装supervisor

首先安装python-setuptools

yum install python-setuptools

安装supervisor

easy_install supervisor

生成supervisor配置文件

echo_supervisord_conf > /etc/supervisord.conf

然后在/etc/supervisord.conf添加:

[program:monitor]
command = python /usr/monitor/monitor.py
directory = /usr/monitor
user = root

7.2. 运行监控

然后在终端中运行supervisord启动supervisor。
在终端中运行supervisorctl,进入shell,运行status查看脚本的运行状态。

7.3. 关闭监控 以及常用命令

以下命令全部在supervisorctl的shell中执行。

  • shutdown 停止Supervisor(子进程也会被停止) ;
  • start monitor 开启monitor进程服务(一旦monitor进程退出,会自启动) ;
  • stop monitor 关闭monitor进程服务 ;
  • restart monitor 关闭正在运行的monitor进程,并且重新启动monitor进程服务 ;
  • reload 重新加载supervisor配置文件 ;
  • exit 退出supervisorctl的shell。

程序基本上就写完了,也可以跑起来了,是不是很酷,大家快点动手实践一下吧!

Python 相关文章推荐
python多线程扫描端口示例
Jan 16 Python
python获取本机mac地址和ip地址的方法
Apr 29 Python
python正则实现计算器功能
Dec 14 Python
python2 与python3的print区别小结
Jan 16 Python
Python单向链表和双向链表原理与用法实例详解
Aug 31 Python
实例介绍Python中整型
Feb 11 Python
python and or用法详解
Jun 26 Python
关于PyTorch 自动求导机制详解
Aug 18 Python
python 和c++实现旋转矩阵到欧拉角的变换方式
Dec 04 Python
python绘制雪景图
Dec 16 Python
使用OpenCV circle函数图像上画圆的示例代码
Dec 27 Python
Pytorch1.5.1版本安装的方法步骤
Dec 31 Python
基于Python实现通过微信搜索功能查看谁把你删除了
Jan 27 #Python
Python图像灰度变换及图像数组操作
Jan 27 #Python
让python在hadoop上跑起来
Jan 27 #Python
CentOS安装pillow报错的解决方法
Jan 27 #Python
python实现文本去重且不打乱原本顺序
Jan 26 #Python
举例讲解Python设计模式编程中的访问者与观察者模式
Jan 26 #Python
Python函数中*args和**kwargs来传递变长参数的用法
Jan 26 #Python
You might like
php项目打包方法
2008/02/18 PHP
phpmyadmin config.inc.php配置示例
2013/08/27 PHP
thinkPHP的表达式查询用法详解
2016/09/14 PHP
PHP调试及性能分析工具Xdebug详解
2017/02/09 PHP
javascript 用原型继承来实现对象系统
2010/03/22 Javascript
用js实现输入提示(自动完成)的实例代码
2013/06/14 Javascript
jquery网页元素拖拽插件效果及实现
2013/08/05 Javascript
JS根据年月获得当月天数的实现代码
2014/07/03 Javascript
JavaScript中使用指数方法Math.exp()的简介
2015/06/15 Javascript
JS和JQuery实现雪花飘落效果
2017/11/30 jQuery
Vue cli构建及项目打包以及出现的问题解决
2018/08/27 Javascript
JS实现的类似微信聊天效果示例
2019/01/29 Javascript
Python语言实现获取主机名根据端口杀死进程
2016/03/31 Python
python 将print输出的内容保存到txt文件中
2018/07/17 Python
使用tensorflow实现线性svm
2018/09/07 Python
Python初学者需要注意的事项小结(python2与python3)
2018/09/26 Python
python操作kafka实践的示例代码
2019/06/19 Python
python二维码操作:对QRCode和MyQR入门详解
2019/06/24 Python
python3调用windows dos命令的例子
2019/08/14 Python
基于Python的自媒体小助手---登录页面的实现代码
2020/06/29 Python
python pyg2plot的原理知识点总结
2021/02/28 Python
摩托车和ATV零件、配件和服装的首选在线零售商:MotoSport
2017/12/22 全球购物
智能钱包:Ekster
2019/11/21 全球购物
静态成员和非静态成员的区别
2012/05/12 面试题
新年联欢会主持词
2014/03/27 职场文书
孝老爱亲模范事迹材料
2014/05/25 职场文书
心理学专业求职信
2014/06/16 职场文书
2014乡镇领导班子四风对照检查材料思想汇报
2014/10/05 职场文书
部门群众路线教育实践活动对照检查材料思想汇报
2014/10/07 职场文书
运动会广播稿200字
2015/08/19 职场文书
安全生产学习心得体会
2016/01/18 职场文书
创业计划书之服装
2019/10/07 职场文书
深入浅析React中diff算法
2021/05/19 Javascript
MySQL触发器的使用
2021/05/24 MySQL
mongoDB数据库索引快速入门指南
2022/03/23 MongoDB
mysql5.5中文乱码问题解决的有用方法
2022/05/30 MySQL