Python模塊分析:第4節-logging日誌模塊

上一篇文章: Python模塊分析:第3節-typing模塊

1、日誌記錄的級別

  1. debug:優先級10,記錄調試的詳細信息,只在調試時開啓
  2. info:優先級20,記錄普通的消息,報告錯誤和警告等待。
  3. warning:優先級30,記錄相關的警告信息。
  4. error:優先級40,記錄錯誤信息、程序崩潰
  5. critical:優先級50,記錄錯誤信息
若是不設置,默認爲iwarning

2、logging模塊的主要結構

查看logging的源碼,可知主要有四個類實現功能:json

  1. Loggers:提供應該程序直接使用的接口,如相關的配置設置
  2. Handlers:將Loggers產生的日誌傳到指定位置,設置日誌保存的位置;
  3. Filters:對輸出日誌進行過濾操做;
  4. Formatters:控制日誌的輸出格式

Formatters

Formatters對象定義了日誌的輸出格式,有多種可選參數。segmentfault

參數 含義
%(name)s Logger的名字
%(levellno)s 數字形式的日誌級別
%(levelname)s 文本形式的日誌級別
%(pathname)s 調用日誌輸出函數的模塊的完整路徑名,可能沒有
%(filename)s 調用日誌輸出函數的模塊的文件名
%(module)s 調用日誌輸出函數的模塊名
%(funcName)s 調用日誌輸出函數的函數名
%(lineno)d 調用日誌輸出函數的語句所在的代碼行
%(created)f 當前時間,用unix標表示的時間浮點表示
%(relativeCreated)d 輸出日誌信息時,自Logger建立以來的毫秒數
%(asctime)s 字符串形式的當前時間,默認格式是‘2018-11-22 16:49:45,896’,逗號後面是毫秒
%(thread)d 線程ID,可能沒有
%(threadName)s 線程名,可能沒有
%(process)d 進程ID,可能沒有
%(message)s 用戶輸出的信息

實例:服務器

import logging

#fmt:定義輸出的日誌信息的格式
#datefmt:定義時間信息的格式,默認爲:%Y-%m-%d %H:%M:%S
#style:定義格式化輸出的佔位符,默認是%(name)格式,可選{}或$格式
formatter=logging.Formatter(fmt='%(asctime)s    %(levelname)s:  %(message)s'
                            ,datefmt='%Y-%m-%d %H:%M:%S',style='%')

Handlers日誌處理器

日誌處理器用來處理日誌的具體流向,是輸出到文件中仍是標準輸出等,它經過設置Formatter控制輸出格式,添加filters過濾日誌。app

經常使用的處理器有兩種
  1. StreamHandler:用於向控制檯打印日誌
  2. FileHandler:用於向日志文件打印日誌
其它的處理器
名稱 詳細位置 說明
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服務器
from logging import Handler

#全部日誌處理器的父類
handler=Handler()

print('處理日誌的等級:',handler.level)
print('處理日誌的名字:',handler.name)
print('處理器的日誌過濾器::',handler.filters)
print('日誌的格式::',handler.filters)

#一些經常使用方法:
handler.get_name()
handler.set_name('')
handler.createLock()#建立線程鎖
handler.acquire()#獲取線程鎖
handler.release()#釋放線程鎖
handler.setLevel('info') #設置日誌處理器的記錄級別
handler.setFormatter(fmt='')#設置日誌的輸出格式
handler.addFilter('')#往處理器中添加過濾器
handler.removeFilter('')#往處理器中移除過濾器
handler.emit('')#日誌記錄的處理邏輯,由子類實現

Logger日誌對象

Logger管理着全部記錄日誌的方法。socket

from logging import error, debug, warning, info, fatal, critical, getLogger

#返回一個Logger實例
#以'root'爲名字的日誌對象在Logger對象中只有一個實例
logger=getLogger('root')

print('獲取根日誌對象',logger.root)
print('獲取manager',logger.manager)
print('獲取根日誌對象的名字',logger.name)
print('獲取根日誌對象記錄水平',logger.level)
print('獲取根日誌對象過濾器列表',logger.filters)
print('獲取根日誌對象處理器列表',logger.handlers)
print('獲取根日誌對象',logger.disabled)

#設置日誌記錄水平
logger.setLevel('info')

#輸出日誌信息,格式化輸出
logger.info('this is %s','info',exc_info=1)
#記錄warning信息
logger.warning('')
#記錄error信息
logger.error('')
#等價於logger.error('',exc_info=1)
logger.exception('')
#記錄debug信息
logger.debug('')
#記錄critical信息
logger.critical('')
#直接指定級別
logger.log('info','')

#添加處理器
logger.addHandler()
#移除處理器
logger.removeHandler()
#判是否有處理器
logger.hasHandlers()

3、logger的基本使用

實例:函數

import logging
import sys

def my_get_logger(appname):
    #獲取logger實例,若是參數爲空則返回root logger
    logger=logging.getLogger(appname)
    #建立日誌輸出格式
    formatter=logging.Formatter('%(asctime)s    %(levelname)s   %(mark)s:  %(message)s')

    #指定輸出的文件路徑
    file_handler=logging.FileHandler('test.log')
    # 設置文件處理器,加載處理器格式
    file_handler.setFormatter(formatter)

    #控制檯日誌
    console_handler=logging.StreamHandler(sys.stdout)
    console_handler.formatter=formatter

    #爲logger添加的日誌處理器
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)

    #指定日誌的最低輸出級別,默認爲warn級別
    logger.setLevel(logging.INFO)
    return logger

