Python LOGGING使用方法
1. 簡介
使用場景
場景 | 適合使用的方法 |
---|---|
在終端輸出程序或腳本的使用方法 | |
報告一個事件的發生(例如狀態的修改) | logging.info()或logging.debug() |
發生了一個特定的警告性的事件 | logging.warn() |
發生了一個特定的錯誤性的事件 | raise |
發生了一個特定的錯誤性的事件,但是又不想因為此錯誤導致程序退出(例如程序是一個守護進程) | logging.error(),logging.exception(),logging.critical() |
日志的嚴重程度
由高到低
Level |
---|
CRITICAL |
ERROR |
WARNING |
INFO |
DEBUG |
logging默認的嚴重程度是WARNING,即在這個嚴重程度或以上的日志才會被記錄。
有兩種常用的記錄日志的方式:
- 輸出到終端
import logging
logging.error('hello1')
- 記錄到文件,也就是硬盤
import logging
logging.basicConfig(filename='./log.log',level=logging.DEBUG)
logging.error('hello1')
basicConfig方法用於快速設置日志,有下面的參數:
- filename 包日志保存到哪個文件
- filemode記錄日志的模式,a代表在文件中追加日志,w是刪除原有文件,創建新文件。
- format 設置日志IDE輸出格式,
- level 日志的嚴重程度,
- datefmt 日期格式
- stream 日志輸出到那里,如果有filename參數,忽略改參數
logging中包含了四個主要的類:
- logger 提供應用程序直接使用的接口
- handler將日志記錄到指定的輸出,例如文件或終端
- filter提供了對日志進行過濾的功能
- formatter決定日志記錄的最終輸出格式。
2. logger
-
命名空間
每個logger都會有一個名字。名字中使用點號來進行等級管理。例如scan
是scan.html
和scan.pdf
的上級
logging中建議使用logger = logging.getLogger(__name__)
來獲取logger,因為__name__
代表當前模塊的路徑 -
日志流
當應用程序執行一個寫日志操作時,例如logging.info(),日志流程圖:
![enter image description here] (http://7xpt1q.com1.z0.glb.clouddn.com/img/doc/logging_flow.png)
-
如果logger有父類,日志流會同時發送給logger和logger的父類的handler。
```python allot_logger('scan', './scan.log') allot_logger('scan.pdf', './scan.pdf.log') scan_log = logging.getLogger('scan') scan_pdf_log = logging.getLogger('scan.pdf') scan_log.info('scan_log') # 日志只會輸出到./scan.log文件 scan_pdf_log.info('scan_pdf_log') # 日志會輸出到./scan.log和./scan.pdf.log兩個文件 ```
-
方法
- Logger.setLevel() 設置logger的日志嚴重程度
- logger.addHandler() ,Logger.remoteHandler()添加或刪除Handler
- Logger.addFilter,Logger.remoteFilter()添加或刪除Filter
- Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), and Logger.critical()記錄日志,其中debug是日志等級。支持字符串格式化,例如
logging.debug('error_msg:%s',error_msg)
- Logger.log(level,msg) 。
logging.log(logging.WARN,'msg')
等於logging.warn(msg)
-
屬性
- Logger.handlers 該logger已添加的Handlers
- Logger.filters 該logger已添加的Filters
- 獲取Logger實例
通過getLogger() 來獲取logger。
3. Handler
一個logger可以設置0個或以上的Handler。logger執行記錄日志的方法后,會把日志交給Handler來處理。
1. 方法
- Handler.setLevel() 設置logger的日志嚴重程度
- Handler.addFilter,Handler.remoteFilter()添加或刪除Filter
- setFormatter() 設置日志輸出的格式
2. Handler類
- logging.StreamHandler
輸出日志到一個文件對象,可以是open打開的文件,也可以是系統終端,例如sys.stdout或sys.stderr
。它的構造函數是:StreamHandler([strm])
- 其中strm是一個文件對象。默認是sys.stderr.
- demo:
f=open('./test1.log','w')
handler3=logging.StreamHandler(f)
import sys
handler4=logging.StreamHandler(sys.stdout)
- logging.FileHandler
向一個文件中輸出日志內容。如果文件根路徑不存在,會報錯。如果文件根路徑存在,但是文件不存在,會自動創建文件。
。它的構造函數是:FileHandler(filename[,mode])
- filename是日志文件路徑。
- mode是寫文件的方法,例如’a’,’w’,參考open里面的mode
-
logging.handlers.RotatingFileHandler
類似FileHandler,不同的是這個可以管理文件的大小,如果日志文件大於某個值,就會把舊的日志重命名,並創建新的日志文件。如果有三個日志文件chat.log,chat.log.1,chat.log.2 ,時間大小:chat.log>chat.log.1>chat.log.2它的構造函數是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
- 其中filename和mode兩個參數和FileHandler一樣。
- maxBytes 最大文件大小,單位字節,0代表無限大。
- backupCount 保留的備份個數。
- demo:
handler = RotatingFileHandler('./test.log', maxBytes=10, backupCount=5)
- logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler類似,不同的是這個Handler通過時間來切分日志文件:TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數和backupCount參數和RotatingFileHandler具有相同的意義- interval是時間間隔。
- when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有以下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時代表星期一)
midnight 每天凌晨
- logging.handlers.SocketHandler
- logging.handlers.DatagramHandler
以上兩個Handler類似,都是將日志信息發送到網絡。不同的是前者使用TCP協議,后者使用UDP協議。它們的構造函數是:
Handler(host, port)
其中host是主機名,port是端口名 - logging.handlers.SysLogHandler
- logging.handlers.NTEventLogHandler
- logging.handlers.SMTPHandler
- logging.handlers.MemoryHandler
- logging.handlers.HTTPHandler
4. Formatter
logging.Formatter('%(asctime)s %(levelname)s %(module)s.%(funcName)s Line:%(lineno)d %(message)s')
常用格式:
%(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 | 用戶輸出的消息 |
5. 常用工具
1. 初始化一個logger
def allot_logger(name, filename, level=None, format=None):
'''
初始化一個logger
:param name: logger名稱
:param filename: 日志文件路徑
:param format: 日志格式
:param level: 日志的嚴重程度
:return:
'''
if level == None:
level = logging.DEBUG
if format == None:
format = '%(asctime)s %(levelname)s %(module)s.%(funcName)s Line:%(lineno)d %(message)s'
logger = logging.getLogger(name)
if not logger.handlers:
logger.setLevel(level)
handler = logging.FileHandler(filename)
handler.setFormatter(
logging.Formatter(format))
logger.handlers = [handler]
- 如果logger有多個handler,這樣會輸出重復的日志,所以添加handler前,先判斷handler的數量,而且采用設置handlers屬性的方式而不是addHandler方法,解決多線程同步問題。