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的方法如上
待續.....
(目前個人自己並沒有更進階的需求,所以暫時就到此為止)

2014年12月29日 星期一

林海峰與藤澤朋齋的東坡棋故事

在Wikipedia上的林海峰先生介紹中,看到了他與藤澤朋齋的東坡棋故事。Wikipedia上寫的是錯的。我又試在用Google找了一下,發現看到的內容和Wikipedia上的差不多,也是錯的。Wikipedia寫說:
五勝一敗的林海峰於名人挑戰權中關鍵賽中遭遇藤澤朋齋九段,其師吳清源料中藤澤必以東坡棋(模仿棋)應戰,乃教之搶佔天元的破解法,使藤澤無從模仿。歷經十多小時之纏鬥,藤澤棄子投降。另外,棋界人士發現此戰從第一手至第七十三手竟與八年前吳清源對戰藤澤朋齋之對戰下位完全相同,為棋界至今津津樂道。
小時候在家裡看過三四十年前出版的「林海峰的人和棋」,當中有正確的版本。那本書應該還在,不過要花時間找一下。實際情形是,那一步天元是他自己臨場想的
林海峰在和藤澤朋齋比賽之前,去找了吳清源。吳清源擺了自己之前和藤澤朋齋的棋,那一局藤澤朋齋下東坡棋,而且最後吳清源輸了。因此,受其思路之影響,林海峰前面下出了和吳清源相同的棋。
但是,林海峰臨場想說:「這樣下去不是辦法。當年老師輸了,我如果照老師的棋繼續下,最後也難逃敗局。」於是,他花了一兩個小時的時間(忘記是一個多或兩個多小時),思考下一手棋。長考後,他下在天元,讓對手無法再模仿。最後仍經過波折才贏得了該局,而非wikipedia所說,好像搶了天元就贏了(棋靈王看太多?)
先記錄在此,哪天找到了書,再去幫wikipedia改一下。