私は次のような構造を持つ小さなPythonプロジェクトを持っています -
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
私はデフォルトのloggingモジュールを使って標準出力とログファイルにメッセージを出力することを計画しています。ロギングモジュールを使用するには、何らかの初期化が必要です -
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')
logger.info('testing')
現在、メッセージのロギングを開始する前に、すべてのモジュールでこの初期化を実行しています。プロジェクト全体でログを記録して同じ設定を再利用するように、この初期化を一箇所で一度だけ実行することはできますか
ベストプラクティスは、各モジュールで、次のようにロガーを定義することです。
import logging
logger = logging.getLogger(__name__)
モジュールの上部付近、そしてモジュール内の他のコードでは、.
logger.debug('My message with %s', 'variable data')
モジュール内でロギングアクティビティを細分化する必要がある場合は、例えば.
loggerA = logging.getLogger(__+ '.A')
loggerB = logging.getLogger(__+ '.B')
そして、必要に応じてloggerA
およびloggerB
にログインします。
あなたのメインプログラムでは、例えば:
def main():
"your program code"
if __== '__main__':
import logging.config
logging.config.fileConfig('/path/to/logging.conf')
main()
または
def main():
import logging.config
logging.config.fileConfig('/path/to/logging.conf')
# your program code
if __== '__main__':
main()
複数のモジュールからのロギングについては here を、他のコードによってライブラリモジュールとして使用されるコードのロギング設定については here を参照してください。
更新:fileConfig()
を呼ぶとき、Python 2.6以降を使っているならdisable_existing_loggers=False
を指定したいかもしれません( the docs を見てください)詳細については)。下位互換性を保つため、デフォルト値はTrue
です。これにより、既存のすべてのロガーがその設定で明示的に指定されていない限り、fileConfig()
によって無効になります。値をFalse
に設定すると、既存のロガーはそのまま残されます。 Python 2.7/Python 3.2以降を使用している場合は、dictConfig()
APIよりも優れているfileConfig()
APIを検討するとよいでしょう。
実際には、すべてのロガーは親のパッケージロガーの子です(つまり、package.subpackage.module
はpackage.subpackage)
から設定を継承します。したがって、ルートロガーを設定するだけで済みます。これは logging.config.fileConfig
(自分の設定で実現できます) (ロガーの場合)または logging.basicConfig
(ルートロガーを設定します)エントリモジュールでのロギングの設定(__main__.py
または実行したいものは何でも。たとえばmain_script.py
。__init__.py
も同様に機能します)
basicConfigを使用して:
# package/__main__.py
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
fileConfigを使う:
# package/__main__.py
import logging
import logging.config
logging.config.fileConfig('logging.conf')
そして、次のようにしてすべてのロガーを作成します。
# package/submodule.py
# or
# package/subpackage/submodule.py
import logging
log = logging.getLogger(__name__)
log.info("Hello logging!")
詳細については、 Advanced Logging Tutorial を参照してください。
私はいつも以下のようにします。
単一のpythonファイルを使用して、ログを 'log_conf.py
'という名前のシングルトンパターンとして設定します。
#-*-coding:utf-8-*-
import logging.config
def singleton(cls):
instances = {}
def get_instance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return get_instance()
@singleton
class Logger():
def __init__(self):
logging.config.fileConfig('logging.conf')
self.logr = logging.getLogger('root')
別のモジュールでは、設定をインポートするだけです。
from log_conf import Logger
Logger.logr.info("Hello World")
これは、簡単かつ効率的にログに記録するためのシングルトンパターンです。
これらの答えのいくつかはあなたがモジュールの一番上であなたがすることを示唆しています
import logging
logger = logging.getLogger(__name__)
これが非常に悪い習慣と考えられていることは私の理解です。その理由は、ファイルconfigがデフォルトで既存のすべてのロガーを無効にするためです。例えば。
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logger.info('Hi, foo')
class Bar(object):
def bar(self):
logger.info('Hi, bar')
そしてあなたのメインモジュールで:
#main
import logging
# load my module - this now configures the logger
import my_module
# This will now disable the logger in my module by default, [see the docs][1]
logging.config.fileConfig('logging.ini')
my_module.foo()
bar = my_module.Bar()
bar.bar()
File.ini呼び出しで既存のロガーが無効化されたため、logging.iniで指定されたログは空になります。
これを回避することは確かに可能ですが(disable_existing_Loggers = False)、実際にはあなたのライブラリの多くのクライアントはこの振る舞いを知らず、あなたのログを受け取らないでしょう。常にローカルでlogging.getLoggerを呼び出すことで、クライアントにとって簡単にすることができます。 Hat Tip: Victor Linのウェブサイト からこの振る舞いについて学びました。
そのため、代わりに常にlogging.getLoggerをローカルに呼び出すことをお勧めします。例えば。
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logging.getLogger(__name__).info('Hi, foo')
class Bar(object):
def bar(self):
logging.getLogger(__name__).info('Hi, bar')
また、メインでfileconfigを使用する場合は、ライブラリ設計者がモジュールレベルのロガーインスタンスを使用する場合に備えて、disable_existing_loggers = Falseを設定してください。
@ Yarkeeの解決策は良さそうだった。もう少し加えたいと思います -
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances.keys():
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class LoggerManager(object):
__metaclass__ = Singleton
_loggers = {}
def __init__(self, *args, **kwargs):
pass
@staticmethod
def getLogger(name=None):
if not name:
logging.basicConfig()
return logging.getLogger()
Elif name not in LoggerManager._loggers.keys():
logging.basicConfig()
LoggerManager._loggers[name] = logging.getLogger(str(name))
return LoggerManager._loggers[name]
log=LoggerManager().getLogger("Hello")
log.setLevel(level=logging.DEBUG)
そのため、LoggerManagerはアプリケーション全体にプラグイン可能です。それが理にかなった、そして価値があることを願っています。
別の解決策で投げます。
私のモジュールのメインではinit私は以下のようなものを持っています:
import logging
def get_module_logger(mod_name):
logger = logging.getLogger(mod_name)
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
return logger
それから各クラスで私はロガーを必要とします、私はします:
from [modname] import get_module_logger
logger = get_module_logger(__name__)
ログが見逃されたとき、あなたはそれらが由来するモジュールによってそれらのソースを区別することができます。
このようなことを思いつくこともできます。
def get_logger(name=None):
default = "__app__"
formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"}
if name:
logger = logging.getLogger(name)
else:
logger = logging.getLogger(default)
fh = logging.FileHandler(log_map[name])
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.setLevel(logging.DEBUG)
return logger
上記が別のモジュールで定義されていて、他のモジュールにインポートされている場合は、同じモジュール内でプロジェクト全体で複数のロガーを使用することができます。
a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starting logging!")
b.debug("Debug Mode")
いくつかの答えがあります。私は私にとって理にかなっているが、多分それはあなたにも理にかなっているかもしれませんが似たようなまだ別のソリューションになった。私の主な目的はそれらのレベル(コンソールへのデバッグレベルログ、ファイルへの警告以上)でログをハンドラに渡すことができるようにすることでした:
from flask import Flask
import logging
from logging.handlers import RotatingFileHandler
app = Flask(__name__)
# make default logger output everything to the console
logging.basicConfig(level=logging.DEBUG)
rotating_file_handler = RotatingFileHandler(filename="logs.log")
rotating_file_handler.setLevel(logging.INFO)
app.logger.addHandler(rotating_file_handler)
logger.pyという名前のNice utilファイルを作成しました。
import logging
def get_logger(name):
return logging.getLogger("flask.app." + name)
flask.appはflaskにハードコードされた値です。アプリケーションロガーはいつもflask.appをモジュール名として始めています。
今、各モジュールでは、私は次のモードでそれを使用することができます:
from logger import get_logger
logger = get_logger(__name__)
logger.info("new log")
これにより、最小限の労力で "app.flask.MODULE_NAME"の新しいログが作成されます。
ベストプラクティスは、呼び出し側のメソッドにロガーハンドラを渡すというタスクを持つメソッドを1つだけ持つモジュールを個別に作成することです。このファイルをm_logger.pyとして保存します
import logger, logging
def getlogger():
# logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
#ch = logging.StreamHandler()
ch = logging.FileHandler(r'log.txt')
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
return logger
ロガーハンドラが必要なときはいつでもgetlogger()メソッドを呼び出します。
from m_logger import getlogger
logger = getlogger()
logger.info('My mssg')