1. 程式人生 > 其它 >【轉】標準庫系列:logging 日誌列印

【轉】標準庫系列:logging 日誌列印

核心參考[1]
b站視訊[2]

目錄

預備知識

什麼是日誌

日誌是一種可以追蹤某些軟體執行時所發生事件的方法。軟體開發人員可以向他們的程式碼中呼叫日誌記錄相關的方法來表明發生了某些事情。一個事件可以用一個可包含可選變數資料的訊息來描述。此外,事件也有重要性的概念,這個重要性也可以被稱為嚴重性級別(level)。

日誌的等級

級別何時使用
DEBUG 詳細資訊,典型地除錯問題時會感興趣。 詳細的debug資訊。
INFO 證明事情按預期工作。 關鍵事件。
WARNING 表明發生了一些意外,或者不久的將來會發生問題(如‘磁碟滿了’)。軟體還是在正常工作。
ERROR 由於更嚴重的問題,軟體已不能執行一些功能了。 一般錯誤訊息。
CRITICAL 嚴重錯誤,表明軟體已不能繼續運行了。
NOTICE 不是錯誤,但是可能需要處理。普通但是重要的事件。
ALERT 需要立即修復,例如系統資料庫損壞。
EMERGENCY 緊急情況,系統不可用(例如系統崩潰),一般會通知所有使用者。

java的log4j,log4php等第三方庫也能較好的提供日誌操作功能,有機會可以試著瞭解瞭解

logging的日誌等級

日誌等級(level)描述
DEBUG 最詳細的日誌資訊,典型應用場景是 問題診斷
INFO 資訊詳細程度僅次於DEBUG,通常只記錄關鍵節點資訊,用於確認一切都是按照我們預期的那樣進行工作
WARNING 當某些不期望的事情發生時記錄的資訊(如,磁碟可用空間較低),但是此時應用程式還是正常執行的
ERROR 由於一個更嚴重的問題導致某些功能不能正常執行時記錄的資訊
CRITICAL 當發生嚴重錯誤,導致應用程式不能繼續執行時記錄的資訊
  • 該列表中的日誌等級是從上到下依次增高,日誌內容依次減少,即DEBUG可以顯示所有日誌,CRITICAL只能顯示自己。例子如下:
import logging

logging.debug("debug_msg")
logging.info("info_msg")
logging.warning("warning_msg")
logging.error("error_msg")
logging.critical("critical_msg")

輸出結果

WARNING:root:warning_msg
ERROR:root:error_msg
CRITICAL:root:critical_msg

說明預設的日誌級別為WARNING

logging的使用方法

常用函式

函式說明
logging.debug(msg, *args, **kwargs) 建立一條嚴重級別為DEBUG的日誌記錄
logging.info(msg, *args, **kwargs) 建立一條嚴重級別為INFO的日誌記錄
logging.warning(msg, *args, **kwargs) 建立一條嚴重級別為WARNING的日誌記錄
logging.error(msg, *args, **kwargs) 建立一條嚴重級別為ERROR的日誌記錄
logging.critical(msg, *args, **kwargs) 建立一條嚴重級別為CRITICAL的日誌記錄
logging.log(level, *args, **kwargs) 建立一條嚴重級別為level的日誌記錄
logging.basicConfig(**kwargs) 對root logger進行一次性配置

不推薦使用basicConfig對日誌等級進行自我創作,因為會影響程式碼的移植性,程式碼在別人那裡容易起衝突

使用方法

日誌輸出方法

logging.basicConfig(level=logging.DEBUG)#將日誌的輸出級別調節為debug
logging.basicConfig(filename='demo.log',level=logging.DEBUG)#將日誌的輸出到demo.log檔案中
logging.basicConfig(filename='demo.log',filemote='w',level=logging.DEBUG)#先清空再寫入,也可以設定為繼續寫

常用的輸出(字串格式化輸出)[3]

