2017-03-04 6 views
1

私はloggingモジュールをPython(3.6.0)で使用することを学び、Logging Cookbookの例から始めました。しかし、コードがループ内から実行されると、ログメッセージは複数回繰り返されます。何故ですか?この場合、ロガーを空にする方法はありますか?私はlogger.propagateで遊んだりしようとしましたが、成功しませんでした。反復の空のlogger

スクリプトtestlog.pyでの私のコード:

#!/usr/bin/env python3 

import logging 

def main(): 
    t = (1,2,1,2,1) 

    logit('Log is fine here', '_logfile', logname='INFO', level='info') 

    for i,x in enumerate(t): 
     if x == 1: 
      logit('Warn at iter {}'.format(i), '_logfile', logname='INFO', level='info') 


def logit(message, logfile, logname='LOG', level='info'): 
    '''https://docs.python.org/3.6/howto/logging-cookbook.html#logging-to-multiple-destinations''' 

    logformat = '%(asctime)-30s %(levelname)-8s %(name)s\t%(message)s' 
    dateformat = '[ %Y-%m-%d %H:%M:%S ]' 
    # set up logging to file 
    logging.basicConfig(level=logging.DEBUG, 
         format=logformat, 
         datefmt=dateformat, 
         filename=logfile, 
         filemode='a') 

    # define a Handler which writes INFO messages or higher to the sys.stderr 
    console = logging.StreamHandler() 
    console.setLevel(logging.DEBUG) 
    # set a format which is simpler for console use 
    formatter = logging.Formatter(logformat, datefmt=dateformat) 
    # tell the handler to use this format 
    console.setFormatter(formatter) 
    # add the handler to the root logger 
    logging.getLogger('').addHandler(console) 
    # Now, we can log to the logger 
    logger = logging.getLogger(logname) 
    console.propagate = False 

    if level.lower() == 'debug': 
     logger.debug(message) 
    elif level.lower() == 'info': 
     logger.info(message) 
    elif level.lower().startswith('warn'): 
     logger.warning(message) 
    else: 
     logger.error(message) 

if __name__ == '__main__': 
    main() 

出力:

> ./testlog.py 
[ 2017-03-04 01:59:09 ]  INFO  INFO Log is fine here 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 0 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 0 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 2 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 2 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 2 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 4 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 4 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 4 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 4 

EDIT1:アイデアは、コンソールの両方に、ログファイルにログインすることです。 ログファイルでは、メッセージは繰り返されません。

[ 2017-03-04 01:59:09 ]  INFO  INFO Log is fine here 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 0 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 2 
[ 2017-03-04 01:59:09 ]  INFO  INFO Warn at iter 4 

答えて

0

私は以下のように動作させました(ほとんどのコードはhereに適合しています)。 まず、ロガーを作成し、異なるハンドラーを追加するための関数が必要でした。各ハンドラは、それ自身の設定レベルを持つことができます。

def set_logger(logfile, logname='LOG'): 

    logformat = '%(asctime)-30s %(levelname)-8s %(name)s\t%(message)s' 
    dateformat = '[ %Y-%m-%d %H:%M:%S ]' 

    # Setup Logging Object 
    logger = logging.getLogger(logname) 
    logger.setLevel(logging.DEBUG) 
    # Set log object to console 
    chandler = logging.StreamHandler() 
    chandler.setLevel(logging.DEBUG) 
    formatter = logging.Formatter(logformat, datefmt=dateformat) 
    chandler.setFormatter(formatter) 
    logger.addHandler(chandler) 

    # Set log object to file 
    fhandler = logging.FileHandler(filename=logfile, 
            mode='a') 
    fhandler.setLevel(logging.DEBUG) 
    formatter = logging.Formatter(logformat, datefmt=dateformat) 
    fhandler.setFormatter(formatter) 
    logger.addHandler(fhandler) 

    return logger 

その後ロガーはに取得することができます)(メイン:

def main(): 

    logger=set_logger('_logfile') 

    t = (1,2,1,2,1) 

    # logit3('Log is fine here', '_logfile', logname='INFO', level='info') 
    logger.debug('Log is fine here') 

    for i,x in enumerate(t): 
     if x == 1: 
      # logit3('Warn at iter {}'.format(i), '_logfile', logname='INFO', level='info') 
      logger.debug('Warn at iter {}'.format(i)) 

コンソールの出力は次のとおりです。ログに

[ 2017-03-04 11:21:02 ]  DEBUG LOG Log is fine here 
[ 2017-03-04 11:21:02 ]  DEBUG LOG Warn at iter 0 
[ 2017-03-04 11:21:02 ]  DEBUG LOG Warn at iter 2 
[ 2017-03-04 11:21:02 ]  DEBUG LOG Warn at iter 4 

出力ファイル:

[ 2017-03-04 11:21:02 ]  DEBUG LOG Log is fine here 
[ 2017-03-04 11:21:02 ]  DEBUG LOG Warn at iter 0 
[ 2017-03-04 11:21:02 ]  DEBUG LOG Warn at iter 2 
[ 2017-03-04 11:21:02 ]  DEBUG LOG Warn at iter 4 

これが最も適切なアプローチであるかどうかは確かですが、今のところ私が期待するように働いています。

0

それは理由logitに次の行で、具体的です: logging.getLogger('').addHandler(console)

あなたはlogit呼び出すたびに、あなたはルートロガーに別のStreamHandlerを追加しています。ロガーのすべての設定を一度行う必要があります。

+0

私は知っていますが、新しいハンドラ(この場合はコンソール)をルートロガーに追加するにはどうすればよいでしょうか。明らかに、logging.basicConfig()でファイル名とハンドラを一緒に設定することはできません。 – PedroA

+0

一般的に、ロガーを一度セットアップします。 'setup_logging'という別のメソッドを作ることができます。このメソッドは、ファイルをパラメータとして受け取り、ロガーを返します。次に、 'logit'メソッドはメッセージ、ロガー、レベルを取ります。あなたの 'main'メソッドは' logger = setup_logging( 'my_log.log') 'を持ち、' ​​logit'へのあなたの呼び出しは 'logit(logger、 'my message'、 'info')'のようになります。しかし、あなたはおそらくあなたの 'logit'メソッドを必要とせず、単に' logger.info( '私のメッセージ') 'を直接呼び出すことができます。' – Stacktrace

+0

具体的な例はありますか? – PedroA