用户工具

站点工具


modules:logging

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

modules:logging [2014/05/25 05:20] (当前版本)
行 1: 行 1:
 +====== Python Logging 模块使用方法======
 +
 +logging模块是Python自带的日志模块,原来一直没怎么用,在GAE里面用logging比较多,后来有个GAE的项目想转到Linux服务器上面,发现logging模块还挺不错的。
 +
 +收集了一些网上的资料,记录如下。
 +
 +===== 1. 简单的将日志打印到屏幕 =====
 +<code python>
 +import logging
 +
 +logging.debug('​This is debug message'​)
 +logging.info('​This is info message'​)
 +logging.warning('​This is warning message'​)
 +</​code>​
 + 
 +屏幕上打印:​
 +<​code>​
 +WARNING:​root:​This is warning message
 +</​code>​
 +
 +默认情况下,logging将日志打印到屏幕,日志级别为WARNING;
 +
 +日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,当然也可以自己定义日志级别。
 +
 +{{:​modules:​python-logging-levle.png|}}
 +
 +===== 2. 使用basicConfig配置logging日志行为=====
 +<code python>
 +import logging
 +
 +logging.basicConfig(level=logging.DEBUG,​
 +                format='​%(asctime)s %(filename)s[line:​%(lineno)d] %(levelname)s %(message)s',​
 +                datefmt='​%a,​ %d %b %Y %H:​%M:​%S',​
 +                filename='​myapp.log',​
 +                filemode='​w'​)
 +    ​
 +logging.debug('​This is debug message'​)
 +logging.info('​This is info message'​)
 +logging.warning('​This is warning message'​)
 +</​code>​
 +
 +./​myapp.log文件中内容为:​
 +<​code>​
 +Sun, 24 May 2009 21:48:54 demo2.py[line:​11] DEBUG This is debug message
 +Sun, 24 May 2009 21:48:54 demo2.py[line:​12] INFO This is info message
 +Sun, 24 May 2009 21:48:54 demo2.py[line:​13] WARNING This is warning message
 +</​code>​
 +
 +logging.basicConfig函数各参数:​
 +
 +<​code>​
 +filename: 指定日志文件名
 +filemode: 和file函数意义相同,指定日志文件的打开模式,'​w'​或'​a'​
 +format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:​
 + ​%(levelno)s:​ 打印日志级别的数值
 + ​%(levelname)s:​ 打印日志级别名称
 + ​%(pathname)s:​ 打印当前执行程序的路径,其实就是sys.argv[0]
 + ​%(filename)s:​ 打印当前执行程序名
 + ​%(funcName)s:​ 打印日志的当前函数
 + ​%(lineno)d:​ 打印日志的当前行号
 + ​%(asctime)s:​ 打印日志的时间
 + ​%(thread)d:​ 打印线程ID
 + ​%(threadName)s:​ 打印线程名称
 + ​%(process)d:​ 打印进程ID
 + ​%(message)s:​ 打印日志信息
 +datefmt: 指定时间格式,同time.strftime()
 +level: 设置日志级别,默认为logging.WARNING
 +stream: 指定将日志的输出流,可以指定输出到sys.stderr,​sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
 +</​code>​
 +
 +===== 3 将日志信息同时输出到文件和屏幕 =====
 +<​code>​
 +import logging
 +
 +logging.basicConfig(level=logging.DEBUG,​
 +                format='​%(asctime)s %(filename)s[line:​%(lineno)d] %(levelname)s %(message)s',​
 +                datefmt='​%a,​ %d %b %Y %H:​%M:​%S',​
 +                filename='​myapp.log',​
 +                filemode='​w'​)
 +
 +#################################################################################################​
 +#​定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象#​
 +console = logging.StreamHandler()
 +console.setLevel(logging.INFO)
 +formatter = logging.Formatter('​%(name)-12s:​ %(levelname)-8s %(message)s'​)
 +console.setFormatter(formatter)
 +logging.getLogger(''​).addHandler(console)
 +#################################################################################################​
 +
 +logging.debug('​This is debug message'​)
 +logging.info('​This is info message'​)
 +logging.warning('​This is warning message'​)
 +</​code>​
 +
 +屏幕上打印:​
 +<​code>​
 +root        : INFO     This is info message
 +root        : WARNING ​ This is warning message
 +</​code>​
 +./​myapp.log文件中内容为:​
 +<​code>​
 +Sun, 24 May 2009 21:48:54 demo2.py[line:​11] DEBUG This is debug message
 +Sun, 24 May 2009 21:48:54 demo2.py[line:​12] INFO This is info message
 +Sun, 24 May 2009 21:48:54 demo2.py[line:​13] WARNING This is warning message
 +</​code>​
 +
 +===== 4.logging之日志回滚 ​ =====
 +
 +<code python>
 +import logging
 +from logging.handlers import RotatingFileHandler
 +
 +#################################################################################################​
 +#​定义一个RotatingFileHandler,最多备份5个日志文件,每个日志文件最大10M
 +Rthandler = RotatingFileHandler('​myapp.log',​ maxBytes=10*1024*1024,​backupCount=5)
 +Rthandler.setLevel(logging.INFO)
 +formatter = logging.Formatter('​%(name)-12s:​ %(levelname)-8s %(message)s'​)
 +Rthandler.setFormatter(formatter)
 +logging.getLogger(''​).addHandler(Rthandler)
 +################################################################################################​
 +</​code>​
 +
 +从上例和本例可以看出,logging有一个日志处理的主对象,其它处理方式都是通过addHandler添加进去的。
 +
 +logging的几种handle方式如下:
 +
 +<​code>​
 +logging.StreamHandler:​ 日志输出到流,可以是sys.stderr、sys.stdout或者文件
 +logging.FileHandler:​ 日志输出到文件
 +日志回滚方式,实际使用时用RotatingFileHandler和TimedRotatingFileHandler
 +logging.handlers.BaseRotatingHandler
 +logging.handlers.RotatingFileHandler
 +logging.handlers.TimedRotatingFileHandler
 +logging.handlers.SocketHandler:​ 远程输出日志到TCP/​IP sockets
 +logging.handlers.DatagramHandler: ​ 远程输出日志到UDP sockets
 +logging.handlers.SMTPHandler: ​ 远程输出日志到邮件地址
 +logging.handlers.SysLogHandler:​ 日志输出到syslog
 +logging.handlers.NTEventLogHandler:​ 远程输出日志到Windows NT/​2000/​XP的事件日志
 +logging.handlers.MemoryHandler:​ 日志输出到内存中的制定buffer
 +logging.handlers.HTTPHandler:​ 通过"​GET"​或"​POST"​远程输出到HTTP服务器
 +
 +</​code>​
 +
 +由于StreamHandler和FileHandler是常用的日志处理方式,所以直接包含在logging模块中,而其他方式则包含在logging.handlers模块中,
 +上述其它处理方式的使用请参见python2.5手册!
 +
 +===== 5.通过logging.config模块配置日志 =====
 +
 +<​code>​
 +#​logger.conf
 +###############################################​
 +[loggers]
 +keys=root,​example01,​example02
 +[logger_root]
 +level=DEBUG
 +handlers=hand01,​hand02
 +[logger_example01]
 +handlers=hand01,​hand02
 +qualname=example01
 +propagate=0
 +[logger_example02]
 +handlers=hand01,​hand03
 +qualname=example02
 +propagate=0
 +###############################################​
 +[handlers]
 +keys=hand01,​hand02,​hand03
 +[handler_hand01]
 +class=StreamHandler
 +level=INFO
 +formatter=form02
 +args=(sys.stderr,​)
 +[handler_hand02]
 +class=FileHandler
 +level=DEBUG
 +formatter=form01
 +args=('​myapp.log',​ '​a'​)
 +[handler_hand03]
 +class=handlers.RotatingFileHandler
 +level=INFO
 +formatter=form02
 +args=('​myapp.log',​ '​a',​ 10*1024*1024,​ 5)
 +###############################################​
 +[formatters]
 +keys=form01,​form02
 +[formatter_form01]
 +format=%(asctime)s %(filename)s[line:​%(lineno)d] %(levelname)s %(message)s
 +datefmt=%a, %d %b %Y %H:%M:%S
 +[formatter_form02]
 +format=%(name)-12s:​ %(levelname)-8s %(message)s
 +datefmt=
 +</​code>​
 +
 +
 +上例3:
 +
 +<code python>
 +import logging
 +import logging.config
 +
 +logging.config.fileConfig("​logger.conf"​)
 +logger = logging.getLogger("​example01"​)
 +
 +logger.debug('​This is debug message'​)
 +logger.info('​This is info message'​)
 +logger.warning('​This is warning message'​)
 +</​code>​
 +
 +上例4:
 +
 +<code python>
 +import logging
 +import logging.config
 +
 +logging.config.fileConfig("​logger.conf"​)
 +logger = logging.getLogger("​example02"​)
 +
 +logger.debug('​This is debug message'​)
 +logger.info('​This is info message'​)
 +logger.warning('​This is warning message'​)
 +</​code>​
 +===== 6.logging是线程安全的 =====
 +
 +在多线程环境中,使用logging时不需要额外的线程冲突考虑。
 +
 +===== 关于root logger以及logger的父子关系 =====
 +
 +
 +前面多次提到root logger, 实际上logger实例之间还有父子关系, root logger就是处于最顶层的logger, 它是所有logger的祖先。如下图: ​
 +
 +{{:​modules:​python-logger-root.png|}}
 +
 +root logger是默认的logger
 +
 +如果不创建logger实例, 直接调用logging.debug()、logging.info()logging.warning()、logging.error()、logging.critical()这些函数,
 +
 +那么使用的logger就是 root logger, 它可以自动创建,也是单实例的。
 +
 +
 +如何得到root logger
 +
 +通过logging.getLogger()或者logging.getLogger(""​)得到root logger实例。
 +
 +
 +默认的level
 +
 +root logger默认的level是logging.WARNING
 +
 +
 +如何表示父子关系
 +
 +logger的name的命名方式可以表示logger之间的父子关系. 比如:
 +
 +<code python>
 +parent_logger = logging.getLogger('​foo'​)
 +child_logger = logging.getLogger('​foo.bar'​)
 +</​code>​
 +
 +什么是effective level
 +
 +logger有一个概念,叫effective level。 如果一个logger没有显示地设置level,那么它就用父亲的level。如果父亲也没有显示地设置level, 就用父亲的父亲的level,以此推....
 +
 +最后到达root logger,一定设置过level。默认为logging.WARNING。
 +
 +child loggers得到消息后,既把消息分发给它的handler处理,也会传递给所有祖先logger处理, ​
 +
 +
 +来看一个例子 ​
 +<code python>
 + 
 +import logging
 +
 +# 设置root logger
 +r = logging.getLogger()
 +ch = logging.StreamHandler()
 +ch.setLevel(logging.DEBUG)
 +formatter = logging.Formatter('​%(asctime)s - %(levelname)s - %(message)s'​)
 +ch.setFormatter(formatter)
 +r.addHandler(ch)
 +
 +# 创建一个logger作为父亲
 +p = logging.getLogger('​foo'​)
 +p.setLevel(logging.DEBUG)
 +ch = logging.StreamHandler()
 +ch.setLevel(logging.DEBUG)
 +formatter = logging.Formatter('​%(asctime)s - %(message)s'​)
 +ch.setFormatter(formatter)
 +p.addHandler(ch)
 +
 +# 创建一个孩子logger
 +c = logging.getLogger('​foo.bar'​)
 +c.debug('​foo'​)  ​
 +</​code>​
 +
 +输出如下:
 +
 +<​code>​
 +2011-08-31 21:​04:​29,​893 - foo
 +2011-08-31 21:​04:​29,​893 - DEBUG - foo
 +</​code>​
 +
 +可见, 孩子logger没有任何handler,所以对消息不做处理。但是它把消息转发给了它的父
 +亲以及root logger。最后输出两条日志。
  
modules/logging.txt · 最后更改: 2014/05/25 05:20 (外部编辑)