python之logging模块
2021/4/23 12:25:27
本文主要是介绍python之logging模块,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
网上已经有很多logging模块的资料,在这里只是把看到的几片博客总结一下,也是为了符合自己阅读习惯。
参考的博客地址:
http://www.cnblogs.com/dahu-daqing/p/7040764.html
https://www.cnblogs.com/louis-w/p/8567434.html
https://www.cnblogs.com/testdjt/p/7834856.html
具体logging模块的具体作用,在上面两片博客里面都很清楚。
logging模块的框架:
- Loggers: 可供程序直接调用的接口,app通过调用提供的api来记录日志
- Handlers: 决定将日志记录分配至正确的目的地
- Filters:对日志信息进行过滤, 提供更细粒度的日志是否输出的判断
- Formatters: 自定义最终记录打印的格式布局
loggers:
loggers 就是程序可以直接调用的一个日志接口,可以直接向logger写入日志信息。logger并不是直接实例化使用的,而是通过logging.getLogger(name)来获取对象,事实上logger对象是单例模式,logging是多线程安全的,也就是无论程序中哪里需要打日志获取到的logger对象都是同一个。但是不幸的是logger并不支持多进程,这个在后面的章节再解释,并给出一些解决方案。
【注意】loggers对象是有父子关系的,当没有父logger对象时它的父对象是root,当拥有父对象时父子关系会被修正。举个例子,logging.getLogger("abc.xyz") 会创建两个logger对象,一个是abc父对象,一个是xyz子对象,同时abc没有父对象,所以它的父对象是root。但是实际上abc是一个占位对象(虚的日志对象),可以没有handler来处理日志。但是root不是占位对象,如果某一个日志对象打日志时,它的父对象会同时收到日志,所以有些使用者发现创建了一个logger对象时会打两遍日志,就是因为他创建的logger打了一遍日志,同时root对象也打了一遍日志。
handlers:
Handlers 将logger发过来的信息进行准确地分配,送往正确的地方。举个栗子,送往控制台或者文件或者both或者其他地方(进程管道之类的)。它决定了每个日志的行为,是之后需要配置的重点区域。
每个Handler同样有一个日志级别,一个logger可以拥有多个handler也就是说logger可以根据不同的日志级别将日志传递给不同的handler。当然也可以相同的级别传递给多个handlers这就根据需求来灵活的设置了。
logging中包含的handler主要有以下几种:
handler名称:位置;作用 StreamHandler:logging.StreamHandler;日志输出到流,可以是sys.stderr,sys.stdout或者文件 FileHandler:logging.FileHandler;日志输出到文件 BaseRotatingHandler:logging.handlers.BaseRotatingHandler;基本的日志回滚方式 RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚 TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件 SocketHandler:logging.handlers.SocketHandler;远程输出日志到TCP/IP sockets DatagramHandler:logging.handlers.DatagramHandler;远程输出日志到UDP sockets SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址 SysLogHandler:logging.handlers.SysLogHandler;日志输出到syslog NTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到Windows NT/2000/XP的事件日志 MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定buffer HTTPHandler:logging.handlers.HTTPHandler;通过"GET"或者"POST"远程输出到HTTP服务器
Filters:
Filters 提供了更细粒度的判断,来决定日志是否需要打印。原则上handler获得一个日志就必定会根据级别被统一处理,但是如果handler拥有一个Filter可以对日志进行额外的处理和判断。例如Filter能够对来自特定源的日志进行拦截or修改甚至修改其日志级别(修改后再进行级别判断)。
logger和handler都可以安装filter甚至可以安装多个filter串联起来。
formatters:
Formatters 指定了最终某条记录打印的格式布局。Formatter会将传递来的信息拼接成一条具体的字符串,默认情况下Format只会将信息%(message)s直接打印出来。Format中有一些自带的LogRecord属性可以使用,如下表格:
asctime %(asctime)s 日志事件发生的时间--人类可读时间,如:2003-07-08 16:49:45,896 created %(created)f 日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值 relativeCreated %(relativeCreated)d 日志事件发生的时间相对于logging模块加载时间的相对毫秒数(目前还不知道干嘛用的) msecs %(msecs)d 日志事件发生事件的毫秒部分 levelname %(levelname)s 该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') levelno %(levelno)s 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50) name %(name)s 所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger message %(message)s 日志记录的文本内容,通过 msg % args计算得到的 pathname %(pathname)s 调用日志记录函数的源码文件的全路径 filename %(filename)s pathname的文件名部分,包含文件后缀 module %(module)s filename的名称部分,不包含后缀 lineno %(lineno)d 调用日志记录函数的源代码所在的行号 funcName %(funcName)s 调用日志记录函数的函数名 process %(process)d 进程ID processName %(processName)s 进程名称,Python 3.1新增 thread %(thread)d 线程ID threadName %(thread)s 线程名称
一个Handler只能拥有一个Formatter 因此如果要实现多种格式的输出只能用多个Handler来实现。
在formatters中levelname中可以设置日志的级别,日志的级别有以下几种,如下:
日志等级:使用范围 FATAL:致命错误 CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用 ERROR:发生错误时,如IO操作失败或者连接问题 WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误 INFO:处理请求或者状态变化等日常事务 DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态
低于设置日志级别的信息,将会被忽略不会被记录!
logging中的两个方法:
- logging.basicConfig(**kwargs)
- 为日志模块配置基本信息。kwargs 支持如下几个关键字参数:
filename :日志文件的保存路径。如果配置了些参数,将自动创建一个FileHandler作为Handler;
filemode :日志文件的打开模式。 默认值为’a’,表示日志消息以追加的形式添加到日志文件中。如果设为’w’, 那么每次程序启动的时候都会创建一个新的日志文件;
format :设置日志输出格式;
datefmt :定义日期格式;
level :设置日志的级别.对低于该级别的日志消息将被忽略;
stream :设置特定的流用于初始化StreamHandler;
- 为日志模块配置基本信息。kwargs 支持如下几个关键字参数:
logging.getLogger([name])
- 创建Logger对象。日志记录的工作主要由Logger对象来完成。在调用getLogger时要提供Logger的名称(注:多次使用相同名称来调用getLogger,返回的是同一个对象的引用。),Logger实例之间有层次关系,这些关系通过Logger名称来体现,如:
p = logging.getLogger(“root”)
c1 = logging.getLogger(“root.c1”)
c2 = logging.getLogger(“root.c2”)
例子中,p是父logger, c1,c2分别是p的子logger。c1, c2将继承p的设置。如果省略了name参数, getLogger将返回日志对象层次关系中的根Logger。
- 创建Logger对象。日志记录的工作主要由Logger对象来完成。在调用getLogger时要提供Logger的名称(注:多次使用相同名称来调用getLogger,返回的是同一个对象的引用。),Logger实例之间有层次关系,这些关系通过Logger名称来体现,如:
基本使用
简单的直接在控制台输出:
In [6]: logging.info("this is info message!") In [7]: logging.warning("This is warnings messages") WARNING:root:This is warnings messages
logging中默认的日志级别是warning,因此info信息不会打印,只有在warning级别以上的信息才会打印。
上述的日志信息为默认的格式信息,下面使用basicconfig对日志信息进行设置。
In [1]: import logging In [2]: logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(name)s - %(process)d - %(message)s") In [3]: logging.debug("this is debug meg")2018-08-04 14:19:50,113 - DEBUG - root - 25188 - this is debug meg In [4]: logging.info("this is info meg")2018-08-04 14:20:03,873 - INFO - root - 25188 - this is info meg In [5]: logging.warning("this is warning meg")2018-08-04 14:20:25,041 - WARNING - root - 25188 - this is warning meg
上述的日志信息,按照自定义的日志格式输出。
日志输出到文本:
#!/usr/bin/env python#*-* coding:utf-8 *-*import logging LOG_FORMAT = "%(asctime)s - %(name)s - %(process)d - %(message)s"DATE_FORMAT = "%Y-%m-%d %H:%M:%S %P"logging.basicConfig(filename="log.txt", level=logging.ERROR, format=LOG_FORMAT, datefmt=DATE_FORMAT) logging.debug("This is a debug log.") logging.error("this is a error") logging.critical("This is a critical log.")=====执行结果=====[root@os1 workgit]# python log.py #控制台并不会输出任何结果[root@os1 workgit]# cat log.txt #文本输出2018-08-04 15:20:29 pm - root - 30511 - this is a error2018-08-04 15:20:29 pm - root - 30511 - This is a critical log. [root@os1 workgit]#
日志输出到控制台和文本
= logging.getLogger(== logging.Formatter(= logging.FileHandler(= logging.StreamHandler() console.setLevel(logging.INFO) console.setFormatter(formatter) ) #整个过程就是先初始化一个logger,然后初始化handler,最后把handler添加进logger!
执行结果:
[root@os1 workgit]2018-08-04 15:08:12,266 - - INFO - Start 2018-08-04 15:08:12,267 - - WARNING -2018-08-04 15:08:12,267 - - INFO -[root@os1 workgit]2018-08-04 15:08:12,266 - - INFO - Start 2018-08-04 15:08:12,267 - - WARNING -2018-08-04 15:08:12,267 - - INFO - Finish 【疑问】 在filehandler中设置了日志的默认级别为debug,但是文件中的调试信息并没有打出,handler的setlevel设置与logger的setlevel设置究竟是怎么样生效的? 未解决!!!!!!!!!!!!
上面的设置已经实现了在控制台和日志中打印输出日志的功能!
几点说明
logging.basicConfig()
函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作的,多次调用的设置并不是累加操作。- 日志器(Logger)是有层级关系的,上面调用的logging模块级别的函数所使用的日志器是
RootLogger
类的实例,其名称为'root',它是处于日志器层级关系最顶层的日志器,且该实例是以单例模式存在的。 - 如果要记录的日志中包含变量数据,可使用一个格式字符串作为这个事件的描述消息(logging.debug、logging.info等函数的第一个参数),然后将变量数据作为第二个参数*args的值进行传递,如:
logging.warning('%s is %d years old.', 'Tom', 10)
,输出内容为WARNING:root:Tom is 10 years old.
- logging.debug(), logging.info()等方法的定义中,除了msg和args参数外,还有一个**kwargs参数。它们支持3个关键字参数:
exc_info, stack_info, extra
,下面对这几个关键字参数作个说明。
关于exc_info, stack_info, extra关键词参数的说明:
- exc_info: 其值为布尔值,如果该参数的值设置为True,则会将异常异常信息添加到日志消息中。如果没有异常信息则添加None到日志信息中。
- stack_info: 其值也为布尔值,默认值为False。如果该参数的值设置为True,栈信息将会被添加到日志信息中。
- extra: 这是一个字典(dict)参数,它可以用来自定义消息格式中所包含的字段,但是它的key不能与logging模块定义的字段冲突。
这些字段介绍,参考上面的第三个博文。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在博文开始的时候,说明了logging模块的四个核心组件,这个四个核心组件彼此之间是怎么工作的以及各自又是怎么工作的?
四个组件的描述:
- 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;
- 不同的处理器(handler)可以将日志输出到不同的位置;
- 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
- 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
- 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。
简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。
具体模块的功能介绍,推荐上面博文的第三篇:https://www.cnblogs.com/testdjt/p/7834856.html
捕捉异常
在python中使用traceback追踪一些错误的信息,这里使用logging.error!
#!/usr/bin/env python#*-* coding:utf-8 *-*import logging logger = logging.getLogger(__name__) logger.setLevel(level = logging.INFO) handler = logging.FileHandler("log.txt") handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) console = logging.StreamHandler() console.setLevel(logging.INFO) logger.addHandler(handler) logger.addHandler(console) logger.info("Start print log") logger.debug("Do something") logger.warning("Something maybe fail.")try: open("sklearn.txt","rb")except (SystemExit,KeyboardInterrupt): raiseexcept Exception: logger.error("Faild to open sklearn.txt from logger.error",exc_info = True) #logger.error("Faild to open sklearn.txt from logger.error")logger.info("Finish")#通过注释可以查看exc_info = True参数输出的信息
输出的结果如下:
-----------注释前----------------[root@os1 workgit]# python log.pyStart print log Something maybe fail. Faild to open sklearn.txt from logger.error Traceback (most recent call last): File "log.py", line 21, in open("sklearn.txt","rb") IOError: [Errno 2] No such file or directory: 'sklearn.txt'Finish-----------注释后-----------------[root@os1 workgit]# python log.pyStart print log Something maybe fail. Faild to open sklearn.txt from logger.error Finish----------注释前日志文件中的结果---[root@os1 workgit]# cat log.txt 2018-08-04 15:47:55,656 - __main__ - INFO - Start print log2018-08-04 15:47:55,656 - __main__ - WARNING - Something maybe fail.2018-08-04 15:47:55,656 - __main__ - ERROR - Faild to open sklearn.txt from logger.error Traceback (most recent call last): File "log.py", line 21, in open("sklearn.txt","rb") IOError: [Errno 2] No such file or directory: 'sklearn.txt'2018-08-04 15:47:55,656 - __main__ - INFO - Finish
这篇关于python之logging模块的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程
- 2024-11-17在FastAPI项目中添加一个生产级别的数据库——本地环境搭建指南
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器
- 2024-11-16四种数据科学Web界面框架快速对比:Rio、Reflex、Streamlit和Plotly Dash
- 2024-11-14获取参数学习:Python编程入门教程
- 2024-11-14Python编程基础入门