logging 模块是一个较庞大的模块。具备较完备的日志体系。
主要分为:主体 Logger - 处理器 - 格式器logging 为 python 内置模块,无需安装。
导入方式: import logging 便可html
DEBUG < INFO < WARNING < ERROR < FATAL DEBUG : 开发调试的一些信息(print调试。。。) INFO: 程序运行过程的重要信息(不宜过多) WARNING: 不影响程序运行的小问题,警告一下。记录下来以备之后解决。 ERROR: 影响程序, 有点严重。须要处理, 否则程序 (可能,可能)就挂了。 FATAL: 严重影响程序,马上从新排查,修改代码吧。
经常使用分为: (由外到里的包含关系)python
为了方便说明,接下来,我会把上面的组件“由里到外”讲解。git
格式器:用来定义一些打印信息的字符串格式化的语法。
初始化一个 格式器:github
fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 console_formatter = logging.Formatter(fmt=fmt) # 实例化格式器,并把格式传进来
理解方式:服务器
我把上例结果贴一下,你可能会看明白些:函数
>>> [2019-09-10 18:23:19,347] [logging11.py: 15] [WARNING] => 哈哈哈 asctime 是日期 filename 是文件名 lineno 是代码行 levelname 是日志等级名 (就是上面说的 INFO WARNING ERROR之类的) message 是 你要打印的日志信息 (下面会讲到,这里先小小埋一个点)
处理器:用来装载上面说的 “格式器”,并处理日志 (处理器有不少种,按需选1个便可,下面说2种经常使用的):
初始化一个 “流处理器” (比较经常使用):线程
handler = logging.StreamHandler()
或初始化一个 “文件处理器” (源码明确写了, 它继承的是 上面的 “流处理器”。一般用来日志持久化):debug
handler = logging.FileHandler('mylog.log', mode='a', encoding='utf-8') # 没必要解释了吧。 这API语法很熟悉了吧。 这不就是咱们经常使用的文件 open 语法么。。。。
装载“格式器” (差点忘了吧。实例化的格式器,还没用呢, 就是在这里装载)调试
handler.setFormatter(fmt=file_formatter)
注意: 虽然 handler对象就能够用 setLevel()设置日志等级,但我不推荐在这里设置。继续往下看日志
Logger: 用来装载 “处理器的”。
实例化Logger有两种方法:
方法1:(非共享式建立, 不推荐)
log= logging.Logger(name='my_log', level='INFO') # name 是给 Logger 起的名 # level是 日志等级(注意要大写), 开篇咱们讲到过, WARNING, INFO, ERROR 这些。
方法2:(Log池共享式建立, 推荐)
log = logging.getLogger(name='console') # 有则取出,无则建立 # name若是不传,则取出root Logger (root Logger是logging默认给咱们提供的,我通常不用)
说一下这两种方法的区别:
装载 "处理器" :(差点忘了吧, 上面定义的 处理器,还没用呢, 就是在这里用的):
log.addHandler(handler)
设置日志等级 (这步可忽略)
log.setLevel('ERROR') 其实上面咱们实例化Logger的时候,咱们就已经传了一个 level参数,设置好了 日志等级。 因此 log.setLevel() 这个能够不设置 (包括前面提到,handler也有 setLevel) handler.setLevel()
开始输出日志信息,有如下日志等级相对应的API:
log.debug ("这是一条 调试 日志") log.info ("这是一条 显示主要信息 日志") log.warning('这是一条 警告 日志') log.error ("这是一条 错误 日志") log.fatal ("这是一条 致命错误 日志") ### 回顾咱们前面讲的 Formatter 格式器 咱们第一个讲的就是格式器, 并说了一下经常使用格式。 其中有个 %(message)s, 它就是占位上面这些API里面的参数 eg: log.info('哈哈哈') %(message)s格式 占位输出的就是 哈哈哈 还有个 %(levelname)s,它就是占位上面这些API的方法名 eg: log.info('xxx') %(levelname)s 格式占位输出的就是 info
若是你对日志等级与日志的做用感到模糊,你必定要看我接下来的例子!!!!!!!!
开篇时我就提过: 日志等级排序(弱=>强) => (DEBUG < INFO < WARNING < ERROR < FATAL)你设置了一个日志等级 。那么你所用上面API对应的等级若“强于或等于” 此设定的等级,日志才会被处理
emmmmm, 若是没听懂,就当我放P了。。。 说的越正式,越不容易理解。 咱们仍是看下面的例子吧~~
日志等级理解的小例子:
log.setLevel('WARNING') 你看咱们设置的日志等级是 WARNING log.debug("这是一条 调试 日志") # 这个 debug(), 你能够去开篇列的"日志等级排序"那里瞅一眼。 # debug 比 warning 弱, 因此 这条日志是 不会 被处理的。 # (白话理解:"我给的界限是warning, 你一个 debug等级过低了,问题不严重。不配被记录。") log.info("这是一条 显示主要信息 日志") # 同理, info 也比 warning 弱, 此条日志也 不会 被处理 log.warning('这是一条 警告 日志') # warning == warning (我前面说了,强于 或 等于) 因此此条日志会被处理 log.error("这是一条 错误 日志") # error 比 warning 强, 因此此条日志 会 被处理 log.fatal("这是一条 致命错误 日志") # fatal 比 warning 强, 因此此条日志 会 被处理 # 再白话一下:"你给个人容忍程度是 warning, 而你的这条日志都致命错误了,我确定处理你啊"
思考!上例我一直说一句话 “xxxxx, 此条日志才会被处理”。
那么这个“ 处理” ,究竟是处理什么呢???
这时不妨回头看看,上面讲的 “处理器”, 嗯, 没错。 这些日志就是 “处理器” 处理的。
业务需求以下(随便举个案例,不必定有用):
代码以下(本身使用的话,封装一下比较好):
import logging # 日志等级排序(弱-> 强): DEBUG < INFO < WARNING < ERROR < FATAL fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 file_formatter = logging.Formatter(fmt=fmt) # 定义格式器, 把格式塞进来 file_handler = logging.FileHandler('mylog.log', mode='a', encoding='utf-8') # 定义文件处理器 file_handler.setFormatter(fmt=file_formatter) # 给文件处理器设置 一个 格式器 file_handler.setLevel('WARNING') # 给此处理器设置 日志等级 console_handler = logging.StreamHandler() # 定义流处理器,用于输出到终端 # StreamHandler未设置格式器,它会默认给你设置一个 %(message)s,即只有日志内容,没有日期文件名等 console_handler.setLevel('DEBUG') # 给流处理器设置 日志等级 log = logging.getLogger(name='file_log') # log池中取出一个log(若没有则新建) log.addHandler(file_handler) # 添加一个文件处理器(格式化 输出到 文件) log.addHandler(console_handler) # 再添加一个流处理器(无格式 输出到 终端) log.info('我只会输出到终端') # 由于 info只比 console_handler 设置的 DEBUG强 log.error('我既会输出到终端, 又会输出到文件') # 由于error 比 console_handler 设置的 DEBUG 强, 同时 error 也比 file_handler 设置的 WARNING 强
运行结果:
终端输出: >> 我只会输出到终端 我既会输出到终端, 又会输出到文件 mylog.log 文件中: [2019-09-10 23:54:59,055] [logging11.py: 20] [ERROR] => 我既会输出到终端, 又会输出到文件
这种方式只方便了一点点,但不灵活。
前面咱们花了好大力气,
其实 logging体系中, 有一个默认初始的 Logger, 叫作 root Logger.
咱们不须要实例化它,也不须要实例化"格式器", 也不须要实例化控制器。
一行API就可使用它 (默认是输出到终端的):
import logging fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 logging.basicConfig( # 默认使用的就是 root Logger level='DEBUG', # 设置日志等级为DEBUG format=fmt, # 设置格式 ) logging.info('我只会输出到终端') 运行结果: >> [2019-09-11 00:15:55,219] [logging11.py: 30] [INFO] => 我只会输出到终端
若是想输出到文件,那么只需加 filename 和 filemode 两个参数便可:
import logging fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 logging.basicConfig( level='DEBUG', format=fmt, filename='mylog.log', # 文件名 filemode='a' # 文件操做符 ) 运行结果: mylog.log文件: [2019-09-11 00:20:22,396] [logging11.py: 32] [INFO] => ��ֻ��������ն�
但你发现没,往文件里面输出乱码了, 用耳朵都能想出来,咱们没有配置 encoding。。。
可是,我告诉你, basicConfig() 是没有 encoding参数的。 那咋整 ??
但它有个参数叫作 handlers,handlers熟悉吧,没错就是咱们上面讲的 "处理器", 复数说明能够传多个
logging.basicConfig( level='DEBUG', format=fmt, handlers=[ logging.FileHandler(filename='mylog.log',mode='a',encoding='utf-8') ] # 看这里这个处理器的定义方法,和以前讲过的如出一辙。在这里咱们能够配 encoding ) # 这样就不会乱码了
Note: 以上就是用 logging.baseConfig() 简单日志实现
说了它是投机取巧,由于除了文件乱码有问题以外, 它还欠缺灵活性。
好比你想一想对不一样级别的日志,用不一样格式输出出来。这时你单用basicConfig一行是搞不定的。
因此仍是推荐用 getLogger()那套组合。
logging模块其实还有不少不少功能:
过滤器:(其实还有个这个组件,但我没用过,就没说)
格式器:(前面给了官档大全,里面还有根据进程、线程的(PID,TID, tName,pName)等格式来输出日志。)
控制器:(我只说了 stream 和 file),其实还有不少,它们都在logging.handlers模块下:
from logging.handlers import ( RotatingFileHandler, # 经过设置文件大小阈值,超出这个阈值,就会将日志转存新文件 TimedRotatingFileHandler, # 设置时间间隔,每过这个间隔,就会将日志转存新文件 HTTPHandler, # 经过HTTP协议将日志输出到远程服务器,(只支持 GET 和 POST) SMTPHandler, # 经过SMTP协议,将日志输出到远程邮箱了 SocketHandler, # 经过TCP协议发送到远程服务器。。。 DatagramHandler, # 经过UDP协议发送到远程服务器。。。 QueueHandler, # 发到队列中(若是想发RabbitMQ之类的,能够去github找别人写的成品) ) # 这些用法也很简单,看官档,或者用Pycharm ctrl+左键点进源码,看一下__init__()参数实例化便可 # 实例化后,用 xxx.addHandler() 添加到 logger便可使用 (和前面讲的 file和stream用法同样)
还可作成各种型配置文件使用:https://docs.python.org/3/lib...
官档案例大全:https://docs.python.org/3/how...