日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python 内置模块之 logging

發布時間:2023/12/20 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python 内置模块之 logging 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

日志的級別和適用情況

級別適用情況
DEBUG詳細信息,通常只在診斷問題時對其感興趣
INFO確認工作正常
WARNING表示發生了意料之外的事或者在不遠的將來會有問題(比如磁盤空間低)。軟件依然正常工作
ERROR由于一個更加嚴重的問題,軟件不能執行某些功能
CRITICAL嚴重的錯誤,表示程序可能不能繼續運行

組件

logging 庫提供了以下組件:

  • 日志記錄器(Logger):日志記錄器暴露應用程序代碼可以直接使用的接口。
  • 處理器(Handler):處理器發送日志(由日志記錄器創建)到對應的目的地。
  • 過濾器(Filter):過濾器篩選日志。
  • 和格式化器(Formatter):格式化器決定最終輸出的日志的格式。

目的地

可以將信息記錄到不同的目的地。目的地由處理器提供。在 logging 庫中支持將信息記錄到文件、HTTP GET/POST 地址、基于 SMTP 的 email等,詳細見?Useful Handlers。如果自帶的處理器類不能滿足你的特定需求,你也可以自定義日志目的地。

日志記錄默認是沒有目的地(處理器)的。當你調用?logging?的?debug()?等函數時,它們會檢查處理器是否設置了目的地;如果沒有設置,它會自動調用?logging.basicConfig()?來設置。

basicConfig

logging.basicConfig?只有第一次設置才會生效,即第一次之后的設置不會覆蓋第一次設置。

logging.basicConfig?默認情況下給 root logger 添加一個默認格式的、目的地為控制臺的處理器。

import logging root = logging.getLogger() root.handlers # []logging.basicConfig() root.handlers # [<logging.StreamHandler object at 0x1010b68d0>]

logging模塊有三種配置方式,一種是函數式的簡單配置,一種是對象類的,還有一種是配置文件類型的

配置方式1:函數式簡單配置

import logginglogging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')

默認情況下Python的logging模塊將日志打印到了標準輸出中,且只顯示了大于等于WARNING級別的日志,這說明默認的日志級別設置為WARNING,默認的日志格式為日志級別:Logger名稱:用戶輸出消息。配置日志級別,日志格式,輸出位置:

import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/tmp/test.log', filemode='w' ) logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')

logging.basicConfig()可用參數有:

filename:用指定的文件名創建FiledHandler,這樣日志會被存儲在指定的文件中。 filemode:文件打開方式,在指定了filename時使用這個參數,默認值為“a”還可指定為“w”。 format:指定handler使用的日志顯示格式。 datefmt:指定日期時間格式。 level:設置rootlogger(后邊會講解具體概念)的日志級別 stream:用指定的stream創建StreamHandler??梢灾付ㄝ敵龅絪ys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默認為sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。

format參數中可能用到的格式化串:

