python logging模块

原文:http://www.cnblogs.com/dahu-daqing/p/7040764.html

1 logging模块简介

logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:

  1. 可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息;
  2. print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出;

2 logging模块使用

2.1 基本使用

配置logging基本的设置,然后在控制台输出日志,

  1. import logging
  2. logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  3. logger = logging.getLogger(__name__)
  4.  
  5. logger.info("Start print log")
  6. logger.debug("Do something")
  7. logger.warning("Something maybe fail.")
  8. logger.info("Finish")

运行时,控制台输出,

  1. 2016-10-09 19:11:19,434 - __main__ - INFO - Start print log
  2. 2016-10-09 19:11:19,434 - __main__ - WARNING - Something maybe fail.
  3. 2016-10-09 19:11:19,434 - __main__ - INFO - Finish

logging中可以选择很多消息级别,如debug、info、warning、error以及critical。通过赋予logger或者handler不同的级别,开发者就可以只输出错误信息到特定的记录文件,或者在调试时只记录调试信息。

例如,我们将logger的级别改为DEBUG,再观察一下输出结果,

  1. logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')

控制台输出,可以发现,输出了debug的信息。

  1. 2016-10-09 19:12:08,289 - __main__ - INFO - Start print log
  2. 2016-10-09 19:12:08,289 - __main__ - DEBUG - Do something
  3. 2016-10-09 19:12:08,289 - __main__ - WARNING - Something maybe fail.
  4. 2016-10-09 19:12:08,289 - __main__ - INFO - Finish

logging.basicConfig函数各参数:

filename:指定日志文件名;

filemode:和file函数意义相同,指定日志文件的打开模式,'w'或者'a';

format:指定输出的格式和内容,format可以输出很多有用的信息,

  1. 参数:作用
  2. %(levelno)s:打印日志级别的数值
  3. %(levelname)s:打印日志级别的名称
  4. %(pathname)s:打印当前执行程序的路径,其实就是sys.argv[0]
  5. %(filename)s:打印当前执行程序名
  6. %(funcName)s:打印日志的当前函数
  7. %(lineno)d:打印日志的当前行号
  8. %(asctime)s:打印日志的时间
  9. %(thread)d:打印线程ID
  10. %(threadName)s:打印线程名称
  11. %(process)d:打印进程ID
  12. %(message)s:打印日志信息

datefmt:指定时间格式,同time.strftime();

level:设置日志级别,默认为logging.WARNNING;

stream:指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略;

2.2 将日志写入到文件

2.2.1 将日志写入到文件

设置logging,创建一个FileHandler,并对输出消息的格式进行设置,将其添加到logger,然后将日志写入到指定的文件中,

  1. import logging
  2. logger = logging.getLogger(__name__)
  3. logger.setLevel(level = logging.INFO)
  4. handler = logging.FileHandler("log.txt")
  5. handler.setLevel(logging.INFO)
  6. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  7. handler.setFormatter(formatter)
  8. logger.addHandler(handler)
  9.  
  10. logger.info("Start print log")
  11. logger.debug("Do something")
  12. logger.warning("Something maybe fail.")
  13. logger.info("Finish")

log.txt中日志数据为,

  1. 2016-10-09 19:01:13,263 - __main__ - INFO - Start print log
  2. 2016-10-09 19:01:13,263 - __main__ - WARNING - Something maybe fail.
  3. 2016-10-09 19:01:13,263 - __main__ - INFO - Finish

2.2.2 将日志同时输出到屏幕和日志文件

logger中添加StreamHandler,可以将日志输出到屏幕上,

  1. import logging
  2. logger = logging.getLogger(__name__)
  3. logger.setLevel(level = logging.INFO)
  4. handler = logging.FileHandler("log.txt")
  5. handler.setLevel(logging.INFO)
  6. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  7. handler.setFormatter(formatter)
  8.  
  9. console = logging.StreamHandler()
  10. console.setLevel(logging.INFO)
  11.  
  12. logger.addHandler(handler)
  13. logger.addHandler(console)
  14.  
  15. logger.info("Start print log")
  16. logger.debug("Do something")
  17. logger.warning("Something maybe fail.")
  18. logger.info("Finish")

