使用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 相关文章推荐
Python3基础之基本运算符概述
Aug 13 Python
深入理解Python中的元类(metaclass)
Feb 14 Python
python中星号变量的几种特殊用法
Sep 07 Python
Python2实现的LED大数字显示效果示例
Sep 04 Python
python3.4.3下逐行读入txt文本并去重的方法
Apr 29 Python
python代码过长的换行方法
Jul 19 Python
分享Python切分字符串的一个不错方法
Dec 14 Python
Python操作redis实例小结【String、Hash、List、Set等】
May 16 Python
python3+PyQt5 实现Rich文本的行编辑方法
Jun 17 Python
python zip()函数使用方法解析
Oct 31 Python
jupyter 中文乱码设置编码格式 避免控制台输出的解决
Apr 20 Python
pytorch 如何使用amp进行混合精度训练
May 24 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
全国FM电台频率大全 - 4 山西省
2020/03/11 无线电
通过ODBC连接的SQL SERVER实例
2006/10/09 PHP
PHP stream_context_create()作用和用法分析
2011/03/29 PHP
微信公众平台开发关注及取消关注事件的方法
2014/12/23 PHP
linux下php上传文件注意事项
2016/06/11 PHP
用jQuery打造TabPanel效果代码
2010/05/22 Javascript
ASP.NET jQuery 实例1(在TextBox里面创建一个默认提示)
2012/01/13 Javascript
javascript学习笔记(四) Number 数字类型
2012/06/19 Javascript
jQuery中:selected选择器用法实例
2015/01/04 Javascript
基于JavaScript实现移动端点击图片查看大图点击大图隐藏
2015/11/04 Javascript
详解JavaScript UTC时间转换方法
2016/01/07 Javascript
原生JS实现旋转木马式图片轮播插件
2016/04/25 Javascript
移动端使用localStorage缓存Js和css文的方法(web开发)
2016/09/20 Javascript
package.json文件配置详解
2017/06/15 Javascript
vue设置默认首页的操作
2020/08/12 Javascript
[01:10]DOTA2亚洲邀请赛 征战号角响彻全场
2015/01/06 DOTA
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
浅析Python中的多条件排序实现
2016/06/07 Python
python 禁止函数修改列表的实现方法
2017/08/03 Python
python实现xlsx文件分析详解
2018/01/02 Python
Python利用Django如何写restful api接口详解
2018/06/08 Python
用opencv给图片换背景色的示例代码
2020/07/08 Python
canvas绘制圆角头像的实现方法
2019/01/17 HTML / CSS
Sasa莎莎海外旗舰店:香港莎莎美妆平台
2018/03/21 全球购物
We Fashion荷兰:一家国际时装公司
2018/04/18 全球购物
New Balance比利时官方网站:购买鞋子和服装
2021/01/15 全球购物
名词解释型面试题(主要是网络)
2013/12/27 面试题
师范教师专业大学生职业生涯规划范文
2014/03/02 职场文书
会计试用期自我评价怎么写
2014/09/18 职场文书
2014年环保工作总结
2014/11/26 职场文书
公司聚餐通知
2015/04/22 职场文书
2015年暑假工作总结
2015/07/13 职场文书
幼儿园小朋友毕业感言
2015/07/30 职场文书
小学班主任教育随笔
2015/08/15 职场文书
mongodb清除连接和日志的正确方法分享
2021/09/15 MongoDB
JS实现页面炫酷的时钟特效示例
2022/08/14 Javascript