Python中内置的日志模块logging用法详解


Posted in Python onJuly 12, 2016

logging模块简介

Python的logging模块提供了通用的日志系统,可以方便第三方模块或者是应用使用。这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己实现具体的日志记录方式。
logging模块与log4j的机制是一样的,只是具体的实现细节不同。模块提供logger,handler,filter,formatter。

  • logger:提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
  • handler:将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。
  •  filter:提供一种优雅的方式决定一个日志记录是否发送到handler。
  •  formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。

与log4j类似,logger,handler和日志消息的调用可以有具体的日志级别(Level),只有在日志消息的级别大于logger和handler的级别。

logging用法解析

1. 初始化 logger = logging.getLogger("endlesscode"),getLogger()方法后面最好加上所要日志记录的模块名字,后面的日志格式中的%(name)s 对应的是这里的模块名字
2. 设置级别 logger.setLevel(logging.DEBUG),Logging中有NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL这几种级别,日志会记录设置级别以上的日志
3. Handler,常用的是StreamHandler和FileHandler,windows下你可以简单理解为一个是console和文件日志,一个打印在CMD窗口上,一个记录在一个文件上
4. formatter,定义了最终log信息的顺序,结构和内容,我喜欢用这样的格式 '[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S',
%(name)s Logger的名字
%(levelname)s 文本形式的日志级别
%(message)s 用户输出的消息
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(levelno)s 数字形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s  调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
5. 记录 使用object.debug(message)来记录日志
下面来写一个实例,在CMD窗口上只打出error以上级别的日志,但是在日志中打出debug以上的信息

import logging
logger = logging.getLogger("simple_example")
logger.setLevel(logging.DEBUG)
# 建立一个filehandler来把日志记录在文件里,级别为debug以上
fh = logging.FileHandler("spam.log")
fh.setLevel(logging.DEBUG)
# 建立一个streamhandler来把日志打在CMD窗口上,级别为error以上
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# 设置日志格式
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
fh.setFormatter(formatter)
#将相应的handler添加在logger对象中
logger.addHandler(ch)
logger.addHandler(fh)
# 开始打日志
logger.debug("debug message")
logger.info("info message")
logger.warn("warn message")
logger.error("error message")
logger.critical("critical message")

运行一下将会看到CMD窗口只记录两条,spam.log中记录了五条日志

Python中内置的日志模块logging用法详解

当一个项目比较大的时候,不同的文件中都要用到Log,可以考虑将其封装为一个类来使用

#! /usr/bin/env python
#coding=gbk
import logging,os

class Logger:
 def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG):
  self.logger = logging.getLogger(path)
  self.logger.setLevel(logging.DEBUG)
  fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
  #设置CMD日志
  sh = logging.StreamHandler()
  sh.setFormatter(fmt)
  sh.setLevel(clevel)
  #设置文件日志
  fh = logging.FileHandler(path)
  fh.setFormatter(fmt)
  fh.setLevel(Flevel)
  self.logger.addHandler(sh)
  self.logger.addHandler(fh)

 def debug(self,message):
  self.logger.debug(message)

 def info(self,message):
  self.logger.info(message)

 def war(self,message):
  self.logger.warn(message)

 def error(self,message):
  self.logger.error(message)

 def cri(self,message):
  self.logger.critical(message)

if __name__ =='__main__':
 logyyx = Logger('yyx.log',logging.ERROR,logging.DEBUG)
 logyyx.debug('一个debug信息')
 logyyx.info('一个info信息')
 logyyx.war('一个warning信息')
 logyyx.error('一个error信息')
 logyyx.cri('一个致命critical信息')

这样每次使用的时候只要实例化一个对象就可以了