可以在log.txt文件和控制台中看到,

  1. 2016-10-09 19:20:46,553 - __main__ - INFO - Start print log
  2. 2016-10-09 19:20:46,553 - __main__ - WARNING - Something maybe fail.
  3. 2016-10-09 19:20:46,553 - __main__ - INFO - Finish

可以发现,logging有一个日志处理的主对象,其他处理方式都是通过addHandler添加进去,logging中包含的handler主要有如下几种,

  1. handler名称:位置;作用
  2. StreamHandlerlogging.StreamHandler;日志输出到流,可以是sys.stderrsys.stdout或者文件
  3. FileHandlerlogging.FileHandler;日志输出到文件
  4. BaseRotatingHandlerlogging.handlers.BaseRotatingHandler;基本的日志回滚方式
  5. RotatingHandlerlogging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚
  6. TimeRotatingHandlerlogging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件
  7. SocketHandlerlogging.handlers.SocketHandler;远程输出日志到TCP/IP sockets
  8. DatagramHandlerlogging.handlers.DatagramHandler;远程输出日志到UDP sockets
  9. SMTPHandlerlogging.handlers.SMTPHandler;远程输出日志到邮件地址
  10. SysLogHandlerlogging.handlers.SysLogHandler;日志输出到syslog
  11. NTEventLogHandlerlogging.handlers.NTEventLogHandler;远程输出日志到Windows NT/2000/XP的事件日志
  12. MemoryHandlerlogging.handlers.MemoryHandler;日志输出到内存中的指定buffer
  13. HTTPHandlerlogging.handlers.HTTPHandler;通过"GET"或者"POST"远程输出到HTTP服务器

2.2.3 日志回滚

使用RotatingFileHandler,可以实现日志回滚,

  1. import logging
  2. from logging.handlers import RotatingFileHandler
  3. logger = logging.getLogger(__name__)
  4. logger.setLevel(level = logging.INFO)
  5. #定义一个RotatingFileHandler,最多备份3个日志文件,每个日志文件最大1K
  6. rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3)
  7. rHandler.setLevel(logging.INFO)
  8. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  9. rHandler.setFormatter(formatter)
  10.  
  11. console = logging.StreamHandler()
  12. console.setLevel(logging.INFO)
  13. console.setFormatter(formatter)
  14.  
  15. logger.addHandler(rHandler)
  16. logger.addHandler(console)
  17.  
  18. logger.info("Start print log")
  19. logger.debug("Do something")
  20. logger.warning("Something maybe fail.")
  21. logger.info("Finish")

可以在工程目录中看到,备份的日志文件,

  1. 2016/10/09 19:36 732 log.txt
  2. 2016/10/09 19:36 967 log.txt.1
  3. 2016/10/09 19:36 985 log.txt.2
  4. 2016/10/09 19:36 976 log.txt.3

2.3 设置消息的等级

可以设置不同的日志等级,用于控制日志的输出,

  1. 日志等级:使用范围
  2. FATAL:致命错误
  3. CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用
  4. ERROR:发生错误时,如IO操作失败或者连接问题
  5. WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误
  6. INFO:处理请求或者状态变化等日常事务
  7. DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态

2.4 捕获traceback

Python中的traceback模块被用于跟踪异常返回信息,可以在logging中记录下traceback,

代码,

  1. import logging
  2. logger = logging.getLogger(__name__)
  3. logger.setLevel(level = logging.INFO)
  4. handler = logging.FileHandler("log.txt")
  5. handler.setLevel(logging.INFO)
  6. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  7. handler.setFormatter(formatter)
  8.  
  9. console = logging.StreamHandler()
  10. console.setLevel(logging.INFO)
  11.  
  12. logger.addHandler(handler)
  13. logger.addHandler(console)
  14.  
  15. logger.info("Start print log")
  16. logger.debug("Do something")
  17. logger.warning("Something maybe fail.")
  18. try:
  19. open("sklearn.txt","rb")
  20. except (SystemExit,KeyboardInterrupt):
  21. raise
  22. except Exception:
  23. logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
  24.  
  25. logger.info("Finish")