%(name)s Logger的名字%(levelno)s 數字形式的日志級別%(levelname)s 文本形式的日志級別%(pathname)s 調用日志輸出函數的模塊的完整路徑名,可能沒有%(filename)s 調用日志輸出函數的模塊的文件名%(module)s 調用日志輸出函數的模塊名%(funcName)s 調用日志輸出函數的函數名%(lineno)d 調用日志輸出函數的語句所在的代碼行%(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示%(relativeCreated)d 輸出日志信息時的,自Logger創建以 來的毫秒數%(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒%(thread)d 線程ID。可能沒有%(threadName)s 線程名。可能沒有%(process)d 進程ID??赡軟]有%(message)s用戶輸出的消息

配置方式2:logger對象配置

import logginglogger = logging.getLogger() logger.setLevel(logging.DEBUG)# 創建一個handler,用于寫入日志文件 fh = logging.FileHandler('test.log',encoding='utf-8')# 定義一個RotatingFileHandler(使用日志回滾時使用),最多備份3個日志文件,每個日志文件最大1K rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3)# 輸出到控制臺的handler ch = logging.StreamHandler()# 輸出為空的handler nullhandler = logging.NullHandler() # 設置formatter格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setLevel(logging.DEBUG) fh.setFormatter(formatter) # 把fh 和 格式 綁定 ch.setFormatter(formatter) logger.addHandler(fh) # logger對象可以添加多個fh和ch對象 logger.addHandler(ch) logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message')

設置日志可以通過:logger.setLevel(logging.Debug)設置級別,當然,也可以通過fh.setLevel(logging.Debug)單對文件流設置某個級別。

注:如果通過fh.setLevel(logging.Debug)單對文件流設置某個級別,則需要先修改logging.getLogger(),即logging獲取時的級別,因為?logging.getLogger('')(root logger)的默認日志級別是?WARNING?所以在設置fh.setLevel(logging.Debug)低于wraning時,會獲取不到,需要先修改logger.setLevel(logging.INFO)

擴展傳給syslogserver,郵箱

# 日志傳送到syslog server syslog_handler = handlers.SysLogHandler(address=('192.168.168.1', 514)) # 日志傳送給郵箱 mail_handler = handlers.SMTPHandler('192.168.168.1', 'winter@126.com', 'elly@163.com', 'subject') # 郵件給多人 mail_handler = handlers.SMTPHandler('192.168.168.1', 'winter@126.com', ('elly@163.com', 'dxd@126.com'), 'subject')

配置方式3:logger的配置文件

上面這種方式需要創建各種對象,比如logger對象,fileHandler對象,ScreamHandler對象等等,比較麻煩,下面提供一種字典的方式,創建logger配置文件,這種才是工作中經常使用的實現日志功能的方法,真正的做到拿來即用(簡單改改)。

import os import logging.config# 定義日志輸出格式 log_format_standard = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d][%(levelname)s][%(message)s]' log_format_simple = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'logfile_dir = os.path.dirname(os.path.abspath(__file__)) logfile_name = 'info.log'# 如果不存在定義的日志目錄就創建一個 if not os.path.isdir(logfile_dir):os.mkdir(logfile_dir)logfile_path = os.path.join(logfile_dir, logfile_name) # log文件的全路徑# log配置字典 LOGGING_DIC = {'version': 1,'disable_existing_loggers': False,'formatters': {'standard': {'format': log_format_standard},'simple': {'format': log_format_simple},},'filters': {},'handlers': {'console': { # 打印到終端的日志'level': 'DEBUG','class': 'logging.StreamHandler', # 打印到屏幕'formatter': 'simple'},'default': { # 打印到文件的日志,收集info及以上的日志 'level': 'DEBUG','class': 'logging.handlers.RotatingFileHandler', # 保存到文件'formatter': 'standard','filename': logfile_path, # 日志文件'maxBytes': 1024*1024*5, # 日志大小 5M'backupCount': 5,'encoding': 'utf-8', # 日志文件的編碼,再也不用擔心中文log亂碼了},},'loggers': { # logging.getLogger(__name__)拿到的logger配置'': {'handlers': ['default', 'console'], # 把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕'level': 'DEBUG','propagate': True, # 向上(更高level的logger)傳遞},}, }def load_my_logging_cfg():logging.config.dictConfig(LOGGING_DIC) # 導入上面定義的logging配置logger = logging.getLogger(__name__) # 生成一個log實例logger.info('It works!') # 記錄該文件的運行狀態if __name__ == '__main__':load_my_logging_cfg()

注意注意注意:

  • 有了上述方式我們的好處是:所有與logging模塊有關的配置都寫到字典中就可以了,更加清晰,方便管理
  • 我們需要解決的問題是:
  • 字典加載配置:logging.config.dictConfig(settings.LOGGING_DIC)
  • 拿到logger對象來產生日志,logger對象都是配置到字典的loggers 鍵對應的子字典中的,按照我們對logging模塊的理解,要想獲取某個東西都是通過名字,也就是key來獲取的,于是我們要獲取不同的logger對象就是
  • logger=logging.getLogger('loggers子字典的key名')
  • 但問題是:如果我們想要不同logger名的logger對象都共用一段配置,那么肯定不能在loggers子字典中定義n個key?
  • loggers子字典匹配規則
  • 以 . 為分割,從前往后匹配子字典中的key值。
  • 例:如要匹配 app.utils,則會匹配子字典的key值為(app 和 app.utils,兩者都會匹配)
  • 'loggers': { 'l1': {'handlers': ['default', 'console'], #'level': 'DEBUG','propagate': True, # 向上(更高level的logger)傳遞},'l2: {'handlers': ['default', 'console' ], 'level': 'DEBUG','propagate': False, # 向上(更高level的logger)傳遞},'l3': {'handlers': ['default', 'console'], #'level': 'DEBUG','propagate': True, # 向上(更高level的logger)傳遞},}# 我們的解決方式是,定義一個空的key'loggers': {'': {'handlers': ['default', 'console'], 'level': 'DEBUG','propagate': True, },}# 這樣我們再取logger對象時logging.getLogger(__name__),不同的文件__name__不同,這保證了打印日志時標識信息不同,但是拿著該名字去loggers里找key名時卻發現找不到,于是默認使用key=''的配置

    其他通過yaml 和 模塊配置 捕獲異常等 可參考

    • https://www.cnblogs.com/liujiacai/p/7804848.html
    • https://www.cnblogs.com/louis-w/p/8567434.html

    [BUG] python實例化N次類,調用類函數log會輸出N遍的bug 解決辦法

    最近再寫DOU用例時,采用的是 unittest測試框架,就涉及到將其它所有模塊需要全部在一個 .py文件中進行實例化,然后再運行時發現在控制臺中同一個日志信息會打印多次(實例化幾次,同一消息就會打印幾次),現象如下:

    在common.py 中找到 log 的輸出方法,代碼如下:

    def get_logger(ch_leval='INFO'):logger = logging.getLogger()logger.setLevel(logging.DEBUG)l_format = '[%(asctime)s][%(process)s][%(levelname)s][%(message)s]'formatter = logging.Formatter(l_format)fh = logging.FileHandler('xu.log',encoding='utf-8')fh.setLevel(logging.ERROR)fh.setFormatter(formatter)logger.addHandler(fh)ch = logging.StreamHandler()ch.setLevel(getattr(logging,ch_leval)) ch.setFormatter(formatter)logger.addHandler(ch)

    我們每次在實例化 get_loger() 方法時,都會添加一次 handlers,logger.handlers 實例上是一個列表,這就會導致我們多次進行實例化,這個logger.handlers就會把每次的 handler 添加進來(即使兩個名字相同)。

    所以這里有以下幾個解決辦法:

  • 每次創建不同name的logger,每次都是新logger,不會有添加多個handler的問題。(不解決問題)
  • 像上面一樣每次記錄完日志之后,調用removeHandler()把這個logger里的handler移除掉。(需要在使用完成之后移除)
  • 在log方法里做判斷,如果這個logger已有handler,則不再添加handler。
  • 與方法2一樣,不過把用pop把logger的handler列表中的handler移除。
  • 辦法3的代碼示例:

    def get_logger(ch_leval='INFO'):logger = logging.getLogger()logger.setLevel(logging.DEBUG)if not logger.handlers:l_format = '[%(asctime)s][%(process)s][%(levelname)s][%(message)s]'formatter = logging.Formatter(l_format)fh = logging.FileHandler('xu.log',encoding='utf-8')fh.setLevel(logging.ERROR)fh.setFormatter(formatter)logger.addHandler(fh)ch = logging.StreamHandler()ch.setLevel(getattr(logging,ch_leval)) ch.setFormatter(formatter)logger.addHandler(ch)

    Logger.error or Logger.exception

    logger.exception(msg,_args)等價于logger.error(msg,exc_info = True,_args),

    Logger.exception() creates a log message similar to Logger.error(). The difference is that Logger.exception() dumps a stack trace along with it. Call this method only from an exception handler.

    Exception handler 的意思是要在?except?中調用:

    try:1 / 0 except:logging.exception('msg')ERROR:root:msg Traceback (most recent call last):File "<ipython-input-9-63e73c36224b>", line 2, in <module>1 / 0 ZeroDivisionError: integer division or modulo by zero

    如果不在?except?中調用會?raise Empty

    logging.exception('msg') ERROR:root:msg Traceback (most recent call last):File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevconsole.py", line 198, in process_exec_queuecode_fragment = interpreter.exec_queue.get(block=True, timeout=1/20.) # 20 calls/secondFile "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/Queue.py", line 176, in getraise Empty Empty

    不打印 requests 的日志

    最近寫的代碼基本都用到了python的標準日志模塊logging,但發現在使用requests模塊和elasticsearch時,即使自己沒有打印相關日志,也會自動生成請求過程日志,示例如下:

    Starting new HTTP connection (1): example.com http://example.com:80 "GET / HTTP/1.1" 200 606

    ?上面這種日志我們是不需要的,如果這種日志和我們自己打的日志混合在一塊兒,日志文件將變得難以查看,對后面的問題排查帶來很多不便,因此我們需要禁用掉這種默認的日志打印,方法如下:

    logging.getLogger("requests").setLevel(logging.WARNING) # requests 模塊 logging.getLogger("urllib3").setLevel(logging.WARNING) # urllib3 模塊 logging.getLogger("elasticsearch").setLevel(logging.WARNING) # elasticsearch 模塊 logging.getLogger("werkzeug") # werkzeug 模塊 logging.getLogger("app") # flask 模塊

    總結

    以上是生活随笔為你收集整理的Python 内置模块之 logging的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。