Python如何写日志即logging日志模块的使用方法
作者:redrose2100   类别:    日期:2022-05-10 09:33:25    阅读:1064 次   消耗积分:0 分

1 logging 日志级别

级别 级别数量 使用场合
DEBUG 10 详细信息,常用语调试
INFO 20 程序正常运行过程中产生的一些信息
WARNING 20 警告用户,虽然程序还在正常工作,但有可能发生错误
ERROR 40 由于更严重的问题,程序已不能执行一些功能了
CRITICAL 50 严重错误,程序已不能继续运行了

2 logging 默认的是warning级别

  1. import logging
  2. logging.debug("this is debug log")
  3. logging.info("this is info log")
  4. logging.warning("this is warning log")
  5. logging.error("this is error log")
  6. logging.critical("this is critical log")

执行结果如下:

  1. WARNING:root:this is warning log
  2. ERROR:root:this is error log
  3. CRITICAL:root:this is critical log

3 可以通过logging.basicConfig(level=logging.DEBUG) 来设置日志级别

  1. import logging
  2. logging.basicConfig(level=logging.DEBUG)
  3. logging.debug("this is debug log")
  4. logging.info("this is info log")
  5. logging.warning("this is warning log")
  6. logging.error("this is error log")
  7. logging.critical("this is critical log")

运行结果如下:

  1. DEBUG:root:this is debug log
  2. INFO:root:this is info log
  3. WARNING:root:this is warning log
  4. ERROR:root:this is error log
  5. CRITICAL:root:this is critical log

4 logging日志是一部写入的,logging打印的内容和print打印的内筒先后顺序是不一致的

  1. import logging
  2. print("this is print log")
  3. logging.basicConfig(level=logging.DEBUG)
  4. logging.debug("this is debug log")
  5. logging.info("this is info log")
  6. logging.warning("this is warning log")
  7. logging.error("this is error log")
  8. logging.critical("this is critical log")

运行结果有可能是下面这种输出顺序

  1. DEBUG:root:this is debug log
  2. INFO:root:this is info log
  3. WARNING:root:this is warning log
  4. ERROR:root:this is error log
  5. CRITICAL:root:this is critical log
  6. this is print log

5 logging.basicConfig(filename=”demo.log”)可以指定日志文件名,默认在当前目录下生成文件,此时不再往屏幕打印日志,而是将日志信息输出到指定的日志文件中去

  1. import logging
  2. print("this is print log")
  3. logging.basicConfig(filename="demo.log",level=logging.DEBUG)
  4. logging.debug("this is debug log")
  5. logging.info("this is info log")
  6. logging.warning("this is warning log")
  7. logging.error("this is error log")
  8. logging.critical("this is critical log")

运行后屏幕上输出结果为:

  1. this is print log

而在当前文件下生成了一个demo.log的日志文件,此日志文件的内容为:

  1. DEBUG:root:this is debug log
  2. INFO:root:this is info log
  3. WARNING:root:this is warning log
  4. ERROR:root:this is error log
  5. CRITICAL:root:this is critical log

6 logging.basicConfig(filemode=’w’) 可以指定日志文件的模式,w表示每次清空日志文件,重新写入,a表示在日志文件后面追加,默认的模式为a

将上述 5 中的实例代码再执行一次,demo.log中内容为:

  1. DEBUG:root:this is debug log
  2. INFO:root:this is info log
  3. WARNING:root:this is warning log
  4. ERROR:root:this is error log
  5. CRITICAL:root:this is critical log
  6. DEBUG:root:this is debug log
  7. INFO:root:this is info log
  8. WARNING:root:this is warning log
  9. ERROR:root:this is error log
  10. CRITICAL:root:this is critical log

若代码修改为如下,再执行:

  1. import logging
  2. print("this is print log")
  3. logging.basicConfig(filename="demo.log",filemode='w',level=logging.DEBUG)
  4. logging.debug("this is debug log")
  5. logging.info("this is info log")
  6. logging.warning("this is warning log")
  7. logging.error("this is error log")
  8. logging.critical("this is critical log")

运行后,demo.log中的内容又恢复到如下内容:

  1. DEBUG:root:this is debug log
  2. INFO:root:this is info log
  3. WARNING:root:this is warning log
  4. ERROR:root:this is error log
  5. CRITICAL:root:this is critical log

