关于 logging 的一些琐事
来源:互联网 发布:vb如何反编译exe 编辑:程序博客网 时间:2024/05/22 04:46
http://www.keakon.net/2013/02/21/%E5%85%B3%E4%BA%8Elogging%E7%9A%84%E4%B8%80%E4%BA%9B%E7%90%90%E4%BA%8B
懒得分段了,想到哪写到哪吧。
- 为什么 logging.info() 默认不输出任何东西?
因为默认生成的 root logger 的 level 是 logging.WARNING,低于该级别的就不输出了。可以进行如下设置来输出:
如果还没配置 handler 的话,可以用 logging.basicConfig() 来配置:>>> import logging>>> logging.info('test')>>> root_logger = logging.getLogger() # 或使用未公开的 logging.root>>> root_logger.level30>>> logging.getLevelName(30)'WARNING'>>> root_logger.level = logging.NOTSET>>> logging.info('test')INFO:root:test
>>> root_logger.handlers[]>>> logging.basicConfig(level=logging.NOTSET)>>> root_logger.handlers[<logging.StreamHandler object at 0x108becd10>]>>> logging.info('test')INFO:root:test
- 如何定制输出的格式?
给 logger 的 handler 设置一个 logging.Formatter 对象:
如果还没配置 handler 的话,可以用 logging.basicConfig() 来配置:>>> root_logger.handlers[0].formatter.format<bound method Formatter.format of <logging.Formatter object at 0x10c062d90>>>>> root_logger.handlers[0].formatter.datefmt>>> root_logger.handlers[0].formatter._fmt'%(levelname)s:%(name)s:%(message)s'>>> LOGGING_FORMAT = '[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d] %(message)s'>>> DATE_FORMAT = '%y%m%d %H:%M:%S'>>> formatter = logging.Formatter(LOGGING_FORMAT, DATE_FORMAT)>>> root_logger.handlers[0].formatter = formatter>>> logging.info('test')[I 130221 01:58:28 <stdin>:1] test
详细的格式介绍就查看文档吧。logging.basicConfig( level=logging.NOTSET, format=LOGGING_FORMAT, datefmt=DATE_FORMAT)
- 为什么我重定向了 stdout,但是却看不到输出?
因为默认生成的 root logger 的 handler 的 stream 是 stderr,不是 stdout:
可以如下分别配置:>>> root_logger.handlers[0].stream<open file '<stderr>', mode 'w' at 0x1089cb270>
stdout_handler = logging.StreamHandler(sys.__stdout__)stdout_handler.level = logging.DEBUGstdout_handler.formatter = formatterroot_logger.addHandler(stdout_handler)stderr_handler = logging.StreamHandler(sys.__stderr__)stderr_handler.level = logging.WARNINGstderr_handler.formatter = formatterroot_logger.addHandler(stderr_handler)
- 如何将日志输出到文件?
使用 logging.FileHandler():
其中文件名可以使用相对路径,但要保证文件夹存在。默认的文件打开方式是 append。handler = logging.FileHandler('log/test.log')root_logger.addHandler(handler)
如果还没配置 handler 的话,可以用 logging.basicConfig() 来配置:logging.basicConfig( level=logging.NOTSET, format=LOGGING_FORMAT, datefmt=DATE_FORMAT, filename='log/test.log', filemode='a')
- 捕捉了一个异常,如何输出执行堆栈?
使用 logging.exception(),或在调用 logging.debug() 等方法时加上 exc_info=True 参数。>>> try:... 0 / 0... except:... logging.exception('Catch an exception.')... print '-' * 10... logging.warning('Catch an exception.', exc_info=True)... ERROR:root:Catch an exception.Traceback (most recent call last): File "<stdin>", line 2, in <module>ZeroDivisionError: integer division or modulo by zero----------WARNING:root:Catch an exception.Traceback (most recent call last): File "<stdin>", line 2, in <module>ZeroDivisionError: integer division or modulo by zero
- 能不能针对不同的用途或模块,指定不同的日志?
可以创建多个 logger:
每个 logger 都有个名字,以 '.' 来划分继承关系。名字为空的就是 root_logger,console_logger 的名字是 'test',因此 root_logger 是 console_logger 的 parent;而 file_logger 的名字是 'test.file',因此 console_logger 是 file_logger 的 parent。console_handler = logging.StreamHandler(sys. __stdout__)console_handler.level = logging.DEBUGconsole_logger = logging.getLogger('test')console_logger.addHandler(console_handler)file_handler = logging.FileHandler('log/test.log')file_handler.level = logging.WARNINGfile_logger = logging.getLogger('test.file')file_logger.addHandler(file_handler)console_logger.error('test')file_logger.error('test')console_logger.parent is root_loggerfile_logger.parent is console_loggerconsole_logger.getChild('file') is file_logger
如果 logger 的 propagate 属性为 True(默认值),则它的记录也会传到父 logger。因此,file_logger 在记录到文件的同时,也会在 stdout 输出日志。
建议每个模块都用自己的 logger。 - 如何指定某些记录不输出?
使用 logging.Filter 来过滤记录:import loggingimport randomclass OddFilter(logging.Filter): def __init__(self): self.count = 0 def filter(self, record): self.count += 1 if record.args[0] & 1: record.count = self.count # 给 record 增加了 count 属性 return True # 为 True 的记录才输出 return Falseroot_logger = logging.getLogger()logging.basicConfig(level=logging.NOTSET, format='%(message)s (total: %(count)d)') # 可以使用 record.count 来格式化root_logger.level = logging.NOTSETroot_logger.addFilter(OddFilter())for i in xrange(100): logging.error('number: %d', random.randint(0, 1000))
- 单个日志文件太大怎么分卷?
可以使用 logging.handlers.RotatingFileHandler 和 logging.handlers.TimedRotatingFileHandler。前者按文件大小来分割,后者按时间来分割。
它们会在达到分割条件时(文件达到指定大小或达到指定时间),把当前的日志重命名为备份文件,然后再打开新文件来记录。
值得一提的是,如果备份文件名已存在,就会被删除。所以在多进程时不建议使用。我是将日志输出到 stdout 和 stderr,再用 supervisor 来分割日志。
此外还有一些没考虑到的特殊情况,建议使用前读读源码,然后自行实现。 - logging 是线程安全的么?
是的,handler 内部使用了 threading.RLock() 来保证同一时间只有一个线程能够输出。
但是,在使用 logging.FileHandler 时,多进程同时写一个日志文件是不支持的。 - logging 的流程是怎样的?
这里有张流程图可以参考:
- 关于 logging 的一些琐事
- 关于数据存储的一些琐事
- 关于数据存储的一些琐事
- 西游记的一些琐事
- openwrt的一些琐事
- openwrt的一些琐事
- Tomcat的一些琐事
- 最近的一些琐事
- 一些烦人的琐事
- [OpenWrt] openwrt的一些琐事
- [OpenWrt] DreamBox的一些琐事
- [OpenWrt] openwrt的一些琐事
- [OpenWrt] openwrt的一些琐事
- 一些琐事
- 关于gradle的那些闲碎琐事
- 关于 log4j.jar 和 commons-logging.jar 的一些记录
- 一些关于logging部分的代码笔记以及讲解
- 生活中一些琐事
- Python正则表达式--无捕获组和命名组
- 讯飞的语音识别技术VC源码
- SqlServer数据类型、C#SqlDbType对应关系及转换
- BoradcastReceiver 研究
- cocos2d-x配置Android项目相关事宜
- 关于 logging 的一些琐事
- git checkout -B android 5648d4e 不行啊。
- ONGL表达式的用法(精)
- Python的map函数实现代码
- ActiveMQ5.0实战三:使用Spring发送,消费topic和queue消息
- html常见问题
- 欧拉图
- linux ubuntu 安装更新卸载软件
- 中科软这个超级垃圾的公司之感悟