2011-02-10 26 views
5

こんにちは
それは最高?独自のロギングレベルの独自のログメソッドを作成する方法

私のオリジナルの願いはstdoutにルート・ファイルへすべてを書いロガー、さらに名前のロガー(「rrcheck」)書き込みを持つことであるが、後者はまた、いくつかの他の方法とのレベルを持っている必要があります。 "!PFXWRN"という接頭辞を付けたメッセージを追加する必要があります(ただし、標準出力に行く人のみ)。他のメッセージは変更しないでください。また、ログレベルをと別に設定すると、がrootとnamed loggerになります。

これは私のコードです:

class CheloExtendedLogger(logging.Logger): 
    """ 
    Custom logger class with additional levels and methods 
    """ 
    WARNPFX = logging.WARNING+1 

    def __init__(self, name): 
     logging.Logger.__init__(self, name, logging.DEBUG)     

     logging.addLevelName(self.WARNPFX, 'WARNING') 

     console = logging.StreamHandler() 
     console.setLevel(logging.DEBUG) 
     # create formatter and add it to the handlers 
     formatter = logging.Formatter("%(asctime)s [%(funcName)s: %(filename)s,%(lineno)d] %(message)s") 
     console.setFormatter(formatter) 

     # add the handlers to logger 
     self.addHandler(console) 

     return 

    def warnpfx(self, msg, *args, **kw): 
     self.log(self.WARNPFX, "! PFXWRN %s" % msg, *args, **kw) 


logging.setLoggerClass(CheloExtendedLogger)  
rrclogger = logging.getLogger("rrcheck") 
rrclogger.setLevel(logging.INFO) 

def test(): 
    rrclogger.debug("DEBUG message") 
    rrclogger.info("INFO message") 
    rrclogger.warnpfx("warning with prefix") 

test() 

そして、これが出力されます - 機能とlilne番号が間違っている:代わりにテストのwarnpfx

2011-02-10 14:36:51,482 [test: log4.py,35] INFO message 
2011-02-10 14:36:51,497 [warnpfx: log4.py,26] ! PFXWRN warning with prefix 

はたぶん自分のロガーのアプローチがあります最高のものではない?
あなたはどのような方向に行くと思いますか(独自のロガー、ハンドラ、独自のフォーマッタなど)?

さらに別のロガーを希望する場合はどうすればいいですか?
生憎のロギングは、あなたがPython sourcesをチェックすると、あなたがいることを参照してくださいよ...そう、その後のgetLogger(名前)が必要なものを取ると、

よろしく、
ズビグニエフ

答えて

4

を自分のロガーを登録する可能性がありません原因は、Logger.findCallerメソッドであり、呼び出しスタックを通って進み、logging.pyファイルにない最初の行を検索します。このため、self.logへのカスタム呼び出しでは、CheloExtendedLogger.warnpfxに間違った行が登録されます。

残念ながら、logging.pyのコードは非常にモジュラーではないので、修正はかなり醜いです:あなたは、あなたのサブクラスでfindCaller方法を自分で再定義する必要があり、それは考慮にlogging.pyファイルと内のファイルの両方をとるようにロガーは常駐しています(ファイル内にロガー以外のコードがあってはいけない、または結果が不正確になることに注意してください)。これは、メソッド本体内の1つの行の変更が必要です。これが機能するために

class CheloExtendedLogger(logging.Logger): 

    [...] 

    def findCaller(self): 
     """ 
     Find the stack frame of the caller so that we can note the source 
     file name, line number and function name. 
     """ 
     f = logging.currentframe().f_back 
     rv = "(unknown file)", 0, "(unknown function)" 
     while hasattr(f, "f_code"): 
      co = f.f_code 
      filename = os.path.normcase(co.co_filename) 
      if filename in (_srcfile, logging._srcfile): # This line is modified. 
       f = f.f_back 
       continue 
      rv = (filename, f.f_lineno, co.co_name) 
      break 
     return rv 

を、あなたのファイルに独自の_srcfile変数を定義する必要があります。コピー&ペーストをするには、再度持っているので、ここでも、logging.pyは、関数を使用していないのではなく、モジュールレベルですべてのコードを置く:

if hasattr(sys, 'frozen'): #support for py2exe 
    _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:]) 
elif string.lower(__file__[-4:]) in ['.pyc', '.pyo']: 
    _srcfile = __file__[:-4] + '.py' 
else: 
    _srcfile = __file__ 
_srcfile = os.path.normcase(_srcfile) 

さて、あなたはコンパイルしたバージョンのために気にしないかもしれない場合は、最後の2行で十分です。

期待通りに今、あなたのコードは動作します:複数のロガークラスについては

2011-02-10 16:41:48,108 [test: lg.py,16] INFO message 
2011-02-10 16:41:48,171 [test: lg.py,17] ! PFXWRN warning with prefix 

、あなたがロガー名とロガークラス間の依存関係を気にしないならば、あなたはlogging.Loggerそのサブクラスを作ることができますその名前が何であったかに基づいて、呼び出しを適切なロガークラスに委任します。おそらく他の、よりエレガントな可能性がありますが、私は今は思うことができません。

+0

ありがとうDzinX。私はもう少し試してみましたが、self.logの代わりにself._logを呼び出すように見えます。 – Zbigniew

+0

Aaah、それは 'currentframe()'がコールスタックの4番目のトップ関数を返すからです:)それらのどれが醜いか:) – DzinX

関連する問題