设为首页 收藏本站
查看: 735|回复: 0

[经验分享] 在项目中定制python的logging模块的实例

[复制链接]
累计签到:2 天
连续签到:1 天
发表于 2017-5-6 13:29:10 | 显示全部楼层 |阅读模式
  在一个项目中,日志模块是必不可少的,健壮的日志输出有助于及时发现问题和调试。python的日志模块logging为我们提供了强大的日志功能。
  一.logging模块简介
  我们先看一个标准的程序:


import logging
logger=logging.getLogger()
handler=logging.FileHandler("Log_test.txt")
logger.addHandler(handler)
logger.setLevel(logging.NOTSET)
logger.error("This is an error message")
logger.info("This is an info message")
logger.critical("This is a critical message")
   这个程序应用了logging中常用的filehandler,在日志文件中会出现三行内容:
  This is an error message
  This is an info message
  This is a critical message
  上面程序的第2行是生成一个日志对象,里面的参数时日志的名字,可以带,也可以不带。第3行是生成了一个handler,logging支持很多种
Handler,像FileHandler,SocketHandler等待,这里由于我们要写文件,所以用了FileHandler,它的参数就是
filename,默认当前路径,当然我们可以自己指定路径。
  第5行设置日志信息输出的级别。Logging提供了多种日志级别,如
NOTSET,DEBUG,INFO,WARNING,ERROR,CRITICAL等,每个级别都对应一个数值,如果我们不自己设置输出级别,那么系统
会执行缺省级别,值为30,就warning。当写入日志时,小于指定级别的信息将被忽略。因此为了输出想要的日志级别一定要设置好此参数。这里我设为NOTSET(值为0),也就是想输出所有信息。

  关于logging模块的详细介绍,以及程序实例,可以参考这个链接
  http://www.red-dove.com/python_logging.html
  二.实际项目中的应用
  目前我做的一个爬虫项目,程序由计划任务定时执行,程序一旦跑起来就不会天天去关注,所以对日志模块就以下四个要求。
  1.详细的debug信息写入文件,一旦程序出错,可以在文件里面找到详细的出错信息
  2.控制台实时打印重要信息,如一些error和warning
  3.由于程序属于无人监管状态,当一般错误信息达到一定数量后,自动发邮件提醒。
  4.出现重大的错误后,单独发邮件提醒,并挂起程序。如数据库死掉,磁盘阵列无法访问等。
  综合以上的要求,我需要用到logging中得FileHandler(由于日志量会很大,这里需要用到RotatingFileHandler,日志达到设定大小后自动写到另外的文件中),Streamhandler(往控制台输出日志),SMTPHanler(用于致命错误的邮件提醒), MemoryHandler(用于缓存一般错误日志,达到阀值之后自动邮件提醒).
  logging的配置如下:

#encoding=utf-8
import logging
import time
import smtplib
from email.mime.text import MIMEText
import logging.handlers
import os
#日志文件的路径,FileHandler不能创建目录,这里先检查目录是否存在,不存在创建他
#当然也可以继承之后重写FileHandler的构造函数
LOG_FILE_PATH="log/Execution.log"
dir= os.path.dirname(LOG_FILE_PATH)
if not os.path.isdir(dir):
os.mkdir(dir)
#写入文件的日志等级,由于是详细信息,推荐设为debug
FILE_LOG_LEVEL="DEBUG"
#控制台的日照等级,info和warning都可以,可以按实际要求定制
CONSOLE_LOG_LEVEL="INFO"
#缓存日志等级,最好设为error或者critical
MEMOEY_LOG_LEVEL="ERROR"
#致命错误等级
URGENT_LOG_LEVEL="CRITICAL"
#缓存溢出后的邮件标题
ERROR_THRESHOLD_ACHEIVED_MAIL_SUBJECT="Too many errors occurred during the execution"
#缓存溢出的阀值
ERROR_MESSAGE_THRESHOLD=50
#致命错误发生后的邮件标题
CRITICAL_ERROR_ACHEIVED_MAIL_SUBJECT="Fatal error occurred"
#邮件服务器配置
MAIL_HOST="your exchange server"
FROM="from"
MAIL_TO=["address1","address2"]
class OptmizedMemoryHandler(logging.handlers.MemoryHandler):
"""
由于自带的MemoryHandler达到阀值后,每一条缓存信息会单独处理一次,这样如果阀值设的100,
会发出100封邮件,这不是我们希望看到的,所以这里重写了memoryHandler的2个方法,
当达到阀值后,把缓存的错误信息通过一封邮件发出去.
"""
def __init__(self, capacity,mail_subject):
logging.handlers.MemoryHandler.__init__(self, capacity,flushLevel=logging.ERROR, target=None)
self.mail_subject=mail_subject
self.flushed_buffers=[]
def shouldFlush(self, record):
"""
检查是否溢出
"""
if len(self.buffer) >= self.capacity:
return True
else:
return False
def flush(self):
"""
缓存溢出时的操作,
1.发送邮件 2.清空缓存 3.把溢出的缓存存到另一个列表中,方便程序结束的时候读取所有错误并生成报告
"""
if self.buffer!=[] and len(self.buffer) >= self.capacity:
content=""
for record in self.buffer:
message= record.getMessage()
level= record.levelname
ctime= record.created
t=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(ctime))
content+=t+" "+"*"+level+"* : "+message+"\n"
self.mailNotification(self.mail_subject, content)
self.flushed_buffers.extend(self.buffer)
self.buffer = []
def mailNotification(self,subject,content):
"""
发邮件的方法
"""
msg=MIMEText(content)
msg['Subject']=subject
msg['From']=FROM
msg['To']=";".join(MAIL_TO)
try:
s=smtplib.SMTP()
s.connect(MAIL_HOST)
s.sendmail(FROM,MAIL_TO,msg.as_string())
s.close()
except Exception,e:
self.logger.error(str(e))