logging.debug("姓名 %s, 年齡%d",name,age)
logging.debug("姓名 %s, 年齡%d",% (name,age))
logging.debug("姓名 {}, 年齡{}".format(name,age))
logging.debug(f"姓名{name}, 年齡{age}")
logging.basicConfig(format="%(asctime)s|%(levelname)s|%(filename)s:%(lineno)s|%(message)s",level=logging.DEBUG)
>>> 2020-07-16 15:35:58|DEBUG16-3.py:13|姓名 張三,年齡 18

logger的高階應用

相關元件

名稱作用
Loggers 記錄器,提供應用程式程式碼直接使用的介面
Handlers 處理器,將記錄器產生的日誌傳送至目的地
Filters 過濾器,提供更好的粒度控制,決定哪些日誌會被輸出
Formatters 格式化器,設定日誌內容的組成結構和訊息欄位

Handlers

它們將日誌分發到不同的目的地。可以是檔案、標準輸出、郵件、或者通過 socke、htt等協議傳送到任何地方
setFormatter():設定當前Handler物件使用的訊息格式

  • Streamhandler
    標準輸出stout分發器
sh = logging.StreamHandler(stream=None)
  • Filehandler
    將日誌儲存到磁碟檔案的處理器
fh = logging.FileHandler(filename,mode='a',encoding=None,delay=False)
  • BaseRotatingHandler

  • Rotating Filehandler
    滾動的多日誌輸出,按照時間or其他方式去生成多個日誌

  • TimedRotatingfilehandler

以下的使用較少

  • Sockethandler

  • Dataaramhandler

  • Smtphandler

  • Sysloghandler

  • Nteventloghandler

  • Httphandler

  • WatchedFilehandler

  • Qutelehandler

  • Nullhandler

Formatters格式

