Python日志模块logging,这一篇就够了
橙好科技logging模块教程
文章目录
- 1-logging介绍
- 2-日志作用
- 3-日志配置basicConfig
- 3-日志级别level
- 4-日志格式format
- 4-输出日志到控制台
- 5-输出日志到文件
- 6-输出日志到控制台和文件
- 7-骚操作
1-logging介绍
logging模块都知道是用来输出日志的,但是我们为什么要用它呢,他到底哪点好看?还是有特长?嘿嘿,今天超哥就来告诉你
以前我们都习惯用print,以为很方便,但是有利必有弊,print虽然能让你一时爽,后期代码部署上线,你需要挨个注释或者删除,代码冗余,费时费力。说到这里,logging的优势也就显而易见了,首先我们使用log代替print后,和print一样可以排查问题,更重要的是他可以全局统一管理,定制输出的日志格式,比如输出代码行,文件名称,日志时间,还可以根据代码逻辑分别输出调试日志和错误日志,更牛逼的是以后代码部署上线的时候,我们可以通过控制日志级别来控制哪些日志可以输出,哪些日志不再输出,是不是很强大?
2-日志作用
- 方便排查问题
- 对日志进行分级
- 方便代码维护部署
先来看下最简单的日志输出代码:
代码示例:import logginglogging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")
输出:
日志说明:这是不配置日志时默认的输出内容
1-日志级别 :2-根日志记录器 :3-日志内容
相信你已经看到了,日志只输出了后三者(级别),因为日志默认warning级别,所以其他两个更低的级别不会输出了,但是这样的日志太简单了,不具有配置性,所以我们如果想要定制化的日志,就需要basicConfig了。
3-日志配置basicConfig
日志输出统一使用basicConfig进行配置,配置的参数如下:
参数 | 描述 |
---|---|
filename | 指定日志输出的文件名(fileHandler)如果不指定则默认输出到控制台。eg:filename=‘automatio.log’ |
filemode | 指定打开文件的模式,如果指定了filename(如果文件模式未指定,则默认为’a’)。eg: filemode=‘a’ |
level | 将根记录器级别设置为指定的级别。eg:level=loggin.INFO |
format | 为处理程序使用指定的格式字符串。eg: format=’%(name)s-%(asctime)s’ |
datefmt | 使用指定的日期/时间格式。 |
handlers | 如果指定,这应该是一个已经创建的处理程序的迭代器添加到根记录器。否则默认输出到控制台 |
代码示例:def log():#使用basicConfig配置日志,level和formatlogging.basicConfig(level=logging.INFO, format='%(name)s-%(asctime)s-%(levelname)s-%(message)s')#使用getLogger方法设置日志记录器,不设置的话默认:rootlogger = logging.getLogger('Test')return loggerlogger = log()
logger.info("这是定制化的日志")
输出:
3-日志级别level
log一共五个级别,分别是:
级别 | 数值 |
---|---|
CRITICAL | 50 |
ERROR | 40 |
WARNING | 30,默认 |
INFO | 20 |
DEBUG | 10 |
NOTSET | 0 |
日志配置:basicConfig,默认控制台输出,默认日志级别是WARNING,低于该级别的就不输出了
级别排序 :CRITICAL > ERROR > WARNING > INFO > DEBUG
关于级别的解释:
debug : 级别最低的日志,最为详细的日志,一般用来排查问题
info : 一般可作为正常输出的日志
warning : 一般用来输出警告的日志,但是不会影响代码执行
error : 一般在出错的代码逻辑中使用,说明目前代码报错,用来输出具体的错误信息
critical : 最高级别日志,一般用在程序崩溃的日志输出
这时候,如果需要显示低于WARNING级别的内容,可以引入NOTSET级别来显示:
代码示例1:import logging # 引入logging模块logging.basicConfig(level=logging.INFO) # 设置日志级别
logging.debug("这是debug级别的日志") #因为预设置的日志级别为INFO,所以小于该级别的日志不输出
logging.info("这是debug级别的日志") #正常输出
输出:
日志输出解释:
第一部分:INFO-为日志级别;
第二部分:root-为默认的日志记录器名称;如果通过getlogger指定日志记录器名称,则root会改为指定的名称
第三部分:这是debug级别的日志-这是日志内容
代码示例2:def log():logging.basicConfig(level=logging.DEBUG)logger = logging.getLogger('test')return loggerlogger = log()
logger.debug("这是设置了日志记录器的样子")
输出:
4-日志格式format
日志格式:%(name)s -------日志器名称,如果不通过getlogger指定,则默认为root%(asctime)s -------日志生成时间%(filename)s ------输出日志的文件名称(源代码文件名)%(lineno)d -------源代码的行号%(levelname)s -----日志级别%(message)s -------日志内容%(thread)d --------线程ID。可能没有%(threadName)s ----线程名。可能没有%(process)d -------进程ID。可能没有
根据需要添加指定的日志格式,可以让日志输出更加有效,排查问题更加方便。
代码示例:def log():#添加了两个参数,level和format(format内部出了固定的格式字符串,其他可以随便添加)logging.basicConfig(level=logging.INFO,format='%(name)s-%(asctime)s - %(filename)s-[line:% (lineno)d] - %(levelname)s -日志信息: %(message)s')logger = logging.getLogger('test')return loggerlogger = log()
logger.info("这是添加了日志格式的样子")
输出:
4-输出日志到控制台
basicConfig只要不配置filename参数,日志默认就会输出到控制台。
代码示例:#1、导入Logging包
import loggingdef log():#2、设置基础配置信息(level:日志级别,格式:)logging.basicConfig(level=logging.INFO,format='%(asctime)s-%(name)s-%(levelname)s-%(message)s')#3、定义日志名称getlogger,在输出日志的时候显示logger = logging.getLogger("log_demo")return loggerif __name__ == '__main__':logger = log()logger.debug("debug")logger.info("info")logger.warning("warning")
输出:
5-输出日志到文件
basicConfig只要配置filename参数,日志默认就会输出到指定文件。
代码示例:#1、导入Logging包
import loggingdef log():#2、设置基础配置信息(level:日志级别,格式:)logging.basicConfig(filename='my.log',level=logging.INFO,format='%(asctime)s-%(name)s-%(levelname)s-% (message)s')#3、定义日志名称getlogger,在输出日志的时候显示logger = logging.getLogger("log_demo")return loggerif __name__ == '__main__':logger = log()logger.debug("我是debug日志")logger.info("我是info日志")logger.warning("我是warning日志")
输出:(当前目录下会自动生成一个名为“my.log”的文件)文件内容如图:
注:如果pycharm打开的日志乱码,修改一下pycharm右下角的编码格式为GBK即可
图:控制台和文件你都会了,还想怎样?
6-输出日志到控制台和文件
上面我们可以做到让日志输出到控制台,也可以让其输出到指定文件,那如果我们想要即输出到控制台,也输出到文件该怎么办呢,这时候就用到handler了。
在讲handler之前,我们先来看下log的高级需要掌握哪些东西,logging模块包括logger,handler,filter,formatter这四个基本概念。:
- logger 提供了应用程序可以直接使用的接口
- handler将(logger创建的)日志记录发送到合适的目的输出
- filter提供了细度设备来决定输出哪条日志记录
- formatter决定日志记录的最终输出格式
- logger:提供日志接口,供应用代码使用。logger最常用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
- handler:将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。
- filter:提供一种优雅的方式决定一个日志记录是否发送到handler。
- formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。
那么我们想要输出到控制台和文件就得需要两个handler,如下:
logging.StreamHandler: 日志输出到流,可以是sys.stderr、sys.stdout或者文件
logging.FileHandler: 日志输出到文件
图:废话少说,上代码
函数写法:
代码示例:'''
功能描述:实现控制台和文件同时记录日志的功能
编写人:liangchao
编写日期:2021年2月8日步骤分析:1-配置日志记录器名称2-配置日志级别3-配置日志格式(可以分别设置,也可以统一设置)4-创建并添加handler-控制台5-创建并添加handler-文件6-提供对外获取logger'''import logging
import sysdef log():# 1 - 配置日志记录器名称logger = logging.getLogger('AutoTest')# 2-配置日志级别logger.setLevel(logging.DEBUG)# 3-配置日志格式(可以分别设置,也可以统一设置)format = logging.Formatter('%(name)s-%(asctime)s-%(message)s')# 4 - 创建并添加handler - 控制台sh = logging.StreamHandler()sh.setFormatter(format)logger.addHandler(sh)# 5 - 创建并添加handler - 文件fh = logging.FileHandler('test.log')fh.setFormatter(format)logger.addHandler(fh)# 6 - 提供对外获取loggerreturn loggerif __name__ == '__main__':logger = log()logger.info('使用函数定义的log方法')
下面 是面向对象的写法:
class Log():def __init__(self):"""配置logger记录器名称配置日志级别配置日志格式"""self.logger = logging.getLogger('AutoTest')self.logger.setLevel(logging.DEBUG)self.format = logging.Formatter('%(name)s-%(asctime)s-%(message)s')def __addstreamHan(self):"""定义添加控制台输出handler"""sh = logging.StreamHandler()sh.setFormatter(self.format)self.logger.addHandler(sh)def __addfileHan(self):"""定义添加写入文件handler"""fh = logging.FileHandler('test.log')fh.setFormatter(self.format)self.logger.addHandler(fh)def getLog(self):"""定义对外提供logger的方法注意:此处的方法不要定义为getLogger,否则就是重写log的方法了"""self.__addstreamHan()self.__addfileHan()return self.loggerif __name__ == '__main__':logger = Log().getLog()logger.info('1234?')
注:
1-如何实现部署上线的时候通过控制级别来搞定不输出额外日志?
答:假设我们定义日志级别为DEBUG,在调试输出的时候大部分使用的是logger.debug(‘xxxx’),这时候只需要修改日志级别为更高级别,那么级别为debug的日志就不会再输出
2-如何实现控制台和文件分别输出不同日志格式的日志
答:只需要在定义不同的handler时定义不同的格式即可,比如:
format1 = logging.Formatter(‘xxxxx’)
format2 = logging.Formatter(‘xxxxx’)
fh.setFormatter(self.format1)
sh.setFormatter(self.format2)
3-日志打印重复的问题
坑:
在我们导入写好的log文件时,比如,当前目录下存在文件:streamAndFileLog.py(内容同上方函数写法),在另外一个文件中导入该文件:
from 日志模块.streamAndFileLog import loglog().info('xxx1')log().info('xxx2')log().info('xxx3')
输出:
这个结果什么鬼?明明三句话,打印出来这么多,这其实是log在使用的常遇到的坑,通过debug你会发现,每次调用都会创建句柄,所以重复,如图:
第一句调用之后,handlers里面已经存在了两个handler,分别是控制台句柄StreamHandler和文件句柄FileHandler,下面图中是第二句调用添加句柄
执行后会发现handlers里面多了一个StreamHandler
怎么解决这种情况,有两个方案,咱们分别列出两种方案代码:
第一种,第一使用单例模式,在log.py文件中增加一行:logger = log() ,这句的作用就是提前实例化好对象,其他模块使用都适用该对象,所以别的模块导入语句要改成:from xxx包.log import logger ,然后使用logger.info(‘xxxx’) 输出日志即可
……省略上方代码# 6 - 提供对外获取logg的方法return logger
#增加一行
logger = log()if __name__ == '__main__':logger = log()logger.info('使用函数定义的log方法')
导入:
from 日志模块.streamAndFileLog import loggerlogger.info('xxx1')logger.info('xxx2')logger.info('xxx3')
输出:
第二个方案:log.py每次判断handlers是否已存在
……# 4 - 创建并添加handler - 控制台sh = logging.StreamHandler()sh.setFormatter(format)# 5 - 创建并添加handler - 文件fh = logging.FileHandler('test.log')fh.setFormatter(format)#在新增handler时判断是否为空if not logger.handlers:logger.addHandler(sh)logger.addHandler(fh)# 6 - 提供对外获取logg的方法return loggerif __name__ == '__main__':logger = log()logger.info('使用函数定义的log方法')
导入文件代码保持不变:
from 日志模块.streamAndFileLog import loglog().info('xxx1')log().info('xxx2')log().info('xxx3')
输出:
针对面向对象的方案同样是以上两个,请同学们自行解决,如果有任何问题可以联系橙好科技。
介绍到这里,对于log的掌握已经满足日常工作的需要了,接下来的内容可以作为扩展,不再要求必须掌握
7-骚操作
下面看看两种比较实用的日志handler,RotatingFileHandler和TimedRotatingFileHandler
- logging.handlers.RotatingFileHandler -> 按照大小自动分割日志文件,一旦达到指定的大小重新生成文件
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
代码示例:
import logging
import logging.handlers
import sys
import timedef log():# 1 - 配置日志记录器名称logger = logging.getLogger('AutoTest')# 2-配置日志级别logger.setLevel(logging.DEBUG)# 3-配置日志格式(可以分别设置,也可以统一设置)format = logging.Formatter('%(name)s-%(asctime)s-%(message)s')# 5 - 创建并添加handler - 文件,filename为生成日志的文件名称,模式为追加,最大日志文件为100个字节,备份文件的最大数量为5个fh = logging.handlers.RotatingFileHandler(filename="rotating.log", mode='a', maxBytes=100, backupCount=5)fh.setFormatter(format)logger.addHandler(fh)# 6 - 提供对外获取logg的方法return loggerif __name__ == '__main__':logger = log()while True:time.sleep(0.01)logger.info('日志按照文件大小自动切割')
输出:
- logging.handlers.TimedRotatingFileHandler -> 按照时间自动分割日志文件
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
代码示例:
import logging
import logging.handlers
import sys
import timedef log():# 1 - 配置日志记录器名称logger = logging.getLogger('AutoTest')# 2-配置日志级别logger.setLevel(logging.DEBUG)# 3-配置日志格式(可以分别设置,也可以统一设置)format = logging.Formatter('%(name)s-%(asctime)s-%(message)s')# 添加TimedRotatingFileHandler,间隔2s切割一次,保留3个旧log文件备份fh = logging.handlers.TimedRotatingFileHandler("timeRotaingHandler.log", when='S', interval=2, backupCount=3)# 设置后缀名称,跟strftime的格式一样fh.suffix = "%Y-%m-%d_%H-%M-%S.log"fh.setFormatter(format)logger.addHandler(fh)# 6 - 提供对外获取logg的方法return loggerif __name__ == '__main__':logger = log()while True:time.sleep(0.01)logger.info('日志按照时间自动切割')
输出:
最终log文件咱们就算介绍完了,还不赶紧关注,扫码!
Python日志模块logging,这一篇就够了相关推荐
- Python日志详解【两篇就够了系列】--第一篇logging
目录 第一章 Python日志模块logging详解 一.logging的框架 1.Logger 2.Handler 3.Formater类 4.Filter类 二.Log级别 三.Log格式 四.常 ...
- Python日志模块logging高级用法
推荐图书: <Python程序设计(第3版)>,(ISBN:978-7-302-55083-9),董付国,清华大学出版社,2020年6月第1次印刷,2021年12月第11次印刷,山东省一流 ...
- python logging模块的作用_【python】【logging】python日志模块logging常用功能
logging模块:应用程序的灵活事件日志系统,可以打印并自定义日志内容 logging.getLogger 创建一个log对象 >>> log1=logging.getLogger ...
- python日志模块----logging
使用Python的logging模块能很好的帮我们完成程序的日志功能,其实它跟Java中的log4j有不少相似的地方.下面记录下今天学习到的logging的知识(因为有一些还没真正使用过,不知道是否说 ...
- Python日志详解【两篇就够了系列】--第二篇loguru
目录 第二章 Python日志loguru库详解 一.loguru简介 二.日志级别 三.loguru日志常用参数配置解析 1.rotation 2.retention 3.compression 4 ...
- python 日志模块 logging
如何使用python自带的 logging 模块实现日志功能 1.初始化一个logger对象 1)引入模块 import os import logging import sys 2)初始化变量,声明 ...
- Python:日志模块logging的应用
2019独角兽企业重金招聘Python工程师标准>>> 在Python中,上面以实现的和已经实现的,均可以使用logging模块迅速搞定,且仅仅只需要一个配置文件,两行代码,实现过程 ...
- python logging模块的作用_Python 日志模块logging分析及使用-2
本文作为Python日志模块的补充,主要介绍日志回滚RotatingFileHandler和TimedRotatingFileHandler的使用,以及其所带来的问题.Logger对象的日志等级是如何 ...
- 【Python】—日志模块logging使用详解1
文章目录 1.日志级别 2.logging流程 3.几个重要的类 3.1 Logger类 1) 最常用的配置方法 2) 创建`Logger`对象`logging.getLogger([name])` ...
最新文章
- 一条 update 语句引起的事故,这回让开发长长记性!!
- QQ网页链接打开本地QQ.exe原理
- 实战Python:详解利用Python和Pygame实现飞机大战
- linux 修改文件夹权限_Linux新手非常实用的20个命令
- IntelliJ IDEA如何去掉xml文件背景色
- 8.input设备(input子系统)驱动
- 关于fragstats内存问题
- 搬运: CVonline: 图像数据库(二) (更新于20190821)
- 中国移动一句话 苹果丢掉“两个诺基亚”_-Chaz-_新浪博客
- 到大观园晨光茶社现场听了场相声
- win10应用商店恢复
- 第21批符合道路运输车辆卫星定位系统标准 及规范的车载终端
- 洛谷 P5322 [BJOI2019]排兵布阵
- DOM是什么意思-前端入门
- 【转】ST、SC、FC、LC光纤接头区别
- 时间同步,自动驾驶里的花好月圆
- 简单的《找不同汉字版》,来考考你的眼力吧
- Excel查找字符串下标(findsearch)
- Web项目的Excel文件上传、解析、导入
- 哪吒之魔童降世视听语言影评_《哪吒之魔童降世》影评4篇