目錄
預備知識
什么是日志
日志是一種可以追蹤某些軟件運行時所發生事件的方法。軟件開發人員可以向他們的代碼中調用日志記錄相關的方法來表明發生了某些事情。一個事件可以用一個可包含可選變量數據的消息來描述。此外,事件也有重要性的概念,這個重要性也可以被稱為嚴重性級別(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)
我的使用方式
- 前面的
logger.conf
- 寫一個
get_logging.py
import logging
import logging.config
def getLogging(confName = "applog"):
logging.config.fileConfig("logging.conf")
return logging.getLogger(confName)
- 引用
from get_logging import getLogging
logger = getLogging()
- 輸出
>>> 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]