質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

7124閲覧

pythonのlogging設定をモジュール間で共有する方法

chomechome

総合スコア4

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/04/29 10:42

前提・実現したいこと

python3.7にて、CICDツールを作成しており、logging機能を実装しております。
loggingの設定をファイルに定義し、dictconfigにて設定を読み込ませlog出力しようとしております。
モジュール間でのlogging設定を共有する方法がわからず悩んでおります。
main.pyでloggerの設定をし、sub.pyでloggerを取得し、ログ出力しております。
sub.pyおいて、関数の外側でloggerを取得できるのが理想です。(モジュール内で1回のloggerの取得で済むため)

発生している問題・エラーメッセージ

sub.pyおいて、関数の外側でloggerを取得するとログ出力されず、関数内でloggerを取得するとログ出力されます。

  • main.py

python

1logging.config.dictConfig('path to setting file') 2logger = logging.getLogger(__name__)
  • sub.py

下記はうまくいかないパターン

python

1logger = logging.getLogger(__name__) 2def funcA(): 3 logger.debug('hoge')

下記はうまくいくパターン

python

1def funcA(): 2 logger = logging.getLogger(__name__) 3 logger.debug('hoge')

補足情報(FW/ツールのバージョンなど)

python3.7、フレームワークは使用しておりません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

2番目の例でも期待通りに動作しますが、
main側でのsubの扱いはどのようにされてますか。

getLogger が dictConfig の前か後か、この場合
sub を import する位置によって動作が変わってくるはずです。


ロギングの環境設定より disable_existing_loggers

警告 fileConfig() 関数はデフォルト引数 disable_existing_loggers を取り、後方互換性のためにデフォルト値は True になっています。 これはあなたの望むものかもしれませんし、そうでないかもしれません。というのは、設定で明示的に指定したクラス (もしくはその親クラス) を除いて、 fileConfig() が呼び出される前に存在した非ルートロガーを無効化してしまうからです。 より詳細なことはリファレンスを参照し、望むならこの引数に False を指定してください。

dictConfig() に渡した辞書で、キー disable_existing_loggers にブール値を指定することができ、辞書で指定しなかった場合はデフォルトで True と解釈されます。こうすると上で説明したロガー無効化が動作しますが、これはあなたが望んだものでないかもしれません - その場合は、明示的にキーに False を指定してください。

解決策:

'disable_existing_loggers': False を設定する


disable_existing_loggers の挙動について、動作確認用のサンプルコードを追記します。
コメントアウト部分を編集して試してみてください。
(※ モジュールキャッシュの影響がないことを明示する為、
import sub が dictConfig 後の時は、ファイル先頭のimportはコメントアウトで)

(1) disable_existing_loggers(2) import sub の位置
case 1True(省略時)ファイル先頭
case 2True(省略時)dictConfig 後
case 3Falseファイル先頭
case 4FalsedictConfig 後

python

1# main.py 2 3import logging.config 4import sub 5 6if __name__ == "__main__": 7 logging.config.dictConfig({ 8 'version': 1, 9 'formatters': { 10 'brief': { 11 'format': '[%(asctime)s] %(levelname)s in %(module)s %(funcName)s: %(message)s', 12 } 13 }, 14 'handlers': { 15 'console': { 16 'class': 'logging.StreamHandler', 17 'formatter': 'brief', 18 'stream': 'ext://sys.stdout', 19 } 20 }, 21 'root': { 22 'level': 'DEBUG', 23 'handlers': ['console'] 24 }, 25 # (1) 26 # 'disable_existing_loggers': False, 27 }) 28 # (2) 29 # import sub 30 31 logger = logging.getLogger(__name__) 32 logger.debug("TEST") 33 34 sub.funcA() 35 sub.funcB()

python

1# sub.py 2 3import logging 4 5logger = logging.getLogger(__name__) 6 7def funcA(): 8 logger.debug("TEST") 9 10def funcB(): 11 logger = logging.getLogger(__name__) 12 logger.debug("TEST")

投稿2020/04/29 12:10