7 logging 向日志中写入变量的方式

  1. import logging
  2. logging.basicConfig(level=logging.DEBUG)
  3. name="zhangsan"
  4. age=20
  5. logging.debug("name: %s age: %d",name,age)
  6. logging.info("name: %s age: %d" %(name,age))
  7. logging.warning("name: {} age: {}".format(name,age))
  8. logging.error("name: {name} age: {age}".format(name=name,age=age))

运行结果如下:

  1. DEBUG:root:name: zhangsan age: 20
  2. INFO:root:name: zhangsan age: 20
  3. WARNING:root:name: zhangsan age: 20
  4. ERROR:root:name: zhangsan age: 20

8 日志内容格式增加一些公共的内容

  1. import logging
  2. logging.basicConfig(format=("%(asctime)s | %(levelname)s | %(filename)s:%(lineno)s | %(message)s"),
  3. datefmt="%Y-%m-%d_%H:%M:%S",
  4. level=logging.DEBUG)
  5. name="zhangsan"
  6. age=20
  7. logging.debug("name: %s age: %d",name,age)
  8. logging.info("name: %s age: %d" %(name,age))
  9. logging.warning("name: {} age: {}".format(name,age))
  10. logging.error("name: {name} age: {age}".format(name=name,age=age))

运行结果为:

  1. 2020-08-03_07:20:42 | DEBUG | test1.py:9 | name: zhangsan age: 20
  2. 2020-08-03_07:20:42 | INFO | test1.py:10 | name: zhangsan age: 20
  3. 2020-08-03_07:20:42 | WARNING | test1.py:11 | name: zhangsan age: 20
  4. 2020-08-03_07:20:42 | ERROR | test1.py:12 | name: zhangsan age: 20

9 logging的高级应用

logging模块采用了模块化设计,主要包含四种组件

  • Loggers:记录器,提供应用程序代码能直接使用的接口
  • Handlers:处理器,将记录器产生的日志发送到目的地
  • Filters:过滤器,提供更好的粒度控制,决定哪些日志会被输出
  • 格式化器:设置内置内容的组成结构和消息字段

10 logging的高级应用流程

  1. |---创建屏幕StreamHandler--设置日志等级---|
  2. 创建一个logger并设置默认等级---| |----创建formatter----用formatter渲染所有的hansdler----将所有的handler加入logger内----程序调用logger
  3. |---创建文件FileHandler--设置日志等级-----|

11 loggers记录器

  • 提供应用程序的调用接口

    logger=logging。getLogger(name)
    logger是单例的

  • 决定日志记录的级别

    logger.setLevel()

  • 将日志内容传递到相关联的handlers中

    logger.addHandler()

    logger。removeHandler()

12 handler处理器

  • StreamHandler

    标准输出stdout(如显示器)分发器

    创建方法: sh=logging.StreamHandler(stream=None)

  • FileHandler

    将日志保存到磁盘文件的处理器

    创建方法:fh=logging.FileHandler(filename,mode=”a”,enconding=None,delay=False)

  • setFormatter(): 设置当前handler对象使用的消息格斯

13 常用的Handlers处理器

  • StreamHandler
  • FileHandler
  • BaseRotatingHandler
  • RotatingHandler
  • TimedRotatingFileHandler
  • SocketHandler
  • DatagramHandler
  • SMTPHandler
  • SysLogHandler
  • NTEventLogHandler
  • HTTPHandler
  • WatchedFileHandler
  • QueueHandler
  • NullHandler

14 常见的formatter格式

属性 格式 描述
asctime %(asctime)s 日志产生的时间,默认格式为2020-08-03 12.12.12,265
created %(created)f time.time()生成的日志创建时间戳
filename %(filename)s 生成日志的程序名
funcName %(funcName)s 调用日志的函数名
levelname %(levelname)s 日志级别(DEBUG,INFO,WARNING,ERROR,CRITICAL)
levelno %(levelno)s 日志级别对应的数值
lineno %(lineno)s) 日志所针对的代码行号(如果可用的话)
module %(module)s 生成日志的模块名
mesecs %(mesecs)d 日志生成的时间的毫秒部分
message %(message)s 具体的日志信息
name %(name)s 日志调用者
pathname %(pathname)s 生成日志的文件的完整路径
process %(process)d 生成日志的进程id(如果可用)
processName %(processName)s 进程名(如果可用)
thread %(thread)d 生成日志的线程id(如果可用)
threadName %(threadName)s 线程名(如果可用)

