我们这一辈子都在不断面对各种困难,只是阶段不同,困难的意义便有不同。要感谢困难,以后你会明白,人在安逸时是最容易被毁灭的,只有一直迎接挑战,才会得以生存!
总结:
- 现在编程都是采用约定的方式;
Python logging 模块定义了为应用程序和库实现灵活的事件日志记录的函数和类。
程序开发过程中,很多程序都有记录日志的需求,并且日志包含的信息有正常的程序访问日志还可能有错误、警告等信息输出,Python 的 logging 模块提供了标准的日志接口,可以通过它存储各种格式的日志,日志记录提供了一组便利功能,用于简单的日志记录用法!
1. logging模块
1.1 日志级别
日志级别等级排序:critical > error > warning > info > debug
日志等级(level) | 数值 | 描述 |
---|---|---|
NOTSET | 0 | |
DEBUG | 10 | 最详细的日志信息,典型应用场景是 问题诊断 |
INFO | 20 | 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作 |
WARNING | 30 | 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的 |
ERROR | 40 | 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 |
CRITICAL | 50 | 当发生严重错误,导致应用程序不能继续运行时记录的信息 |
级别越高打印的日志越少,反之亦然,即
debug : 打印全部的日志( notset 等同于 debug )
info : 打印 info, warning, error, critical 级别的日志
warning : 打印 warning, error, critical 级别的日志
error : 打印 error, critical 级别的日志
critical : 打印 critical 级别
1.2 设置日志显示级别
通过 logging.basicConfig() 可以设置 root 的日志级别,和日志输出格式。
logging.basicConfig() 关键字参数:
关键字 | 描述 |
---|---|
filename | 创建一个 FileHandler,使用指定的文件名,而不是使用 StreamHandler。 |
filemode | 如果指明了文件名,指明打开文件的模式(如果没有指明 filemode,默认为 'a')。 |
format | handler 使用指明的格式化字符串。 |
datefmt | handler 使用指明的格式化字符串。 |
level | 指明根 logger 的级别。 |
stream | 使用指明的流来初始化 StreamHandler。该参数与 'filename' 不兼容,如果两个都有,'stream' 被忽略。 |
format 格式
格式 | 描述 |
---|---|
%(levelno)s | 打印日志级别的数值 |
%(levelname)s | 打印日志级别名称 |
%(pathname)s | 打印当前执行程序的路径 |
%(filename)s | 打印当前执行程序名称 |
%(funcName)s | 打印日志的当前函数 |
%(lineno)d | 打印日志的当前行号 |
%(asctime)s | 打印日志的时间 |
%(thread)d | 打印线程 ID |
%(threadName)s | 打印线程名称 |
%(process)d | 打印进程 ID |
%(message)s | 打印日志信息 |
注意:Logging.basicConfig() 需要在开头就设置,在中间设置并无作用
import logging
FORMAT = '%(asctime)-15s\tThread info: %(thread)d %(threadName)s %(message)s' # -15 左对齐;
logging.basicConfig(format=FORMAT)
logging.info('I am {}'.format(20)) # info不显示
logging.warning('I am {}'.format(20)) # warning默认级别
#-----------------------------------------------------------------------
2020-01-15 17:23:28,034 Thread info: 21064 MainThread I am 20
上例是基本的使用方法,大多数时候,使用的是info,正常运行信息的输出
日志级别和格式字符串扩展的例子;
import logging
FORMAT = '%(asctime)-15s\tThread info: %(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)
logging.info('I am {}'.format(20)) # 单一字符串
logging.info('I am %d %s', 20, 'years old.') # c风格
修改日期格式
import logging
logging.basicConfig(format="%(asctime)s %(message)s",datefmt='%Y%m%d% %I:%M:%S')
logging.warning('this event was logged.')
输出到文件
日志一般是采用 追加的方式;
import logging
logging.basicConfig(format='%(asctime)s %(message)s', filename='o:/test.log')
for _ in range(5):
logging.warning('this event was logged.')
2. Logger类
loggin模块加载的时候,会创建一个root logger。跟Logger对象的默认级别是WARNING。
root = RootLogger(WARNING) # 大约在1731行处,指定跟Logger对象的默认级别;跟logger定义;
调用logging.basicConfig来调整级别,就是对这个根Logger的级别进行修改。
构造(工厂方法)
logging.getLogger([name=None])
使用工厂方法返回一个Logger实例。
指定name,返回一个名称为name的Logger实例。如果再次使用相同的名字,是实例化一个对象。未指定name,返回根Logger实例。
层次结构
Logger是层次结构的,使用.点号分割,如'a'、'a.b'或'a.b.c.d',a是a.b的父parent,a.b是a的子child。对于foo来说,名字为foo.bar、foo.bar.baz、foo.bam都是 foo的后代;
import logging
# 父子 层次关系
root = logging.getLogger() # 根logger
print(root.name, type(root), root.parent, id(root)) # 根logger没有父
logger = logging.getLogger(__name__) # 模块级logger
print(logger.name, type(logger), id(logger.parent), id(logger))
loggerchild = logging.getLogger(__name__ + '.child') # 模块名.child 这是子logger
print(loggerchild.name, type(loggerchild), id(loggerchild.parent), id(loggerchild))
#---------------------------------------------------------------------------------
root <class 'logging.RootLogger'> None 2123278436560
__main__ <class 'logging.Logger'> 2123278436560 2123355825880
__main__.child <class 'logging.Logger'> 2123355825880 2123355826216
Level级别设置
logging的父子关系用点 间隔;
import logging
FORMAT = '%(asctime)-15s\tThread info: %(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.INFO)
logger = logging.getLogger(__name__) # 创建一个新的logger,未设定级别;
print(logger.name,type(logger))
print(logger.getEffectiveLevel()) #20
logger.info('hello1')
logger.setLevel(28) # 重新修改level ;
print(logger.getEffectiveLevel()) # 28
logger.info('hello2') # 被拦截
logger.warning('hello3 warning')
root = logging.getLogger() # 根logger
root.info('hello4 info root') # 输出成功
#------------------------------------------------------
2020-01-15 18:15:42,613 Thread info: 17568 MainThread hello1
2020-01-15 18:15:42,613 Thread info: 17568 MainThread hello3 warning
2020-01-15 18:15:42,613 Thread info: 17568 MainThread hello4 info root
__main__ <class 'logging.Logger'>
20
28
每一个logger创建后,都有一个等效的level。
logger对象可以在创建后动态的修改自己的level。
网友评论