摘要:原因是,直接傳遞格式化后的字符串會導致參數被完全求值,這個有可能是非必要的,會導致日志性能下降。添加一個過濾器用來進行消息格式化上面的中的中文注釋部分直接說明了解決方案。
問題
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")
上面的中的中文注釋部分直接說明了解決方案。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/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...
閱讀 1967·2021-11-22 15:33
閱讀 3005·2021-11-18 10:02
閱讀 2612·2021-11-08 13:16
閱讀 1623·2021-10-09 09:57
閱讀 1372·2021-09-30 09:47
閱讀 2008·2019-08-29 13:05
閱讀 3071·2019-08-29 12:46
閱讀 1010·2019-08-29 12:19