2013-04-08 59 views
15

任務的Python:在所有模塊自定義日誌記錄

我有腳本的集合,我想他們產生最小的改動統一日誌消息模塊做記錄的實際信息。

我寫了一個小模塊'custom_logger',我打算從主應用程序調用一次,讓它返回一個記錄器,然後我將繼續使用。

我會導入到應用程序的子模塊只能(或者更確切地說,我希望他們)

  • 只能「進口記錄日誌」 - 這樣沒有具體到我的網站需要做如果有人發現它們有用,它們就會運行。
  • 應該只是記錄與log.info/error('message消息「),而不添加任何特定的站點到他們
  • 應該使用已配置‘與所有的格式和左撇子,而不是根’記錄影響根記錄的配置

* custom_logger.py *

import logging 
import logging.handlers 
import os 
import sys 


def getLogger(name='root', loglevel='INFO'): 
    logger = logging.getLogger(name) 

    # if logger 'name' already exists, return it to avoid logging duplicate 
    # messages by attaching multiple handlers of the same type 
    if logger.handlers: 
    return logger 
    # if logger 'name' does not already exist, create it and attach handlers 
    else: 
    # set logLevel to loglevel or to INFO if requested level is incorrect 
    loglevel = getattr(logging, loglevel.upper(), logging.INFO) 
    logger.setLevel(loglevel) 
    fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
    fmt_date = '%Y-%m-%dT%T%Z' 
    formatter = logging.Formatter(fmt, fmt_date) 
    handler = logging.StreamHandler() 
    handler.setFormatter(formatter) 
    logger.addHandler(handler) 

    if logger.name == 'root': 
     logger.warning('Running: %s %s', 
        os.path.basename(sys.argv[0]), 
        ' '.join(sys.argv[1:])) 
    return logger 

然後是它有什麼不的什麼作品例子幾個測試消息的子模塊。

submodule.py

import sys 
import custom_logger 
import logging 


class SubClass(object): 

    def __init__(self): 
    # NOK (no idea why since by default (no name parameter), it should return the root logger) 
    #log = logging.getLogger() 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    #log = logging.getLogger('root') 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/__init__') 


    def SomeMethod(self): 
    # OK but I'd have to define `log` for every method, which is unacceptable 
    # Please see question below all code snippets 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/SomeMethod') 

和主要應用:app.py這裏沒有什麼特別的:

#!/usr/bin/python 

import custom_logger 
import submodule 

log = custom_logger.getLogger('root', loglevel='DEBUG') 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

輸出,我以後和我得到我,只是以極其醜陋的方式:

% ./app.py 
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py 
2013-04-08T03:07:46BST app.py    DEBUG : debug message 
2013-04-08T03:07:46BST app.py    INFO : info message 
2013-04-08T03:07:46BST app.py    WARNING : warning message 
2013-04-08T03:07:46BST app.py    ERROR : error message 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/SomeMethod 

我希望能夠在app.py中定義一個記錄器,然後在子模塊中只使用標準的Python日誌記錄庫來使用app.py中已配置的記錄器。

此外,一個醜陋的解決方法:如果我把下面的代碼在submodule.py進口後:

log = custom_logger.getLogger('root') 

之前我在記錄器被app.py配置,有效地使子模塊將被執行,不是我的應用程序配置日誌

另一個解決辦法我認爲是:子類的constuctor內,我可以定義

self.log = custom_logger.getLogger('root')

然後用self.log.error( '一些錯誤')。必須有更好的方法 - 如果您能提出有用的建議或指出我誤解了文檔的地方,我會非常感激!

PS。我花了很多時間閱讀Python日誌記錄howto(basic和advanced)和cookbook,如果我錯過了某些有用的東西,請指出。

謝謝!

回答

3

如果你想改變你可以只使用getLogger()無處不在,不帶任何參數根記錄。

關於實例安裝只在主模塊,你可以實例化你的記錄,添加自己的處理程序,並在所有其它子模塊使用它(像我一樣波紋管)。

custom_logger.py創建繼承StreamHandler中的一類:

class MyHandler(logging.StreamHandler): 

    def __init__(self): 
     logging.StreamHandler.__init__(self) 
     fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
     fmt_date = '%Y-%m-%dT%T%Z' 
     formatter = logging.Formatter(fmt, fmt_date) 
     self.setFormatter(formatter) 

然後,在submodule.py,我把getLogger進口之後,並在方法評價它:

import sys 
import logging 

log = logging.getLogger('root') 

class SubClass(object): 

    def __init__(self): 
     log.info('message from SubClass/__init__') 

    def SomeMethod(self): 
     log.info('message from SubClass/SomeMethod') 

然後,在app.py我創建了一個記錄器實例(這將是在所有模塊相同),並加入我的處理程序,其格式輸出:

#!/usr/bin/python 

import logging 
import custom_logger 
import submodule 

log = logging.getLogger('root') 
log.setLevel('DEBUG') 
log.addHandler(custom_logger.MyHandler()) 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

輸出:

./app.py 
2013-04-08T15:20:05EEST app.py    DEBUG : debug message 
2013-04-08T15:20:05EEST app.py    INFO : info message 
2013-04-08T15:20:05EEST app.py    WARNING : warning message 
2013-04-08T15:20:05EEST app.py    ERROR : error message 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/SomeMethod 
+0

謝謝米哈伊。我想我會有更多的時間來看看它,但我需要等待週末。到目前爲止,我已經能夠通過在submodule.py中將日誌定義爲getLogger對象來使我的類可以完成所有工作(附加格式器,處理程序和設置日誌級別)。我希望這可以在不將事物放在類定義之外的情況下完成。 我的問題更多的是「爲什麼我所做的某些方法沒有按預期工作,因爲我想了解其背後的原因,而不是將代碼交給我,但我非常感謝您的幫助: ) – 2013-04-10 01:27:35

+0

我更新了我的答案,除此之外,您可以查看模塊的代碼。您可以看到根記錄器在導入過程中被實例化了,我也不明白爲什麼getLogger(「root」)不能正常工作在所有情況下(你可以在app.py中執行getLogger(),在submodule.py中執行getLogger(「root」),你將得到你所需要的東西,但是反之亦然) – Mihai 2013-04-10 14:15:47

+0

如何使用stdout重定向到文件例如python ./app.py >> file.log? – 2016-04-14 11:37:45