控制台和日志文件log.txt中输出,

  1. Start print log
  2. Something maybe fail.
  3. Faild to open sklearn.txt from logger.error
  4. Traceback (most recent call last):
  5. File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in <module>
  6. open("sklearn.txt","rb")
  7. IOError: [Errno 2] No such file or directory: 'sklearn.txt'
  8. Finish

也可以使用logger.exception(msg,_args),它等价于logger.error(msg,exc_info = True,_args),

  1. logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)

替换为,

  1. logger.exception("Failed to open sklearn.txt from logger.exception")

控制台和日志文件log.txt中输出,

  1. Start print log
  2. Something maybe fail.
  3. Failed to open sklearn.txt from logger.exception
  4. Traceback (most recent call last):
  5. File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in <module>
  6. open("sklearn.txt","rb")
  7. IOError: [Errno 2] No such file or directory: 'sklearn.txt'
  8. Finish

2.5 多模块使用logging

主模块mainModule.py,

  1. import logging
  2. import subModule
  3. logger = logging.getLogger("mainModule")
  4. logger.setLevel(level = logging.INFO)
  5. handler = logging.FileHandler("log.txt")
  6. handler.setLevel(logging.INFO)
  7. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  8. handler.setFormatter(formatter)
  9.  
  10. console = logging.StreamHandler()
  11. console.setLevel(logging.INFO)
  12. console.setFormatter(formatter)
  13.  
  14. logger.addHandler(handler)
  15. logger.addHandler(console)
  16.  
  17. logger.info("creating an instance of subModule.subModuleClass")
  18. a = subModule.SubModuleClass()
  19. logger.info("calling subModule.subModuleClass.doSomething")
  20. a.doSomething()
  21. logger.info("done with subModule.subModuleClass.doSomething")
  22. logger.info("calling subModule.some_function")
  23. subModule.som_function()
  24. logger.info("done with subModule.some_function")

子模块subModule.py,

  1. import logging
  2.  
  3. module_logger = logging.getLogger("mainModule.sub")
  4. class SubModuleClass(object):
  5. def __init__(self):
  6. self.logger = logging.getLogger("mainModule.sub.module")
  7. self.logger.info("creating an instance in SubModuleClass")
  8. def doSomething(self):
  9. self.logger.info("do something in SubModule")
  10. a = []
  11. a.append(1)
  12. self.logger.debug("list a = " + str(a))
  13. self.logger.info("finish something in SubModuleClass")
  14.  
  15. def som_function():
  16. module_logger.info("call function some_function")

执行之后,在控制和日志文件log.txt中输出,

  1. 2016-10-09 20:25:42,276 - mainModule - INFO - creating an instance of subModule.subModuleClass
  2. 2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - creating an instance in SubModuleClass
  3. 2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.subModuleClass.doSomething
  4. 2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - do something in SubModule
  5. 2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - finish something in SubModuleClass
  6. 2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.subModuleClass.doSomething
  7. 2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.some_function
  8. 2016-10-09 20:25:42,279 - mainModule.sub - INFO - call function some_function
  9. 2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.some_function

首先在主模块定义了logger'mainModule',并对它进行了配置,就可以在解释器进程里面的其他地方通过getLogger('mainModule')得到的对象都是一样的,不需要重新配置,可以直接使用。定义的该logger的子logger,都可以共享父logger的定义和配置,所谓的父子logger是通过命名来识别,任意以'mainModule'开头的logger都是它的子logger,例如'mainModule.sub'。

实际开发一个application,首先可以通过logging配置文件编写好这个application所对应的配置,可以生成一个根logger,如'PythonAPP',然后在主函数中通过fileConfig加载logging配置,接着在application的其他地方、不同的模块中,可以使用根logger的子logger,如'PythonAPP.Core','PythonAPP.Web'来进行log,而不需要反复的定义和配置各个模块的logger。

3 通过JSON或者YAML文件配置logging模块

尽管可以在Python代码中配置logging,但是这样并不够灵活,最好的方法是使用一个配置文件来配置。在Python 2.7及以后的版本中,可以从字典中加载logging配置,也就意味着可以通过JSON或者YAML文件加载日志的配置。

3.1 通过JSON文件配置

