標准庫系列: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'))

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


  1. 核心參考 ↩︎

  2. b站視頻 ↩︎

  3. 字符串格式化輸出 ↩︎

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM