0、为什么用日志
编码时,基本调试手段是添加print。添加print的有优点也有缺点:
- 优点 :通过输出,可以快速判断程序是否执行到关注的语句块;
- 缺点 :可能有两点,
1、print适用于短的代码,长的代码。print输出的东西太多,就找不到真正关心的内容。
2、输出到控制台的东西不太美观,可能还要它删除掉,导致工作量加大。
所以应该使用日志模块logging。提供三个好处:
- 日志信息可以详细记录时间,发生位置,方便debug。
- 可以通过日志的严重性,调整输出日志的详细程度,不重要的日志可以被屏蔽掉,美观整洁。
- 日志可以定向输出到文件中,方便存储和追溯。
1、参考
[1] python 官网的文档:https://docs.python.org/zh-cn/3.7/howto/logging.html#
2、通过例子快速看一下
先不看日志部分,第一个文件 main.py,主要干了两件事。
from Hello import Hello
from NewClass import NewClass
import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger(__name__)
if __name__=="__main__":
logger.debug("这里开始")
Hello()
newClass = NewClass()
newClass.run()
logger.critical("这里结束")
第一件事:调用了另一个Hello模块下的Hello()函数。
第二件事:实例化了NewClass模块下的NewClass类,调用了该对象的run()方法。
第二个文件 Hello.py,以及第三个文件 NewClass.py 都很简单,向命令行窗口输出一些信息。
import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger(__name__)
def Hello():
logger.debug("这是Hello")
#print("This is Hello!")
logger.info("Hello结束")
import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger(__name__)
class NewClass():
def run(self):
logger.debug("这是NewClass开始")
#print("This is in NewClass")
logger.warning("这是NewClass结束")
这时如果要记录调试日志,可以通过配置文件的方式进行
#########################################
####### #########
#########################################
## 参考内容 https://docs.python.org/zh-cn/3.7/howto/logging.html#configuring-logging
## 定义一个处理器, 向命令行窗口输出日志记录, 这个处理器的名字叫 consoleHandler
[handlers]
keys=consoleHandler
## 定义个日志格式, 这个对象的名字叫 LoggingFormatter
[formatters]
keys=LoggingFormatter
## 配置 consoleHandler 这个处理器的属性
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=LoggingFormatter
args=(sys.stdout,)
## 配置 LoggingFormatter 这个格式的属性
[formatter_LoggingFormatter]
format=[%(asctime)s][PID:%(process)d][TID:%(thread)d][%(filename)0.8s][line:%(lineno)4.4d][%(funcName)0.6s][%(levelname)1.3s]%(message)s
datefmt=
#########################################
####### #########
#########################################
## 记录器
[loggers]
keys=root,Hello,NewClass
[logger_root]
level=DEBUG
handlers=consoleHandler
## 针对Hello模块定义记录器,和Hello.py中的 logger = logging.getLogger(__name__) 对应
[logger_Hello]
level=DEBUG
handlers=consoleHandler
qualname=Hello
propagate=0
##针对NewClass模块定义记录器NewClass,这是模块名,不是类名
[logger_NewClass]
level=DEBUG
handlers=consoleHandler
qualname=NewClass
propagate=0
接下来回到每个文件中, 通过下面四句话,得到一个logger对象.
import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger(__name__)
通过logger对象,可以调用debug,warning,info,error,critical五个不同的函数输出对应的五种级别的日志.
由于在上面你的配置中logger和handler的级别都配置成了debug,所以,所以最低级别的日志时debug.类似下面的调用,将会向命令行输出一行debug级别的日志.
logger.debug("这是Hello")
运行main.py,可以看到输出的日志.
可以通过调节
[logger_NewClass]
level=DEBUG
或
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
这两个调高中的level级别,过滤低级别的日志,例如配置到level = INFO级别,输出日志就变成:
3、简单总结一下
- 使用日志,需要先有个日志配置文件,配置记录器,处理器,格式,还可以配置过滤器(上面的例子没有体现). 记录器的名字最好时每个模块的名字.
- 在自己的模块中,调用logging.config.fileConfig() 读取配置文件,然后获取对应模块名字的记录器,就可以在代码中调用记录器的debug(),info(),记录日志了.
4、多想一点
如果想日志输出到日志文件中,怎么配置? 应该要配置Handler.
https://docs.python.org/3.5/library/logging.handlers.html#logging.handlers.RotatingFileHandler
普通的一个log.log文件,用来存放日志,args里面可以加上’w’或者’a’,表示覆盖或者追加模式.
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=LoggingFormatter
args=("logs/log.log")
基于时间的日志循环模式,在args里面,配置间隔的单位’s’秒(这就是when),间隔的数字5(这就是interval),这两个组合起来就是间隔5秒保存一次日志文件,最后一个5(backupCount),是备份前5次的文件.
[handler_fileHandler]
class=handlers.TimedRotatingFileHandler
level=DEBUG
formatter=LoggingFormatter
args=("logs/log.log", 's',5,5)
执行效果就像这样
基于日志文件大小的循环模式,当日志超过指定大小时,备份日志,重新写一个日志文件.在args里面,'a’是追加模式,1024*1024是maxBytes单个文件的大小,backupCount和时间循环的日志一致,都是备份几次文件.backupCount为0时,不循环.
[handler_fileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=LoggingFormatter
args=("logs/log.log", 'a',1024*1024,5)
#maxBytes=1024
#backupCount=10