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判断某个用户对某个文件的权限
Oct 13 Python
python字符串str和字节数组相互转化方法
Mar 18 Python
python执行使用shell命令方法分享
Nov 08 Python
tensorflow识别自己手写数字
Mar 14 Python
使用Python操作FTP实现上传和下载的方法
Apr 01 Python
Python中常用的8种字符串操作方法
May 06 Python
PyQt5实现让QScrollArea支持鼠标拖动的操作方法
Jun 19 Python
Python使用matplotlib绘制三维参数曲线操作示例
Sep 10 Python
Python pygame绘制文字制作滚动文字过程解析
Dec 12 Python
Python类的绑定方法和非绑定方法实例解析
Mar 04 Python
python中列表的含义及用法
May 26 Python
python tkinter的消息框模块(messagebox,simpledialog)
Nov 07 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操作Memcache实例介绍
2013/06/14 PHP
以文件形式缓存php变量的方法
2015/06/26 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
php传值和传引用的区别点总结
2019/11/19 PHP
脚本之家贴图转换+转贴工具用到的js代码超级推荐
2007/04/05 Javascript
javascript中的this详解
2014/12/08 Javascript
jQuery鼠标经过方形图片切换成圆边效果代码分享
2015/08/20 Javascript
JS实时弹出新消息提示框并有提示音响起的实现代码
2016/04/20 Javascript
JS去除空格和换行的正则表达式(推荐)
2016/06/14 Javascript
解决bootstrap中使用modal加载kindeditor时弹出层文本框不能输入的问题
2017/06/05 Javascript
jquery animate动画持续运动的实例
2017/11/29 jQuery
javaScript产生随机数的用法小结
2018/04/21 Javascript
浅谈React 服务器端渲染的使用
2018/05/08 Javascript
angular5 子组件监听父组件传入值的变化方法
2018/09/30 Javascript
微信小程序 腾讯地图显示偏差问题解决
2019/07/27 Javascript
微信小程序音乐播放器开发
2019/11/20 Javascript
python虚拟环境 virtualenv的简单使用
2020/01/21 Javascript
vue router返回到指定的路由的场景分析
2020/11/10 Javascript
在vue中使用inheritAttrs实现组件的扩展性介绍
2020/12/07 Vue.js
[38:23]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第一场
2014/05/24 DOTA
[01:43]深扒TI7聊天轮盘语音出处4
2017/05/11 DOTA
python 第三方库的安装及pip的使用详解
2017/05/11 Python
Python 迭代器与生成器实例详解
2017/05/18 Python
itchat接口使用示例
2017/10/23 Python
使用python3调用wxpy模块监控linux日志并定时发送消息给群组或好友
2019/06/05 Python
python实现五子棋人机对战游戏
2020/03/25 Python
Python API len函数操作过程解析
2020/03/05 Python
在python中求分布函数相关的包实例
2020/04/15 Python
html5教程调用绘图api画简单的圆形代码分享
2013/12/04 HTML / CSS
喜诗官方在线巧克力店:See’s Candies
2017/01/01 全球购物
速卖通欧盟:Aliexpress EU
2020/08/19 全球购物
会计专业毕业生求职信分享
2014/01/03 职场文书
护士毕业生自我鉴定
2014/02/08 职场文书
《圆明园的毁灭》教学反思
2014/02/28 职场文书
个人批评与自我批评
2014/10/15 职场文书
离婚上诉状范文
2015/05/23 职场文书