MAPPING={"CRITICAL" :50,
"ERROR" : 40,
"WARNING" : 30,
"INFO" : 20,
"DEBUG" : 10,
"NOTSET" :0,
}
class logger:
"""
logger的配置
"""
def __init__(self,logFile,file_level,console_level,memory_level,urgent_level):
self.config(logFile, file_level, console_level, memory_level,urgent_level)
def config(self,logFile,file_level,console_level,memory_level,urgent_level):
#生成root logger
self.logger = logging.getLogger("crawler")
self.logger.setLevel(MAPPING[file_level])
#生成RotatingFileHandler,设置文件大小为10M,编码为utf-8,最大文件个数为100个,如果日志文件超过100,则会覆盖最早的日志
self.fh = logging.handlers.RotatingFileHandler(logFile,mode='a', maxBytes=1024*1024*10, backupCount=100, encoding="utf-8")
self.fh.setLevel(MAPPING[file_level])
#生成StreamHandler
self.ch = logging.StreamHandler()
self.ch.setLevel(MAPPING[console_level])  
#生成优化过的MemoryHandler,ERROR_MESSAGE_THRESHOLD是错误日志条数的阀值
self.mh = OptmizedMemoryHandler(ERROR_MESSAGE_THRESHOLD,ERROR_THRESHOLD_ACHEIVED_MAIL_SUBJECT)
self.mh.setLevel(MAPPING[memory_level])
#生成SMTPHandler
self.sh=logging.handlers.SMTPHandler(MAIL_HOST,FROM,";".join(MAIL_TO),CRITICAL_ERROR_ACHEIVED_MAIL_SUBJECT)
self.sh.setLevel(MAPPING[urgent_level])
#设置格式
formatter = logging.Formatter("%(asctime)s *%(levelname)s* : %(message)s",'%Y-%m-%d %H:%M:%S')  
self.ch.setFormatter(formatter)  
self.fh.setFormatter(formatter)
self.mh.setFormatter(formatter)
self.sh.setFormatter(formatter)
#把所有的handler添加到root logger中
self.logger.addHandler(self.ch)  
self.logger.addHandler(self.fh)
self.logger.addHandler(self.mh)
self.logger.addHandler(self.sh)
def debug(self,msg):
if msg is not None:
self.logger.debug(msg)
def info(self,msg):
if msg is not None:
self.logger.info(msg)
def warning(self,msg):
if msg is not None:
self.logger.warning(msg)
def error(self,msg):
if msg is not None:
self.logger.error(msg)
def critical(self,msg):
if msg is not None:
self.logger.critical(msg)
LOG=logger(LOG_FILE_PATH,FILE_LOG_LEVEL,CONSOLE_LOG_LEVEL,MEMOEY_LOG_LEVEL,URGENT_LOG_LEVEL)
if __name__=="__main__":
#测试代码
for i in range(50):
LOG.error(i)
LOG.debug(i)
LOG.critical("Database has gone away")
  
在主程序中,只需要把LOG对象import进去,就可以通过LOG提供的info,debug。。。的方法输入日志。
  当输入一条debug日志,由于等级是最低的,只有RotatingFileHandler的日志等级与之匹配,所以文件中会记录这条debug信息。
  当输入一条error日志时,匹配日志等级,文件中会记录这条日志,控制台中会打印出来,MemoryHandler模块会缓存这条日志,并判断是否达到溢出条件。
  当输入一条critical日志时,匹配日志等级,文件中会记录这条日志,控制台中会打印出来,MemoryHandler模块会缓存这条日志,并判断是否达到溢出条件,同时SMTPHandler会直接发送致命错误邮件提醒。
  使用了这个日志配置之后,我们就可以高枕无忧的干其他事情了,只要没有邮件提醒,程序都在正常运行。。
  一旦收到邮件后,及时查看文件日志,也不难找出错误。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-373871-1-1.html 上篇帖子: S60 Python 编程指南——如何创建pys60应用程序 下篇帖子: 用python做http接口自动化测试框架
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表