摘要:原因是,直接传递格式化后的字符串会导致参数被完全求值,这个有可能是非必要的,会导致日志性能下降。添加一个过滤器用来进行消息格式化上面的中的中文注释部分直接说明了解决方案。
问题
Python的logging库是标准库中用来实现日志的库,功能强大,而且使用起来也算是方便。该库提供了很多个不同的Handler,用来对日志进行不同的处理。例如FileHandler用来将日志记录到文件,RotateFileHandler用来将日志记录到文件而且支持日志文件滚动备份,还有本文中所说的HttpHandler,可以将日志通过HTTP请求发送到服务器上。
使用Python的logging模块的过程大约有如下几个步骤:
根据配置文件、配置字典或者调用方法的方式初始化日志配置,并获取一个logger。
调用logger实例的如下方法来发出一条日志:critical, error, warning, info, debug。这些方法的定义如下,以info为例:
logger.info(fmt, *args, exc_info, extra)
P.S. 本文的目的不是说明logging如何使用,所以具体的用法请参考官方文档。
当logger对象调用info等方法发出一条日志时,他可以接受像C语言中的printf函数或者Python3中的pritnf函数一样的前两个参数:格式化字符串和对应的参数列表,用来表示要发出的日志的内容。当logging模块真的要发出这条日志时,才会对字符串进行格式化,并且加入最终的日志字符串中。因此,在Python参考手册(第4版)中(19.7节,289页)有强调了如下这一点:发出日志消息时,应该避免在发出消息时带有字符串格式化的代码(即格式化一条消息,然后把结果传递到日志记录模块中)。原因是,直接传递格式化后的字符串会导致参数被完全求值,这个有可能是非必要的,会导致日志性能下降。举个例子:
正确方式: logger.info("hello, %s", "myname") 错误方式: logger.info("hello, %s" % "myname")
那么问题来了,如果一个logger的handler使用了HttpHandler,这个坑爹货居然不会在发出日志前对日志内容部分进行格式化,而是只发送了前面的fmt字符串到http服务器,结果就像下面这样:
WARNING Tue Jan 27 15:27:34 2015 admin.config 192.168.100.126 POST /user/login User [%s] logged in failed.
而我们期待的应该是:
WARNING Fri Jan 23 11:36:45 2015 admin.config 192.168.100.126 POST /user/login User [admin] logged in failed.
解决方法使用logging模块提供的Filter功能。
直接给出实例代码:
# -*- coding: utf-8 -*- import logging import logging.config import logging.handlers log_config_dict = { "version": 1, "formatters": { "format_def": { "format": "%(levelname)-8s %(asctime)s %(name)s %(ip)s " "%(method)s %(path)s %(message)s", }, }, "handlers": { "handler_http": { "class": "logging.handlers.HTTPHandler", "formatter": "format_def", "level": "INFO", "host": "192.168.100.1:8888", "url": "/log/admin", "method": "POST", }, }, "loggers": { "admin.config": { "level": "INFO", "propagate": 0, "handlers": ["handler_http"], }, "admin.api": { "level": "INFO", "propagate": 0, "handlers": ["handler_http"], } }, } class RequestFilter(logging.Filter): """A filter used to add extra information to a record. Add ip, method and path information to a record for a HTTP request. Attributes: name: logger"s name """ def __init__(self, name): self.name = name def filter(self, record): # 这里调用getMessage()方法得到格式化后的日志内容, # HTTP服务器上只要读取POST中的message参数即可。 record.message = record.getMessage() return True def init_log(): logging.config.dictConfig(log_config_dict) def get_logger(name): if type(name) is not str: return None log = logging.getLogger(name) log.addFilter(RequestFilter(name)) # 添加一个过滤器用来进行消息格式化 log.addHandler(logging.NullHandler()) return log def get_config_logger(): return get_logger("admin.config") def get_api_logger(): return get_logger("admin.api")
上面的中的中文注释部分直接说明了解决方案。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/45341.html
摘要:上一篇文章模块分析第节模块一日志记录的级别优先级,记录调试的详细信息,只在调试时开启优先级,记录普通的消息,报告错误和警告等待。监听端口号上一篇文章模块分析第节模块 上一篇文章:Python模块分析:第3节-typing模块 一、日志记录的级别 debug:优先级10,记录调试的详细信息,只在调试时开启 info:优先级20,记录普通的消息,报告错误和警告等待。 warning:优...
Python整个底层的逻辑还是比较的复杂的,内容也是比较的多,那么,Python如何进行异步处理操作呢?通俗来说,就是怎么同步发送日志到远程服务器?下面就一步一步的给大家解答,请仔细阅读哦。 背景 在Python中使用日志最常用的方式就是在控制台和文件中输出日志了,logging模块也很好的提供的相应的类,使用起来也非常方便,但是有时我们可能会有一些需求,如还需要将日志发送到远端,或者直接...
摘要:它的构造函数是其中参数是一个文件对象。它的构造函数是是文件名,必须指定一个文件名。用于指定日志文件的最大文件大小。它的构造函数是其中参数和参数和具有相同的意义。表示时间间隔的单位,不区分大小写。可能没有线程名。 0.前置说明 1.运行环境:Win7虚拟机、python2.7(anacoda版) 2.本文大部分内容引用此参考文献:http://my.oschina.net/leeju...
摘要:百度云搜索搜网盘淘宝券使用代理格式化,第一个参数,请求目标可能是或者对应设置初始化将代理设置成全局当使用请求时自动使用代理引入随机模块文件格式化注意第一个参数可能是或者,对应设置初始化将代理设置成全局当使用请求时自动使用代理请求 【百度云搜索:http://bdy.lqkweb.com】 【搜网盘:http://www.swpan.cn】 【淘宝券:http://www.tbquan....
摘要:确认一切按预期运行。表明发生了一些意外,或者不久的将来会发生问题如磁盘满了。由于更严重的问题,软件已不能执行一些功能了。严重错误,表明软件已不能继续运行了。对于不能获取的名称,则记录到模块。 最近在写一些python脚本,总是使用print来打印信息感觉很low,所以抽空研究了一下python的logging库,来优雅的来打印和记录日志: 一、简单的将日志打印到屏幕: import l...
阅读 1961·2021-11-22 15:33
阅读 3002·2021-11-18 10:02
阅读 2605·2021-11-08 13:16
阅读 1619·2021-10-09 09:57
阅读 1366·2021-09-30 09:47
阅读 2002·2019-08-29 13:05
阅读 3065·2019-08-29 12:46
阅读 1004·2019-08-29 12:19