logobj = Logger(‘filename',clevel,Flevel)

如果想在CMD窗口中对于error的日志标红,warning的日志标黄,那么可以使用ctypes模块

Python中内置的日志模块logging用法详解

#! /usr/bin/env python
#coding=gbk
import logging,os
import ctypes

FOREGROUND_WHITE = 0x0007
FOREGROUND_BLUE = 0x01 # text color contains blue.
FOREGROUND_GREEN= 0x02 # text color contains green.
FOREGROUND_RED = 0x04 # text color contains red.
FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN

STD_OUTPUT_HANDLE= -11
std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
def set_color(color, handle=std_out_handle):
 bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
 return bool

class Logger:
 def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG):
  self.logger = logging.getLogger(path)
  self.logger.setLevel(logging.DEBUG)
  fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
  #设置CMD日志
  sh = logging.StreamHandler()
  sh.setFormatter(fmt)
  sh.setLevel(clevel)
  #设置文件日志
  fh = logging.FileHandler(path)
  fh.setFormatter(fmt)
  fh.setLevel(Flevel)
  self.logger.addHandler(sh)
  self.logger.addHandler(fh)

 def debug(self,message):
  self.logger.debug(message)

 def info(self,message):
  self.logger.info(message)

 def war(self,message,color=FOREGROUND_YELLOW):
  set_color(color)
  self.logger.warn(message)
  set_color(FOREGROUND_WHITE)

 def error(self,message,color=FOREGROUND_RED):
  set_color(color)
  self.logger.error(message)
  set_color(FOREGROUND_WHITE)

 def cri(self,message):
  self.logger.critical(message)

if __name__ =='__main__':
 logyyx = Logger('yyx.log',logging.WARNING,logging.DEBUG)
 logyyx.debug('一个debug信息')
 logyyx.info('一个info信息')
 logyyx.war('一个warning信息')
 logyyx.error('一个error信息')
 logyyx.cri('一个致命critical信息')

多模块使用logging
logging模块保证在同一个python解释器内,多次调用logging.getLogger('log_name')都会返回同一个logger实例,即使是在多个模块的情况下。所以典型的多模块场景下使用logging的方式是在main模块中配置logging,这个配置会作用于多个的子模块,然后在其他模块中直接通过getLogger获取Logger对象即可。
配置文件:

[loggers] 
keys=root,main 
 
[handlers] 
keys=consoleHandler,fileHandler 
 
[formatters] 
keys=fmt 
 
[logger_root] 
level=DEBUG 
handlers=consoleHandler 
 
[logger_main] 
level=DEBUG 
qualname=main 
handlers=fileHandler 
 
[handler_consoleHandler] 
class=StreamHandler 
level=DEBUG 
formatter=fmt 
args=(sys.stdout,) 
 
[handler_fileHandler] 
class=logging.handlers.RotatingFileHandler 
level=DEBUG 
formatter=fmt 
args=('tst.log','a',20000,5,) 
 
[formatter_fmt] 
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 
datefmt=

主模块main.py:

import logging 
import logging.config 
 
logging.config.fileConfig('logging.conf') 
root_logger = logging.getLogger('root') 
root_logger.debug('test root logger...') 
 
logger = logging.getLogger('main') 
logger.info('test main logger') 
logger.info('start import module \'mod\'...') 
import mod 
 
logger.debug('let\'s test mod.testLogger()') 
mod.testLogger() 
 
root_logger.info('finish test...')

子模块mod.py:

import logging 
import submod 
 
logger = logging.getLogger('main.mod') 
logger.info('logger of mod say something...') 
 
def testLogger(): 
  logger.debug('this is mod.testLogger...') 
  submod.tst()

子子模块submod.py:

import logging 
 
logger = logging.getLogger('main.mod.submod') 
logger.info('logger of submod say something...') 
 
def tst(): 
  logger.info('this is submod.tst()...')

然后运行python main.py,控制台输出:

2012-03-09 18:22:22,793 - root - DEBUG - test root logger... 
2012-03-09 18:22:22,793 - main - INFO - test main logger 
2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'... 
2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something... 
2012-03-09 18:22:22,809 - main.mod - INFO - logger say something... 
2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger() 
2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger... 
2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()... 
2012-03-09 18:22:22,841 - root - INFO - finish test...

可以看出,和预想的一样,然后在看一下tst.log,logger配置中的输出的目的地:

2012-03-09 18:22:22,793 - main - INFO - test main logger 
2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'... 
2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something... 
2012-03-09 18:22:22,809 - main.mod - INFO - logger say something... 
2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger() 
2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger... 
2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()...