if __name__ == '__main__':
    logger=my_get_logger('test')
    # extra: 這是一個字典(dict)參數,它能夠用來自定義消息格式中所包含的字段,可是它的key不能與logging模塊定義的字段衝突。
    logger.debug('this is debug info',extra={'mark':'mark'})
    logger.info('this is information',extra={'mark':'mark'})
    logger.warning('this is warning message',extra={'mark':'mark'})
    logger.error('this is error message',extra={'mark':'mark'})
    logger.fatal('this is fatal message,it is same ad logger.critical',extra={'mark':'mark'})
    logger.critical('this is critical message',extra={'mark':'mark'})

結果:ui

2018-11-27 09:54:43,318    INFO   mark:  this is information
2018-11-27 09:54:43,318    WARNING   mark:  this is warning message
2018-11-27 09:54:43,318    ERROR   mark:  this is error message
2018-11-27 09:54:43,319    CRITICAL   mark:  this is fatal message,it is same ad logger.critical
2018-11-27 09:54:43,319    CRITICAL   mark:  this is critical message

4、logger日誌記錄的邏輯調用過程

  1. 記錄日誌經過調用logger.debug等方法;
  2. 首先判斷本條記錄的日誌級別是否大於設置的級別,若是不是,直接pass,再也不執行;
  3. 將日誌信息當作參數建立一個LogRecord日誌記錄對象
  4. 將LogRecord對象通過logger過濾器過濾,若是被過濾則pass
  5. 日誌記錄對象被Handler處理器的過濾器過濾
  6. 判斷本條記錄的日誌級別是否大於Handler處理器設置的級別,若是不是,直接pass,再也不執行;
  7. 最後調用處理器的emit方法處理日誌記錄;

5、配置logger

  1. 經過代碼進行完整配置,主要是經過getLogger方法實現,但很差修改
  2. 經過basicConfig方法實現,這種方式快速但不夠井井有條
  3. 經過logging.config.fileConfig(filepath),文件配置
  4. 經過dictConfig的字典方式配置,這是py3.2版本引入的新的配置方法

使用文件方式配置

#logging.cong

[loggers]
#定義日誌的對象名稱是什麼,注意必須定義root,不然報錯
keys=root,main

[handlers]
#定義處理器的名字是什麼,能夠有多個,用逗號隔開
keys=consoleHandler

[formatters]
#定義輸出格式對象的名字,能夠有多個,用逗號隔開
keys=simpleFormatter

[logger_root]
#配置root對象的日誌記錄級別和使用的處理器
level=INFO
handlers=consoleHandler

[logger_main]
#配置main對象的日誌記錄級別和使用的處理器,qualname值得就是日誌對象的名字
level=INFO
handlers=consoleHandler
qualname=main
#logger對象把日誌傳遞給全部相關的handler的時候,會逐級向上尋找這個logger和它全部的父logger的所有handler,
#propagate=1表示會繼續向上搜尋;
#propagate=0表示中止搜尋,這個參數涉及重複打印的坑。
propagate=0

[handler_consoleHandler]
#配置處理器consoleHandler
class=StreamHandler
level=WARNING
formatter=simpleFormatter
args=(sys,)

[formatter_simpleFormatter]
#配置輸出格式過濾器simpleFormatter
format=%(asctime)-%(name)s-%(levelname)s-%(message)s
注意:能夠看到logger和Handler均可以設置日誌級別,日誌輸出是取最高級別。

使用字典形式配置

字典形式配置功能更強大,也更加靈活。經過dictConfig函數,咱們能夠將其餘格式的配置文件轉化成字典,如json,YAML等。this

實例:spa

import yaml
from logging.config import dictConfig
import os
filename=os.path.dirname(os.path.abspath(__file__))
with  open(filename+'/logging.yaml','r') as f:
    log=yaml.load(f.read())
    dictConfig(log)
#logging.yaml
#注意:yaml格式嚴格,:後面必定要帶空格
version: 1
formatters:
    simple:
          format: '%(asctime)s-%(name)s-%(levelname)s-%(message)s'
handlers:
    console:
          class: logging.StreamHandler
          level: DEBUG
          formatter: simple
          stream: ext://sys.stdout
    console_err:
          class: logging.StreamHandler
          level: DEBUG
          formatter: simple
          stream: ext://sys.stderr
loggers:
    simpleExample:
          level: DEBUG
          handlers: [console]
          propagate: no
root:
    level: DEBUG
    handlers: [console_err]]

6、監聽logger配置更改

logging.config.listen(port)函數可讓英語程序在一個socket上監聽新的配置信息,達到在運行時改變配置,而不用重啓應用程序的目的。
import logging.config
import logging
logging.config.fileConfig("logging.conf")
logger=logging.getLogger('test.listen')

#監聽端口號9999
t=logging.config.listen(9999)
t.setDaemon(True)
t.start()
上一篇文章: Python模塊分析:第3節-typing模塊
相關文章
相關標籤/搜索