15 下面两段代码的功能是完全一样的,使用logging直接调info、debug等日志与实例化一个默认的root logger是一样的,换言之,使用logging直接调日志方法的方式就是通过获取root日志来实现的

  1. import logging
  2. logging.debug("this is debug log")
  3. logging.info("this is info log")
  4. logging.warning("this is warning log")
  5. logging.error("this is error log")
  6. logging.critical("this is critical log")
  7. logger=logging.getLogger()
  8. logger.debug("this is debug log")
  9. logger.info("this is info log")
  10. logger.warning("this is warning log")
  11. logger.error("this is error log")
  12. logger.critical("this is critical log"

运行结果如下:

  1. WARNING:root:this is warning log
  2. ERROR:root:this is error log
  3. CRITICAL:root:this is critical log
  4. WARNING:root:this is warning log
  5. ERROR:root:this is error log
  6. CRITICAL:root:this is critical log

16 下面一段代码使用getLogger时指定一个名称,即实例化一个logger,然后设置两种处理器,分别往控制台和文件中写日志,还可以设置日志内容的格式,具体如下所示

  1. import logging
  2. logger=logging.getLogger("test")
  3. console_handler=logging.StreamHandler()
  4. console_handler.setLevel(logging.DEBUG)
  5. file_handler=logging.FileHandler(filename="demo.log")
  6. file_handler.setLevel(logging.DEBUG)
  7. formatter=logging.Formatter(fmt="%(asctime)s | %(levelname)s | %(filename)s:%(lineno)s | %(message)s")
  8. console_handler.setFormatter(formatter)
  9. file_handler.setFormatter(formatter)
  10. logger.addHandler(console_handler)
  11. logger.addHandler(file_handler)
  12. log=logger
  13. log.debug("this is debug log")
  14. log.info("this is info log")
  15. log.warning("this is warning log")
  16. log.error("this is error log")
  17. log.critical("this is critical log")

运行结果如下:

  1. 2020-08-04 23:08:56,625 | WARNING | test1.py:25 | this is warning log
  2. 2020-08-04 23:08:56,625 | ERROR | test1.py:26 | this is error log
  3. 2020-08-04 23:08:56,625 | CRITICAL | test1.py:27 | this is critical log

并且在demo.log日志文件中写入了如下内容:

  1. 2020-08-04 23:08:56,625 | WARNING | test1.py:25 | this is warning log
  2. 2020-08-04 23:08:56,625 | ERROR | test1.py:26 | this is error log
  3. 2020-08-04 23:08:56,625 | CRITICAL | test1.py:27 | this is critical log

17 上述 16 的日志打印明显与本来的期望是不一致的,本来期望控制台和文件都是设置了DEBUG级别,但实际上控制台和文件中都打印了Warning的级别的日志

这里需要注意的是,logger默认的日志级别是warning,而日志的最终级别将取决于logger和handler级别的最高级别,所以上述16中虽然控制台和文件handler的日志级别都设置了debug,但是因为logger默认级别是warning,所以最终打印的都是warning级别,下面一段代码将logger设置为debug级别,然后将控制台设置为info,将文件handler设置为warning,然后再看一下效果:

  1. import logging
  2. logger=logging.getLogger("test")
  3. logger.setLevel(logging.DEBUG)
  4. console_handler=logging.StreamHandler()
  5. console_handler.setLevel(logging.INFO)
  6. file_handler=logging.FileHandler(filename="demo.log")
  7. file_handler.setLevel(logging.WARNING)
  8. formatter=logging.Formatter(fmt="%(asctime)s | %(levelname)s | %(filename)s:%(lineno)s | %(message)s")
  9. console_handler.setFormatter(formatter)
  10. file_handler.setFormatter(formatter)
  11. logger.addHandler(console_handler)
  12. logger.addHandler(file_handler)
  13. log=logger
  14. log.debug("this is debug log")
  15. log.info("this is info log")
  16. log.warning("this is warning log")
  17. log.error("this is error log")
  18. log.critical("this is critical log")

运行结果如下:

  1. 2020-08-04 23:21:37,888 | INFO | test1.py:25 | this is info log
  2. 2020-08-04 23:21:37,888 | WARNING | test1.py:26 | this is warning log
  3. 2020-08-04 23:21:37,888 | ERROR | test1.py:27 | this is error log
  4. 2020-08-04 23:21:37,888 | CRITICAL | test1.py:28 | this is critical log

而在demo.log日志文件中写入了如下内容,此时与上述分析一致了

  1. 2020-08-04 23:21:37,888 | WARNING | test1.py:26 | this is warning log
  2. 2020-08-04 23:21:37,888 | ERROR | test1.py:27 | this is error log
  3. 2020-08-04 23:21:37,888 | CRITICAL | test1.py:28 | this is critical log

18 定义filter并给控制台的handler加一个filter,过滤的name与日志名称不一致,如下代码,此时则不会往控制台写日志,但日志文件的日志还是正常写的

  1. import logging
  2. logger=logging.getLogger("test")
  3. logger.setLevel(logging.DEBUG)
  4. console_handler=logging.StreamHandler()
  5. console_handler.setLevel(logging.INFO)
  6. file_handler=logging.FileHandler(filename="demo.log")
  7. file_handler.setLevel(logging.WARNING)
  8. formatter=logging.Formatter(fmt="%(asctime)s | %(levelname)s | %(filename)s:%(lineno)s | %(message)s")
  9. console_handler.setFormatter(formatter)
  10. file_handler.setFormatter(formatter)
  11. logger.addHandler(console_handler)
  12. logger.addHandler(file_handler)
  13. filter=logging.Filter("test1")
  14. console_handler.addFilter(filter)
  15. log=logger
  16. log.debug("this is debug log")
  17. log.info("this is info log")
  18. log.warning("this is warning log")
  19. log.error("this is error log")
  20. log.critical("this is critical log")

此时运行后控制台结果为空,日志文件如下日志打印正常

  1. 2020-08-04 23:31:00,459 | WARNING | test1.py:29 | this is warning log
  2. 2020-08-04 23:31:00,459 | ERROR | test1.py:30 | this is error log
  3. 2020-08-04 23:31:00,459 | CRITICAL | test1.py:31 | this is critical log

19 配置文件的方式

  • (1) 首先编写类似如下的log配置文件:logging.conf, 这里面定义了root和test两个logger
  1. [loggers]
  2. keys=root,test
  3. [handlers]
  4. keys=fileHandler,consoleHandler
  5. [formatters];
  6. keys=simpleFormatter
  7. [logger_root]
  8. level=DEBUG
  9. handlers=consoleHandler
  10. [logger_test]
  11. level=DEBUG
  12. handlers=fileHandler,consoleHandler
  13. qualname=test
  14. propagate=0
  15. [handler_consoleHandler]
  16. class=StreamHandler
  17. args=(sys.stdout,)
  18. level=DEBUG
  19. formatter=simpleFormatter
  20. [handler_fileHandler]
  21. class=handlers.TimedRotatingFileHandler
  22. args=("test.log","midnight",1,0)
  23. level=DEBUG
  24. formatter=simpleFormatter
  25. [formatter_simpleFormatter]
  26. format=%(asctime)s|%(levelname)s|%(filename)s[line:%(lineno)d]|%(message)s
  27. datafmt=%Y-%m-%d_%H:%M:%S
  • (2)然后在py文件中编写如下代码,这里演示了root的logger和test的logger两种的使用方式
  1. import logging.config
  2. logging.config.fileConfig("logging.conf")
  3. logger=logging.getLogger("test")
  4. log=logger
  5. log.debug("this is debug log")
  6. log.info("this is info log")
  7. log.warning("this is warning log")
  8. log.error("this is error log")
  9. log.critical("this is critical log")
  10. rlog=logging.getLogger("root")
  11. rlog.debug("this is debug log")
  12. rlog.info("this is info log")
  13. rlog.warning("this is warning log")
  14. rlog.error("this is error log")
  15. rlog.critical("this is critical log")

运行结果如下:

  1. 2020-08-05 00:25:02,673|DEBUG|test1.py[line:8]|this is debug log
  2. 2020-08-05 00:25:02,674|INFO|test1.py[line:9]|this is info log
  3. 2020-08-05 00:25:02,674|WARNING|test1.py[line:10]|this is warning log
  4. 2020-08-05 00:25:02,674|ERROR|test1.py[line:11]|this is error log
  5. 2020-08-05 00:25:02,674|CRITICAL|test1.py[line:12]|this is critical log
  6. 2020-08-05 00:25:02,674|DEBUG|test1.py[line:15]|this is debug log
  7. 2020-08-05 00:25:02,674|INFO|test1.py[line:16]|this is info log
  8. 2020-08-05 00:25:02,674|WARNING|test1.py[line:17]|this is warning log
  9. 2020-08-05 00:25:02,674|ERROR|test1.py[line:18]|this is error log
  10. 2020-08-05 00:25:02,674|CRITICAL|test1.py[line:19]|this is critical log

同时在test.log日志文件中生成如下日志:

  1. 2020-08-05 00:25:02,673|DEBUG|test1.py[line:8]|this is debug log
  2. 2020-08-05 00:25:02,674|INFO|test1.py[line:9]|this is info log
  3. 2020-08-05 00:25:02,674|WARNING|test1.py[line:10]|this is warning log
  4. 2020-08-05 00:25:02,674|ERROR|test1.py[line:11]|this is error log
  5. 2020-08-05 00:25:02,674|CRITICAL|test1.py[line:12]|this is critical log

20 在上述19的基础上,加入在其他文件中想使用建好的log系统进行日志的打印,有如下两种使用方法:

  1. import test1
  2. import logging
  3. log=logging.getLogger("test")
  4. log.debug("this is debug log")
  5. log.info("this is info log")
  6. log.warning("this is warning log")
  7. log.error("this is error log")
  8. log.critical("this is critical log")
  9. log=test1.logger
  10. log.debug("this is debug log")
  11. log.info("this is info log")
  12. log.warning("this is warning log")
  13. log.error("this is error log")
  14. log.critical("this is critical log")

运行结果如下:

  1. 2020-08-05_00:31:35|DEBUG|test2.py[line:8]|this is debug log
  2. 2020-08-05_00:31:35|INFO|test2.py[line:9]|this is info log
  3. 2020-08-05_00:31:35|WARNING|test2.py[line:10]|this is warning log
  4. 2020-08-05_00:31:35|ERROR|test2.py[line:11]|this is error log
  5. 2020-08-05_00:31:35|CRITICAL|test2.py[line:12]|this is critical log
  6. 2020-08-05_00:31:35|DEBUG|test2.py[line:16]|this is debug log
  7. 2020-08-05_00:31:35|INFO|test2.py[line:17]|this is info log
  8. 2020-08-05_00:31:35|WARNING|test2.py[line:18]|this is warning log
  9. 2020-08-05_00:31:35|ERROR|test2.py[line:19]|this is error log
  10. 2020-08-05_00:31:35|CRITICAL|test2.py[line:20]|this is critical log

日志文件中也生成了对应的日志:

  1. 2020-08-05_00:31:35|DEBUG|test2.py[line:8]|this is debug log
  2. 2020-08-05_00:31:35|INFO|test2.py[line:9]|this is info log
  3. 2020-08-05_00:31:35|WARNING|test2.py[line:10]|this is warning log
  4. 2020-08-05_00:31:35|ERROR|test2.py[line:11]|this is error log
  5. 2020-08-05_00:31:35|CRITICAL|test2.py[line:12]|this is critical log
  6. 2020-08-05_00:31:35|DEBUG|test2.py[line:16]|this is debug log
  7. 2020-08-05_00:31:35|INFO|test2.py[line:17]|this is info log
  8. 2020-08-05_00:31:35|WARNING|test2.py[line:18]|this is warning log
  9. 2020-08-05_00:31:35|ERROR|test2.py[line:19]|this is error log
  10. 2020-08-05_00:31:35|CRITICAL|test2.py[line:20]|this is critical log

21 在try - except语句块中,打印异常日志可以使用log.exception(e),这个函数可以将程序错误调用栈打印出来

  1. import logging.config
  2. logging.config.fileConfig("logging.conf")
  3. logger=logging.getLogger("test")
  4. log=logger
  5. try:
  6. a=1/0
  7. except Exception as e:
  8. log.exception(e)

运行结果如下:

  1. 2020-08-05_00:35:14|ERROR|test1.py[line:12]|division by zero
  2. Traceback (most recent call last):
  3. File "G:/lamb_source/test/log/test1.py", line 10, in <module>
  4. a=1/0
  5. ZeroDivisionError: division by zero
始终坚持开源开放共享精神,同时感谢您的充电鼓励和支持!
版权所有,转载本站文章请注明出处:redrose2100, http://blog.redrose2100.com/article/143