使用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求斐波那契数列示例分享
Feb 14 Python
Python中的列表知识点汇总
Apr 14 Python
全面解析Python的While循环语句的使用方法
Oct 13 Python
Flask之flask-script模块使用
Jul 26 Python
使用Python实现跳帧截取视频帧
May 31 Python
Python 虚拟空间的使用代码详解
Jun 10 Python
Python获取统计自己的qq群成员信息的方法
Nov 15 Python
python实现翻译word表格小程序
Feb 27 Python
python实现提取COCO,VOC数据集中特定的类
Mar 10 Python
python实现简单俄罗斯方块
Mar 13 Python
python自动提取文本中的时间(包含中文日期)
Aug 31 Python
python - asyncio异步编程
Apr 06 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
Yii框架中jquery表单验证插件用法示例
2016/10/18 PHP
CodeIgniter框架数据库基本操作示例
2018/05/24 PHP
PHP5.5新特性之yield理解与用法实例分析
2019/01/11 PHP
JavaScript 数组循环引起的思考
2010/01/01 Javascript
AJAX 网页保留浏览器前进后退等功能
2011/02/12 Javascript
查找iframe里元素的方法可传参
2013/09/11 Javascript
js下拉菜单语言选项简单实现
2013/09/23 Javascript
对比分析AngularJS中的$http.post与jQuery.post的区别
2015/02/27 Javascript
理解JavaScript的变量的入门教程
2015/07/07 Javascript
JavaScript修改作用域外变量的方法
2016/03/25 Javascript
jquery动态创建div与input的实例代码
2016/10/12 Javascript
js阻止默认右键的下拉菜单方法
2018/01/02 Javascript
JavaScript中的高级函数
2018/01/04 Javascript
JavaScript中arguments和this对象用法分析
2018/08/08 Javascript
python从入门到精通(DAY 1)
2015/12/20 Python
python 与GO中操作slice,list的方式实例代码
2017/03/20 Python
Python基于递归算法实现的走迷宫问题
2017/08/04 Python
Python解决抛小球问题 求小球下落经历的距离之和示例
2018/02/01 Python
Python实现简单求解给定整数的质因数算法示例
2018/03/25 Python
图文详解python安装Scrapy框架步骤
2019/05/20 Python
python对象转字典的两种实现方式示例
2019/11/07 Python
Python 异步协程函数原理及实例详解
2019/11/13 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
2020/03/10 Python
Python类super()及私有属性原理解析
2020/06/15 Python
Python 在 VSCode 中使用 IPython Kernel 的方法详解
2020/09/05 Python
用python写PDF转换器的实现
2020/10/29 Python
matplotlib常见函数之plt.rcParams、matshow的使用(坐标轴设置)
2021/01/05 Python
CSS3+HTML5+JS 实现一个块的收缩与展开动画效果
2020/11/17 HTML / CSS
Hotels.com印度:酒店预订
2019/05/11 全球购物
法国滑雪假期的专家:Ski Planet
2019/11/02 全球购物
随机分配座位,共50个学生,使学号相邻的同学座位不能相邻
2014/01/18 面试题
农田水利实习自我鉴定
2013/09/19 职场文书
新年团拜会主持词
2014/04/02 职场文书
幼儿园教师的考核评语
2014/04/18 职场文书
导游词之包公祠
2019/11/25 职场文书
一篇文章带你复习java知识点
2021/06/28 Java/Android