2014年12月30日 星期二

Python logging (一)

以下是python logging的徹底研究,大家可以一條一條的讀下去,相信會對logging模組的使用有幫助。
  1. 為何要使用logging?
    • 程式執行中,有時需要輸出一些訊息來記錄執行狀態、錯誤、...
    • 訊息可以寫在檔案中,較緊急的訊息可能同時要寫檔案、console顯示、寄email提醒、(或其它管道)
    • 使用logging模組,可以讓我們方便達成單一訊息送至多個管道的功能(個人覺得是最大的好處)
  2. 只在console顯示 (stderr, 預設等級warning以上才顯示,從輕到嚴重分成debug, info, warning, error, fatal/critical 五級)
  3. >>> 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
    >>>
  4. 改成從sys.stdout輸出,層級是debug以上就顯示,可使用logging.basicConfig:
  5. >>> 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:快來救人阿

  6. 注意:logging.basicConfig 必須在輸出訊息之前呼叫,而且只能呼叫一次。第二次就沒效了。
  7. logging.basicConfig 的詳細介紹,請呼叫 print(logging.basicConfig.__doc__),可看到它還有哪些參數可以使用。
  8. 如何將訊息輸出至檔案?
  9. # 輸出至 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')
  10.  如何同時輸出至console和檔案?下例會同時輸出在console和log.txt中。當只有單一輸出時,可以用filename來指定目標檔案,或用stream來指定目標stream。如果要輸出至多個目標,就要將它們以list of handlers當參數傳入。
  11. >>> 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
  12.  練習一下,如果要同時輸出到stdout和stderr,可以這麼作(當然我們應該不會真的這麼作):
  13. >>> import sys, logging
    >>> logging.basicConfig(handlers=[logging.StreamHandler(sys.stdout), logging.StreamHandler(sys.stderr)])
    >>> logging.warning('你確定要這麼作嗎?')
    WARNING:root:你確定要這麼作嗎?
    WARNING:root:你確定要這麼作嗎?
  14.  輸出的訊息格式是可以改的。例如我們如果要將訊息放在最前面,可以這麼作:
  15. >>> import logging
    >>> logging.basicConfig(format='%(message)s:%(levelname)s:%(name)s')
    >>> logging.warning('倒過來看會有些不習慣')
    倒過來看會有些不習慣:WARNING:root

  16. format當中,可以使用的參數有:
  17. %(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訊息
  18. 時間的格式可以更改,方式是使用 datefmt 參數:
  19. >>> 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
  20. 如果要印出milliseconds,不能使用datefmt='%Y/%m/%d %H:%M:%S.%f',而是要這麼作(參考 10 當中的 %(msecs)d ):
  21. >>> 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的方法如上
待續.....
(目前個人自己並沒有更進階的需求,所以暫時就到此為止)

沒有留言:

張貼留言