tst.log中没有root logger输出的信息,因为logging.conf中配置了只有main logger及其子logger使用RotatingFileHandler,而root logger是输出到标准输出。

Python 相关文章推荐
Python使用Socket(Https)Post登录百度的实现代码
May 18 Python
Python脚本实现代码行数统计代码分享
Mar 10 Python
Python连接MySQL并使用fetchall()方法过滤特殊字符
Mar 13 Python
python 系统调用的实例详解
Jul 11 Python
Python实现破解12306图片验证码的方法分析
Dec 29 Python
Python获取二维矩阵每列最大值的方法
Apr 03 Python
python re模块的高级用法详解
Jun 06 Python
pandas 数据实现行间计算的方法
Jun 08 Python
Python3.6基于正则实现的计算器示例【无优化简单注释版】
Jun 14 Python
python利用JMeter测试Tornado的多线程
Jan 12 Python
Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释
Jan 25 Python
Python 安装 virturalenv 虚拟环境的教程详解
Feb 21 Python
Swift 3.0在集合类数据结构上的一些新变化总结
Jul 11 #Python
浅析Python的web.py框架中url的设定方法
Jul 11 #Python
深入解析Python的Tornado框架中内置的模板引擎
Jul 11 #Python
使用Python的Tornado框架实现一个Web端图书展示页面
Jul 11 #Python
Windows中使用wxPython和py2exe开发Python的GUI程序的实例教程
Jul 11 #Python
Python的requests网络编程包使用教程
Jul 11 #Python
Python的SQLalchemy模块连接与操作MySQL的基础示例
Jul 11 #Python
You might like
PHP分页函数代码(简单实用型)
2010/12/02 PHP
支持中文字母数字、自定义字体php验证码代码
2012/02/27 PHP
php实现可逆加密的方法
2015/08/11 PHP
jquery的颜色选择插件实例代码
2008/10/02 Javascript
Javascript实现仿WebQQ界面的“浮云”兼容 IE7以上版本及FF
2011/04/27 Javascript
jquery 插件学习(三)
2012/08/06 Javascript
javascript中的取反再取反~~没有意义
2014/04/06 Javascript
Firefox下无法正常显示年份的解决方法
2014/09/04 Javascript
jQuery获得子元素个数的方法
2015/04/14 Javascript
JS实现弹性菜单效果代码
2015/09/07 Javascript
基于node实现websocket协议
2016/04/25 Javascript
JavaScript闭包和范围实例详解
2016/12/19 Javascript
vue.js模仿京东省市区三级联动的选择组件实例代码
2017/11/22 Javascript
webpack搭建vue 项目的步骤
2017/12/27 Javascript
vue中如何让子组件修改父组件数据
2018/06/14 Javascript
微信小程序 wxParse插件显示视频问题
2019/09/27 Javascript
JS前端广告拦截实现原理解析
2020/02/17 Javascript
VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定的数据不能实时更新)
2020/04/03 Javascript
JS创建自定义对象的六种方法总结
2020/12/15 Javascript
python网络编程学习笔记(六):Web客户端访问
2014/06/09 Python
Python 绘图和可视化详细介绍
2017/02/11 Python
Windows 64位下python3安装nltk模块
2018/09/19 Python
Python实现的合并两个有序数组算法示例
2019/03/04 Python
运用PyTorch动手搭建一个共享单车预测器
2019/08/06 Python
在tensorflow中设置使用某一块GPU、多GPU、CPU的操作
2020/02/07 Python
Python3操作读写CSV文件使用包过程解析
2020/04/10 Python
Html5游戏开发之乒乓Ping Pong游戏示例(一)
2013/01/21 HTML / CSS
在线课程:Skillshare
2019/04/02 全球购物
C/C++ 笔试、面试题目大汇总
2015/11/21 面试题
集团公司总经理岗位职责
2013/12/20 职场文书
环保公益广告语
2014/03/13 职场文书
计算机应用专业自荐信
2014/07/05 职场文书
竞选班干部演讲稿600字
2014/08/20 职场文书
大学生读书笔记大全
2015/07/01 职场文书
庆祝教师节主持词
2015/07/06 职场文书
Apache POI的基本使用详解
2021/11/07 Servers