編集2020/04/30 03:27
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chomechome

2020/04/29 13:08

ご回答ありがとうございます。 subをimportした後にdictconfigを呼んでおります。 disable_existing_loggersはFalseにしています。 今、dictconfigを読んでからsubをimportするようにしたら関数外でloggerを取得してもログ出力されるようになりました。
chomechome

2020/04/29 13:18

dictconfigを呼んでから、subをimportするようにしたらログ出力されるようになった理由がわかりました。 dictconfigでは`rootロガー`に対して設定を定義しており、rootロガーに設定が反映される前に他ファイルでロガーを取得しても意図した設定が反映されないからです。 1. dictconfigでrootロガーに設定する。 2. subをimport 3. subでlogger取得(rootロガーの設定を引き継ぐ) 4. ログ出力 となるようです。 subをimport後に、dictconfigした際に、subの関数内でloggerを取得したらログ出力された理由。 1. subをimport 2.dictconfig 3. subの関数内でloggerを取得 →関数が呼ばれた時点のrootロガーに設定された後のloggerを取得 4.subでログ出力 ということが考察できました。
teamikl

2020/04/29 14:07 編集

解決されたみたいですが、 若干、原因に対しての認識が異なります。 >dictconfigでは`rootロガー`に対して設定を定義しており、rootロガーに設定が反映される前に他ファイルでロガーを取得しても意図した設定が反映されないからです。 ここの原因は、ドキュメントの引用箇所より > fileConfig() が呼び出される前に存在した非ルートロガーを無効化してしまうからです。 disable_existing_loggers=True の場合は、 上記に示された通りの挙動になります。 disable_existing_loggers が False の場合は、ここの挙動を変更でき 回答の2番目のコードも、getLoggerや import sub の位置に関わらず、 (dictConfig後であれば) 期待通りの挙動になるはずです。 なので、根本的な解決策は import sub を dictConfig の後にする、ではなく 'disable_existing_loggers': False の設定だと思います。 一応、import sub を後に遅らせるでも意図通りの挙動になるので 充分かもしれませんが、ファイル先頭でimport出来ない等の 制限に成ります。 > subをimportした後にdictconfigを呼んでおります。 > disable_existing_loggersはFalseにしています。 もし、この条件で質問文に記載されたような挙動になっていた場合は、 dictConfigの設定方法に齟齬があるのかもしれません。 disable_existing_loggersが正しく False に設定されているか、 TrueとFalseで挙動の違いを確認できるか等を再確認してみてください。
chomechome

2020/04/30 01:58

ご回答ありがとうございます。 disable_existing_loggersのTrue、Falseの挙動について、これから確認いたします。 昨日、実験して確認した内容は下記になります。 sub.pyについて下記のように関数外でloggerを取得する。 ```python logger = logging.getLogger(__name__) def funcA(): logger.debug('hoge') ``` main.pyについて下記のように、sub.pyをimport後にdictconfigにて設定する。 sub.pyでは関数外でloggerを取得しているので、sumをimportした際にloggerの取得が行われ、そのloggerはmain.pyでのloggerの設定が効いていない。 ```python import sub logging.config.dictConfig('path to setting file') sub.funcA() ``` dictconfigした後にsubをimportするようにしたら、dictconfigにてロガーへの設定が行われ、subをimportした際に設定完了したロガーが読み込まれる。 ```python logging.config.dictConfig('path to setting file') import sub sub.funcA() ```
teamikl

2020/04/30 02:37

「disable_existing_loggersがTrue の時」の挙動は、説明された通りで合ってます。 それ自体は間違いではないのですが、認識が異なると思った点は >disable_existing_loggersはFalseにしています。 とのことなので、懸念があるのは、 disable_existing_loggers を False にしたつもりが設定が効いてないケース。 この設定は、デフォルト(何も指定しない場合) で True です。 logging.config.dictConfig('path to setting file') の'path to setting file' で省略された箇所が重要で、 特に disable_existing_loggers を設定した箇所辺りを要確認。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問