JSON配置文件,

  1. {
  2. "version":1,
  3. "disable_existing_loggers":false,
  4. "formatters":{
  5. "simple":{
  6. "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  7. }
  8. },
  9. "handlers":{
  10. "console":{
  11. "class":"logging.StreamHandler",
  12. "level":"DEBUG",
  13. "formatter":"simple",
  14. "stream":"ext://sys.stdout"
  15. },
  16. "info_file_handler":{
  17. "class":"logging.handlers.RotatingFileHandler",
  18. "level":"INFO",
  19. "formatter":"simple",
  20. "filename":"info.log",
  21. "maxBytes":"10485760",
  22. "backupCount":20,
  23. "encoding":"utf8"
  24. },
  25. "error_file_handler":{
  26. "class":"logging.handlers.RotatingFileHandler",
  27. "level":"ERROR",
  28. "formatter":"simple",
  29. "filename":"errors.log",
  30. "maxBytes":10485760,
  31. "backupCount":20,
  32. "encoding":"utf8"
  33. }
  34. },
  35. "loggers":{
  36. "my_module":{
  37. "level":"ERROR",
  38. "handlers":["info_file_handler"],
  39. "propagate":"no"
  40. }
  41. },
  42. "root":{
  43. "level":"INFO",
  44. "handlers":["console","info_file_handler","error_file_handler"]
  45. }
  46. }

通过JSON加载配置文件,然后通过logging.dictConfig配置logging,

  1. import json
  2. import logging.config
  3. import os
  4.  
  5. def setup_logging(default_path = "logging.json",default_level = logging.INFO,env_key = "LOG_CFG"):
  6. path = default_path
  7. value = os.getenv(env_key,None)
  8. if value:
  9. path = value
  10. if os.path.exists(path):
  11. with open(path,"r") as f:
  12. config = json.load(f)
  13. logging.config.dictConfig(config)
  14. else:
  15. logging.basicConfig(level = default_level)
  16.  
  17. def func():
  18. logging.info("start func")
  19.  
  20. logging.info("exec func")
  21.  
  22. logging.info("end func")
  23.  
  24. if __name__ == "__main__":
  25. setup_logging(default_path = "logging.json")
  26. func()

3.2 通过YAML文件配置

通过YAML文件进行配置,比JSON看起来更加简介明了,

  1. version: 1
  2. disable_existing_loggers: False
  3. formatters:
  4. simple:
  5. format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  6. handlers:
  7. console:
  8. class: logging.StreamHandler
  9. level: DEBUG
  10. formatter: simple
  11. stream: ext://sys.stdout
  12. info_file_handler:
  13. class: logging.handlers.RotatingFileHandler
  14. level: INFO
  15. formatter: simple
  16. filename: info.log
  17. maxBytes: 10485760
  18. backupCount: 20
  19. encoding: utf8
  20. error_file_handler:
  21. class: logging.handlers.RotatingFileHandler
  22. level: ERROR
  23. formatter: simple
  24. filename: errors.log
  25. maxBytes: 10485760
  26. backupCount: 20
  27. encoding: utf8
  28. loggers:
  29. my_module:
  30. level: ERROR
  31. handlers: [info_file_handler]
  32. propagate: no
  33. root:
  34. level: INFO
  35. handlers: [console,info_file_handler,error_file_handler]

通过YAML加载配置文件,然后通过logging.dictConfig配置logging,

  1. import yaml
  2. import logging.config
  3. import os
  4.  
  5. def setup_logging(default_path = "logging.yaml",default_level = logging.INFO,env_key = "LOG_CFG"):
  6. path = default_path
  7. value = os.getenv(env_key,None)
  8. if value:
  9. path = value
  10. if os.path.exists(path):
  11. with open(path,"r") as f:
  12. config = yaml.load(f)
  13. logging.config.dictConfig(config)
  14. else:
  15. logging.basicConfig(level = default_level)
  16.  
  17. def func():
  18. logging.info("start func")
  19.  
  20. logging.info("exec func")
  21.  
  22. logging.info("end func")
  23.  
  24. if __name__ == "__main__":
  25. setup_logging(default_path = "logging.yaml")
  26. func()

4 Reference

每个 Python 程序员都要知道的日志实践

Python标准模块logging

python 的日志logging模块学习

(转)python logging模块的更多相关文章

  1. python logging模块可能会令人困惑的地方

    python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...

  2. python logging模块使用

    近来再弄一个小项目,已经到收尾阶段了.希望加入写log机制来增加程序出错后的判断分析.尝试使用了python logging模块. #-*- coding:utf-8 -*- import loggi ...

  3. 读懂掌握 Python logging 模块源码 (附带一些 example)

    搜了一下自己的 Blog 一直缺乏一篇 Python logging 模块的深度使用的文章.其实这个模块非常常用,也有非常多的滥用.所以看看源码来详细记录一篇属于 logging 模块的文章. 整个 ...

  4. Python logging 模块学习

    logging example Level When it's used Numeric value DEBUG Detailed information, typically of interest ...

  5. python logging—模块

    python logging模块 python logging提供了标准的日志接口,python logging日志分为5个等级: debug(), info(), warning(), error( ...

  6. Python logging模块无法正常输出日志

    废话少说,先上代码 File:logger.conf [formatters] keys=default [formatter_default] format=%(asctime)s - %(name ...

  7. 0x03 Python logging模块之Formatter格式

    目录 logging模块之Formatter格式 Formater对象 日志输出格式化字符串 LogRecoder对象 时间格式化字符串 logging模块之Formatter格式 在记录日志是,日志 ...

  8. 0x01 Python logging模块

    目录 Python logging 模块 前言 logging模块提供的特性 logging模块的设计过程 logger的继承 logger在逻辑上的继承结构 logging.basicConfig( ...

  9. Python Logging模块的简单使用

    前言 日志是非常重要的,最近有接触到这个,所以系统的看一下Python这个模块的用法.本文即为Logging模块的用法简介,主要参考文章为Python官方文档,链接见参考列表. 另外,Python的H ...

随机推荐

  1. Vue:(五)axios

    Axios是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中.axios主要是用于向后台发起请求的,还有在请求中做更多可控功能.官方不再维护vue-resource,推 ...

  2. 使用scss为css样式自动添加浏览器前缀

    当一个浏览器实现一个新的属性.值或者选择器,而这个特征还不是处于候选推荐标准状态的时候,这属性的前面会添加一个前缀以便于它的渲染引擎识别. 浏览器使用前缀来尝试一些新属性.值和选择器,即使他们还没有最 ...

  3. 这可能是史上最全的css布局教程

    标题严格遵守了新广告法,你再不爽,我也没犯法呀!话不多说,直入正题. 所谓布局,其实包含两个含义:尺寸与定位.也就是说,所有与尺寸和定位相关的属性,都可以用来布局. 大体上,布局中会用到的有:尺寸相关 ...

  4. linux下查看进程命令

    他们都是用来显示当前运行的进程,但是: ps -aux 是用BSD的格式来显示python这个进程显示的项目有:USER , PID , %CPU , %MEM , VSZ , RSS , TTY , ...

  5. jRazor

    引擎渲染速度竞赛 条数据 × 次渲染测试 建议在高版本的浏览器上进行测试,避免浏览器停止响应 测试环境: 开始测试»  

  6. 7.5 GRASP原则五:高内聚 High Cohesion

    GRASP原则五:高内聚 High Cohesion  How to keep objects focused, understandable and manageable, and as a si ...

  7. Police Stations CodeForces - 796D (bfs)

    大意: 给定树, 有k个黑点, 初始满足条件:所有点到最近黑点距离不超过d, 求最多删除多少条边后, 使得原图仍满足条件. 所有黑点开始bfs, 贪心删边. #include <iostream ...

  8. CSS选择器 nth-child 和 nth-of-type

    Css 3 中两个新的选择器 nth-child 和 nth-of-type 都可以选择父元素下对应的子元素,但它们到底有什么区别呢? :nth-child(n) 选择器匹配属于其父元素下的第n个子元 ...

  9. 一天一点Zynq(1)xilinx-arm-linux交叉编译链 安装总结以及资源更新

    结束了对xilinx-arm-linux交叉编译链安装后,总结一下整个过程,方便后来的研究者们,少走点弯路. 关于xilinx-arm-linux交叉编译链的安装,网上一搜一大把,可是有的资料中的资源 ...

  10. AutoMapper实现对象转换的几种方式

    namespace ConsoleApplication1 { class Program { static void Main(string[] args) { //1.普通转换 Name name ...