屬性格式描述
asctime %(asctime)s 日誌產生的時間,預設格式為msecs2003-07-0816:49:45,896
msecs %(msecs)d 日誌生成時間的亳秒部分
created %(created)f time.tme)生成的日誌建立時間戳
message %(message)s 具體的日誌資訊
filename %(filename)s 生成日誌的程式名
name %(name)s 日誌呼叫者
funcname %( funcname)s 呼叫日誌的函式名
levelname %(levelname)s 日誌級別( DEBUG,INFO, WARNING, 'ERRORCRITICAL)
levene %( leveling)s 日誌級別對應的數值
lineno %(lineno)d 日誌所針對的程式碼行號(如果可用的話)
module %( module)s 生成日誌的模組名
pathname %( pathname)s 生成日誌的檔案的完整路徑
process %( (process)d 生成日誌的程序D(如果可用)
processname (processname)s 程序名(如果可用)
thread %(thread)d 生成日誌的執行緒D(如果可用)
threadname %( threadname)s 執行緒名(如果可用)

舉例

#記錄器
logger = logging.getLogger('cn.cccb.applog')
logger.setLevel(logging.DEBUG)
#必須設定為兩個handler中級別更低的

#處理器handler
consoleHandler = logging.StreamHandler()
consoleHandler.setLevel(logging.DEBUG)

#沒有給handler指定日誌級別,將使用logger的級別
fileHandler = logging.FileHandler(filename='addDemo.log')
consoleHandler.setLevel(logging.INFO)

#formatter格式
formatter = logging.Formatter("%(asctime)s|%(levelname)8s|%(filename)10s%lineno)s|%(message)s")
#裡面的8,10實現了佔位對齊

#給處理器設定格式
consoleHandler.setFormatter(formatter)
fileHandler.setFormatter(formatter)

#記錄器要設定處理器
logger.addHandler(consoleHandler)
logger.addHandler(fileHandler)

#定義一個過濾器
# flt = logging.Filter("cn.cccb")


#關聯過濾器
# logger.addFilter(flt)
fileHandler.addFilter(flt)

#列印日誌的程式碼
#logging.debug()#不能使用這個了!!!會使用WARNING的版本,不會用之前的記錄器
logger.debug("姓名 %s, 年齡%d",name,age)
logger.debug("姓名 %s, 年齡%d",% (name,age))
logger.debug("姓名 {}, 年齡{}"format(name,age))
logger.debug(f"姓名{name}, 年齡{age}")

大型工程的配置檔案(推薦!!!)

使用字典可以進行過渡,不過需要找時間再去了解吧~

#./logging.conf

#記錄器:提供應用程式程式碼直接使用的介面
#設定記錄器名稱,root必須存在!!!
[loggers]
keys=root,applog

#處理器,將記錄器產生的日誌傳送至目的地
#設定處理器型別
[handlers]
keys=fileHandler,consoleHandler

#格式化器,設定日誌內容的組成結構和訊息欄位
#設定格式化器的種類
[formatters]
keys=simpleFormatter

#設定記錄器root的級別與種類
[logger_root]
level=DEBUG
handlers=consoleHandler

#設定記錄器applog的級別與種類
[logger_applog]
level=DEBUG 
handlers=fileHandler,consoleHandler
#起個對外的名字
qualname=applog
#繼承關係
propagate=0

#設定
[handler_consoleHandler]
class=StreamHandler
args=(sys.stdout,)
level=DEBUG
formatter=simpleFormatter

[handler_fileHandler]
class=handlers.TimedRotatingFileHandler
#在午夜1點(3600s)開啟下一個log檔案,第四個引數0表示保留歷史檔案
args=('applog.log','midnight',3600,0)
level=DEBUG
formatter=simpleFormatter

[formatter_simpleFormatter]
format=%(asctime)s|%(levelname)8s|%(filename)s[:%(lineno)d]|%(message)s
#設定時間輸出格式
datefmt=%Y-%m-%d %H:%M:%S
import logging
import logging.config

logging.config.fileConfig('logging.conf')
#使用字典就能從任意格式檔案進行配置,字典是一種介面格式
# logging.config.dictConfig({"loggers":"root,applog"})

rootLogger = logging.getLogger('applog')
rootLogger.debug("This is root Logger, debug")

logger = logging.getLogger('cn.cccb.applog')
logger.debug("This is applog, debug")

try:
    int(a)
except Exception as e:
    logger.exception(e)

我的使用方式

  1. 前面的logger.conf
  2. 寫一個get_logging.py
import logging
import logging.config

def getLogging(confName = "applog"):
    logging.config.fileConfig("logging.conf")
    return logging.getLogger(confName)
  1. 引用
from get_logging import getLogging

logger = getLogging()
  1. 輸出
>>> 2021-04-26 11:23:05|   DEBUG|try.py[:21]|This is root Logger, debug
>>> 2021-04-26 11:23:05|   DEBUG|try.py[:24]|This is applog, debug
>>> 2021-04-26 11:23:05|   ERROR|try.py[:29]|name 'a' is not defined
Traceback (most recent call last):
  File "/home/kangshuaibo/code/shapan/calibration/try.py", line 27, in <module>
    int(a)
NameError: name 'a' is not defined

一些個性化

設定列印顏色

print('\x1b[36m{}\x1b[0m'.format('This is debug Logger'))
print('\x1b[1;31m{}\x1b[0m'.format('This is warn Logger'))
print('\x1b[1;4;31m{}\x1b[0m'.format('This is error Logger'))
print('\x1b[35m{}\x1b[0m'.format('This is omitted Logger'))
print('\x1b[32m{}\x1b[0m'.format('This is normal Logger'))


具體含義見:冷知識集錦-linux相關-linux終端控制符[4]


  1. 核心參考 ↩︎

  2. b站視訊 ↩︎

  3. 字串格式化輸出 ↩︎

  4. 冷知識集錦-linux相關-linux終端控制符 ↩︎