- 為何要使用logging?
- 程式執行中,有時需要輸出一些訊息來記錄執行狀態、錯誤、...
- 訊息可以寫在檔案中,較緊急的訊息可能同時要寫檔案、console顯示、寄email提醒、(或其它管道)
- 使用logging模組,可以讓我們方便達成單一訊息送至多個管道的功能(個人覺得是最大的好處)
- 只在console顯示 (stderr, 預設等級warning以上才顯示,從輕到嚴重分成debug, info, warning, error, fatal/critical 五級)
- 改成從sys.stdout輸出,層級是debug以上就顯示,可使用logging.basicConfig:
- 注意:logging.basicConfig 必須在輸出訊息之前呼叫,而且只能呼叫一次。第二次就沒效了。
- logging.basicConfig 的詳細介紹,請呼叫 print(logging.basicConfig.__doc__),可看到它還有哪些參數可以使用。
- 如何將訊息輸出至檔案?
- 如何同時輸出至console和檔案?下例會同時輸出在console和log.txt中。當只有單一輸出時,可以用filename來指定目標檔案,或用stream來指定目標stream。如果要輸出至多個目標,就要將它們以list of handlers當參數傳入。
- 練習一下,如果要同時輸出到stdout和stderr,可以這麼作(當然我們應該不會真的這麼作):
- 輸出的訊息格式是可以改的。例如我們如果要將訊息放在最前面,可以這麼作:
- format當中,可以使用的參數有:
- 時間的格式可以更改,方式是使用 datefmt 參數:
- 如果要印出milliseconds,不能使用datefmt='%Y/%m/%d %H:%M:%S.%f',而是要這麼作(參考 10 當中的 %(msecs)d ):
>>> import logging
>>> logging.debug('Hi')
>>> logging.info('Hi')
>>> logging.warning('Hi')
WARNING:root:Hi
>>> logging.error('Hi')
ERROR:root:Hi
>>> logging.fatal('Hi')
CRITICAL:root:Hi
>>>
>>> import sys
>>> import logging
>>> logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
>>> logging.debug('Debug Msg')
DEBUG:root:Debug Msg
>>> logging.info('Info')
INFO:root:Info
>>> logging.warning('This is a warning')
WARNING:root:This is a warning
>>> logging.error('錯誤發生了')
ERROR:root:錯誤發生了
>>> logging.fatal('快來救人阿')
CRITICAL:root:快來救人阿
# 輸出至 log.txt,如果已存在會接著記錄
logging.basicConfig(filename='log.txt')
# 輸出至 log.txt,同上
logging.basicConfig(filename='log.txt', filemode='a')
# 輸出至 log.txt,會開新檔案
logging.basicConfig(filename='log.txt', filemode='w')
>>> import sys
>>> import logging
>>> logging.basicConfig(handlers=[logging.StreamHandler(sys.stderr), logging.FileHandler('log.txt')], level=logging.CRITICAL)
>>> logging.debug("Let's debug") # 無輸出
>>> logging.critical("Let's go crazy")
CRITICAL:root:Let's go crazy
>>> import sys, logging
>>> logging.basicConfig(handlers=[logging.StreamHandler(sys.stdout), logging.StreamHandler(sys.stderr)])
>>> logging.warning('你確定要這麼作嗎?')
WARNING:root:你確定要這麼作嗎?
WARNING:root:你確定要這麼作嗎?
>>> import logging
>>> logging.basicConfig(format='%(message)s:%(levelname)s:%(name)s')
>>> logging.warning('倒過來看會有些不習慣')
倒過來看會有些不習慣:WARNING:root
%(name)s logger名稱(之後介紹)
%(levelno)s 10, 20, ... 50 =>DEBUG, INFO, WARNING, ERROR, CRITICAL
%(levelname)s DEBUG, INFO, WARNING, ERROR, CRITICAL
%(pathname)s 呼叫logging的執行原始碼的完整路徑
%(filename)s %(pathnames)s 中的檔名部份
%(module)s Module
%(lineno)d 原始碼正執行到的行數
%(funcName)s Function name
%(created)f 一筆log訊息的產生時間(time.time() return value)
%(asctime)s 一筆log訊息的產生時間(文字格式)
%(msecs)d 一筆log訊息的產生時間的毫秒部份
%(relativeCreated)d 從logging載入算起,至一筆log訊息產生所經毫秒數
%(thread)d Thread ID (if available)
%(threadName)s Thread name (if available)
%(process)d Process ID (if available)
%(message)s log訊息
>>> import logging
>>> logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
>>> logging.warning('Warning msg')
2014/12/30 21:51:44 Warning msg
>>> import logging
>>> logging.basicConfig(format='%(asctime)s.%(msecs)d %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
>>> logging.warning('印出milliseconds的方法如上')
2014/12/30 21:58:30.869 印出milliseconds的方法如上
(目前個人自己並沒有更進階的需求,所以暫時就到此為止)