logging.config
--- ロギングの環境設定¶
ソースコード: Lib/logging/config.py
この節は、logging モジュールを設定するための API を解説します。
環境設定のための関数¶
以下の関数は logging モジュールの環境設定をします。これらの関数は、 logging.config
にあります。これらの関数の使用はオプションです --- logging
モジュールはこれらの関数を使うか、 (logging
自体で定義されている) 主要な API を呼び出し、 logging
か logging.handlers
で宣言されているハンドラを定義することで設定できます。
-
logging.config.
dictConfig
(config)¶ 辞書からロギング環境設定を取得します。この辞書の内容は、以下の 環境設定辞書スキーマ で記述されています。
環境設定中にエラーに遭遇すると、この関数は適宜メッセージを記述しつつ
ValueError
,TypeError
,AttributeError
またはImportError
を送出します。例外を送出する条件を (不完全かもしれませんが) 以下に列挙します:文字列でなかったり、実際のロギングレベルと関係ない文字列であったりする
level
。ブール値でない
propagate
の値。対応する行き先を持たない id。
インクリメンタルな呼び出しの中で見つかった存在しないハンドラ id。
無効なロガー名。
内部や外部のオブジェクトに関わる不可能性。
解析は
DictConfigurator
クラスによって行われます。このクラスのコンストラクタは環境設定に使われる辞書に渡され、このクラスはconfigure()
メソッドを持ちます。logging.config
モジュールは、呼び出し可能属性dictConfigClass
を持ち、これはまずDictConfigurator
に設定されます。dictConfigClass
の値は適切な独自の実装で置き換えられます。dictConfig()
はdictConfigClass
を、指定された辞書を渡して呼び出し、それから返されたオブジェクトのconfigure()
メソッドを呼び出して、環境設定を作用させます:def dictConfig(config): dictConfigClass(config).configure()
例えば、
DictConfigurator
のサブクラスは、自身の__init__()
でDictConfigurator.__init__()
を呼び出し、それから続くconfigure()
の呼び出しに使えるカスタムの接頭辞を設定できます。dictConfigClass
は、この新しいサブクラスに束縛され、そしてdictConfig()
はちょうどデフォルトの、カスタマイズされていない状態のように呼び出せます。バージョン 3.2 で追加.
-
logging.config.
fileConfig
(fname, defaults=None, disable_existing_loggers=True, encoding=None)¶ ログ記録の環境設定を
configparser
形式ファイルから読み出します。そのファイルの形式は 環境設定ファイルの書式 で記述されているとおりにしなければなりません。この関数はアプリケーションから何度も呼び出すことができ、これによって、 (設定を選択し、選択された設定を読み出す機構をデベロッパが提供していれば) 複数の準備済みの設定からエンドユーザが選択するようにできます。- パラメータ
fname -- ファイル名、あるいはファイルのようなオブジェクト、または
RawConfigParser
派生のインスタンス。RawConfigParser
派生のインスタンスが与えられれば、それはそのまま使われます。そうでない場合Configparser
がインスタンス化され、設定はそれを使ってfname
が指すオブジェクトから読み込まれます。それがreadline()
メソッドを持っていればそれはファイルのようなオブジェクトと仮定され、read_file()
で読み込まれます; そうでない場合、それはファイル名と仮定されて、read()
に渡されます。defaults -- ConfigParser に渡されるデフォルト値をこの引数で指定することができます。
disable_existing_loggers --
False
が指定されるとこの呼び出しが行われたときに存在するロガーは有効のまま残されます。後方互換性のあるやり方で古い振る舞いを保つので、デフォルト値はTrue
になっています。そのような振る舞いでは、既存の非ルートロガーまたはそれらのロガーの先祖がロギング設定の中で明示的に名付けられていない限り、既存のロガーを無効にします。
バージョン 3.4 で変更:
fname
としてRawConfigParser
のサブクラスのインスタンスが渡せ得るようになっています。これによってこのようなことが容易になります:ロギングの設定が、アプリケーション全体の設定における単なる一部であるような設定ファイルの使用。
ファイルから設定を読み込み、
fileConfig
に通す前に(例えばコマンドラインパラメータやランタイム環境の他のなにかで)アプリケーションによって修正するようなこと。
バージョン 3.10 で追加: encoding パラメータが追加されました。
-
logging.config.
listen
(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)¶ 指定されたポートでソケットサーバを起動し、新しい設定を待ち受けます。ポートが指定されなかった場合は、モジュールのデフォルトの
DEFAULT_LOGGING_CONFIG_PORT
が使用されます。ロギング設定はdictConfig()
あるいはfileConfig()
で処理できるファイルとして送信されます。Thread
インスタンスを返し、このインスタンスのstart()
を呼び出してサーバを起動し、適切なところでjoin()
を呼び出すことができます。サーバを停止するには、stopListening()
を呼び出します。verify
引数を指定する場合は、これはソケットを通して受け取ったバイト文字列が妥当であるか、処理すべきであるかどうかを検査する callable である必要があります。ソケットを通じて、暗号化または署名あるいはその両方を受け取ることがあります。そのような場合に、verify
callable が署名の正当性検査または暗号化の復号あるいはその両方を実施することが出来ます。verify
callable は単一引数で呼び出されます - ソケットを通じて受け取ったバイト文字列です - そして処理すべきバイト文字列、または捨て去られるべきであることを示すためのNone
を返す必要があります。返却されるバイト文字列は(たとえば正当性検査だけが行われて)渡されたものと同じかもしれませんし、あるいは(おそらく暗号化の復号が行われて)まったく異なるものかもしれません。ソケットに設定を送るには、まず設定ファイルを読み、それを
struct.pack('>L', n)
を使って長さ 4 バイトのバイナリにパックしたものを前に付けたバイト列としてソケットに送ります。注釈
設定の一部は
eval()
を通じて渡されるため、この関数を利用することはユーザーをセキュリティ上のリスクにさらす可能性があります。この関数はlocalhost
のソケットだけにバインドされており、リモートマシンからの接続を受け付けませんが、それでもlisten()
を呼び出したプロセスのアカウントのもとで信頼できないコードが実行されうるシナリオが存在します。特に、listen()
を呼び出したプロセスが複数のユーザーが利用するマシン上で実行されており、ユーザー同士が互いに信頼できない場合、悪意あるユーザーが被害者ユーザーのプロセス上で本質的に任意のコードを実行するように計画する可能性があります。攻撃は、単に被害者ユーザーのlisten()
ソケットに接続して、被害者ユーザーのプロセス上で攻撃者が実行したいコードが実行されるような設定を送り込むだけです。この攻撃はデフォルトのポートが使われている場合きわめて容易であり、異なるポートが使われている場合でもそれほど難しくはありません。このような事象が発生するリスクを回避するためには、listen()
のverify
引数を使って不正な設定が適用されるのを防ぐようにしてください。バージョン 3.4 で変更:
verify
引数が追加されました。注釈
既存のロガーを無効にしない構成をリスナーに送信する場合は、設定にはJSONフォーマットを使用する必要があります。これは、設定に
dictConfig()
を使用します。 このメソッドを使用すると、disable_existing_loggers
にFalse
を指定した設定を送信できます。
セキュリティで考慮すべき点¶
logging の設定機能は便利さを提供します。その便利さの一部は設定ファイル内のテキストを logging の設定に使われる Python オブジェクトに変換する機能を提供することによって実現されています - たとえば、 ユーザ定義オブジェクト で説明されているような機能です。しかし、まさにこのメカニズム (実行可能オブジェクトをユーザー定義モジュールからインポートし、設定ファイルから読み込んだパラメータを使ってそれらを呼び出すこと) が任意のコードを呼び出すことに利用できる可能性があります。そして、この理由により、信頼できない情報源から取得した設定ファイルは 細心の注意 を払って取り扱わなければなりません。そのようなファイルをロードする場合、そのファイルがいかなる問題も起こさないと確認した上で実際にファイルをロードしてください。
環境設定辞書スキーマ¶
ロギング設定を記述するには、生成するさまざまなオブジェクトと、それらのつながりを列挙しなければなりません。例えば、 'console' という名前のハンドラを生成し、'startup' という名前のロガーがメッセージを 'console' ハンドラに送るというようなことを記述します。これらのオブジェクトは、 logging
モジュールによって提供されるものに限らず、独自のフォーマッタやハンドラクラスを書くことも出来ます。このクラスへのパラメータは、 sys.stderr
のような外部オブジェクトを必要とすることもあります。これらのオブジェクトとつながりを記述する構文は、以下の オブジェクトの接続 で定義されています。
辞書スキーマの詳細¶
dictConfig()
に渡される辞書は、以下のキーを含んでいなければなりません:
version - スキーマのバージョンを表す整数値に設定されます。現在有効な値は 1 だけですが、このキーがあることで、このスキーマは後方互換性を保ちながら発展できます。
その他すべてのキーは省略可能ですが、与えられたなら以下に記述するように解釈されます。以下のすべての場合において、 '環境設定辞書' と記載されている所では、その辞書に特殊な '()'
キーがあるかを調べることで、カスタムのインスタント化が必要であるか判断されます。その場合は、以下の ユーザ定義オブジェクト で記述されている機構がインスタンス生成に使われます。そうでなければ、インスタンス化するべきものを決定するのにコンテキストが使われます。
formatters - 対応する値は辞書で、そのそれぞれのキーがフォーマッタ id になり、それぞれの値が対応する
Formatter
インスタンスをどのように環境設定するかを記述する辞書になります。設定辞書は
Formatter
オブジェクトを作成するときの引数に対応する、次のようなオプションキーがないか探索されます。format
datefmt
style
validate
(バージョン3.8以降)
オプションの
class
キーはフォーマッタークラスの名前を表します(モジュールとクラス名をドットで繋げる)。インスタンス化時の引数はFormatter
と同じであるため、このキーはFormatter
をカスタマイズしたサブクラスのインスタンス化に使うのがもっとも便利です。例えばトレースバックにさらに情報を付加したり、情報を要約代替クラスを実装するといったことが想定されます。もし、自作のフォーマッターが異なる引数や追加の設定引数を持つ場合は、 ユーザ定義オブジェクト を使うべきです。filters - 対応する値は辞書で、そのそれぞれのキーがフィルタ id になり、それぞれの値が対応する Filter インスタンスをどのように環境設定するかを記述する辞書になります。
環境設定辞書は、(デフォルトが空文字列の) キー
name
を検索され、それらがlogging.Filter
インスタンスを構成するのに使われます。handlers - 対応する値は辞書で、そのそれぞれのキーがハンドラ id になり、それぞれの値が対応する Handler インスタンスをどのように環境設定するかを記述する辞書になります。
環境設定辞書は、以下のキーを検索されます:
class
(必須)。これはハンドラクラスの完全に修飾された名前です。level
(任意)。ハンドラのレベルです。formatter
(任意)。このハンドラへのフォーマッタの id です。filters
(任意)。このハンドラへのフィルタの id のリストです。
その他の すべての キーは、ハンドラのコンストラクタにキーワード引数として渡されます。例えば、以下のコード片が与えられたとすると:
handlers: console: class : logging.StreamHandler formatter: brief level : INFO filters: [allow_foo] stream : ext://sys.stdout file: class : logging.handlers.RotatingFileHandler formatter: precise filename: logconfig.log maxBytes: 1024 backupCount: 3
id が
console
であるハンドラが、sys.stdout
を根底のストリームにして、logging.StreamHandler
としてインスタンス化されます。id がfile
であるハンドラが、filename='logconfig.log', maxBytes=1024, backupCount=3
をキーワード引数にして、logging.handlers.RotatingFileHandler
としてインスタンス化されます。loggers - 対応する値は辞書で、そのそれぞれのキーがロガー名になり、それぞれの値が対応する Logger インスタンスをどのように環境設定するかを記述する辞書になります。
環境設定辞書は、以下のキーを検索されます:
level
(任意)。ロガーのレベルです。propagate
(任意)。ロガーの伝播の設定です。filters
(任意)。このロガーへのフィルタの id のリストです。handlers
(任意)。このロガーへのハンドラの id のリストです。
指定されたロガーは、指定されたレベル、伝播、ハンドラに従って環境設定されます。
root - これは、ルートロガーへの設定になります。この環境設定の進行は、
propagate
設定が適用されないことを除き、他のロガーと同じです。incremental - この環境設定が既存の環境設定に対する増分として解釈されるかどうかです。この値のデフォルトは
False
で、指定された環境設定は、既存のfileConfig()
API によって使われているのと同じ意味上で、既存の環境設定を置き換えます。指定された値が
True
なら、環境設定は 増分設定 の節で記述されているように進行します。disable_existing_loggers - 既存の非ルートロガーをすべて無効にするべきかどうかです。この設定は、
fileConfig()
における同じ名前のパラメータと同じです。設定されていなければ、このパラメータのデフォルトはTrue
です。この値は、 incremental がTrue
なら無視されます。
増分設定¶
増分設定に完全な柔軟性を提供するのは難しいです。例えば、フィルタやフォーマッタのようなオブジェクトは匿名なので、一旦環境設定がなされると、設定を拡張するときにそのような匿名オブジェクトを参照することができません。
さらに、一旦環境設定がなされた後、実行時にロガー、ハンドラ、フィルタ、フォーマッタのオブジェクトグラフを任意に変えなければならない例もありません。ロガーとハンドラの冗長性は、レベル (または、ロガーの場合には、伝播フラグ) を設定することによってのみ制御できます。安全な方法でオブジェクトグラフを任意に変えることは、マルチスレッド環境で問題となります。不可能ではないですが、その効用は実装に加えられる複雑さに見合いません。
従って、環境設定辞書の incremental
キーが与えられ、これが True
であるとき、システムは formatters
と filters
の項目を完全に無視し、handlers
の項目の level
設定と、loggers
と root
の項目の level
と propagate
設定のみを処理します。
環境設定辞書の値を使うことで、設定は pickle 化された辞書としてネットワークを通してソケットリスナに送ることができます。これにより、長時間起動するアプリケーションのロギングの冗長性を、アプリケーションを止めて再起動する必要なしに、いつでも変更することができます。
オブジェクトの接続¶
このスキーマは、ロギングオブジェクトの一揃い - ロガー、ハンドラ、フォーマッタ、フィルタ - について記述します。これらは、オブジェクトグラフ上でお互い接続されます。従って、このスキーマは、オブジェクト間の接続を表現しなければなりません。例えば、環境設定で、特定のロガーが特定のハンドラに取り付けられたとします。この議論では、ロガーとハンドラが、これら 2 つの接続のそれぞれ送信元と送信先であるといえます。もちろん、この設定オブジェクト中では、これはハンドラへの参照を保持しているロガーで表されます。設定辞書中で、これは次のようになされます。まず、送信先オブジェクトを曖昧さなく指定する id を与えます。そして、その id を送信元オブジェクトの環境設定で使い、送信元とその id をもつ送信先が接続されていることを示します。
ですから、例えば、以下の YAML のコード片を例にとると:
formatters:
brief:
# configuration for formatter with id 'brief' goes here
precise:
# configuration for formatter with id 'precise' goes here
handlers:
h1: #This is an id
# configuration of handler with id 'h1' goes here
formatter: brief
h2: #This is another id
# configuration of handler with id 'h2' goes here
formatter: precise
loggers:
foo.bar.baz:
# other configuration for logger 'foo.bar.baz'
handlers: [h1, h2]
(注釈: YAML がここで使われているのは、辞書の等価な Python 形式よりもこちらのほうが少し読みやすいからです。)
ロガーの id は、プログラム上でロガーへの参照を得るために使われるロガー名で、たとえば foo.bar.baz
です。フォーマッタとフィルタの id は、(上の brief
, precise
のような) 任意の文字列値にできます。これらは一時的なもので、環境設定辞書の処理にのみ意味があり、オブジェクト間の接続を決定するのに使われます。また、これらは設定の呼び出しが完了したとき、どこにも残りません。
上記のコード片は、foo.bar.baz
というの名ロガーに、ハンドラ id h1
と h2
で表される 2 つのハンドラを接続することを示します。h1
のフォーマッタは id brief
で記述されるもので、h2
のフォーマッタは id precise
で記述されるものです。
ユーザ定義オブジェクト¶
このスキーマは、ハンドラ、フィルタ、フォーマッタのための、ユーザ定義オブジェクトをサポートします。(ロガーは、異なるインスタンスに対して異なる型を持つ必要はないので、この環境設定スキーマは、ユーザ定義ロガークラスをサポートしていません。)
設定されるオブジェクトは、それらの設定を詳述する辞書によって記述されます。場所によっては、あるオブジェクトがどのようにインスタンス化されるかというコンテキストを、ロギングシステムが推測できます。しかし、ユーザ定義オブジェクトがインスタンス化されるとき、システムはどのようにこれを行うかを知りません。ユーザ定義オブジェクトのインスタンス化を完全に柔軟なものにするため、ユーザは 'ファクトリ' - 設定辞書を引数として呼ばれ、インスタンス化されたオブジェクトを返す呼び出し可能オブジェクト - を提供する必要があります。これは特殊キー '()'
で利用できる、ファクトリへの絶対インポートパスによって合図されます。ここに具体的な例を挙げます:
formatters:
brief:
format: '%(message)s'
default:
format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
datefmt: '%Y-%m-%d %H:%M:%S'
custom:
(): my.package.customFormatterFactory
bar: baz
spam: 99.9
answer: 42
上記の YAML コード片は 3 つのフォーマッタを定義します。 1 つ目は、id が brief
で、指定されたフォーマット文字列をもつ、標準 logging.Formatter
インスタンスです。 2 つ目は、id が default
で、長いフォーマットを持ち、時間フォーマットも定義していて、結果はその 2 つのフォーマット文字列で初期化された logging.Formatter
になります。Python ソース形式で見ると、 brief
と default
フォーマッタは、それぞれ設定の部分辞書:
{
'format' : '%(message)s'
}
および:
{
'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
'datefmt' : '%Y-%m-%d %H:%M:%S'
}
を持ち、これらの辞書が特殊キー '()'
を持たないので、インスタンス化はコンテキストから推測され、結果として標準の logging.Formatter
インスタンスが生成されます。id が custom
である、3 つ目のフォーマッタの設定をする部分辞書は:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42
}
で、ユーザ定義のインスタンス化が望まれることを示す特殊キー '()'
を含みます。この場合、指定された呼び出し可能ファクトリオブジェクトが使われます。これが実際の呼び出し可能オブジェクトであれば、それが直接使われます - そうではなく、(この例でのように) 文字列を指定したなら、実際の呼び出し可能オブジェクトは、通常のインポート機構を使って検索されます。その呼び出し可能オブジェクトは、環境設定の部分辞書の、残りの 要素をキーワード引数として呼ばれます。上記の例では、id が custom
のフォーマッタは、以下の呼び出しによって返されるものとみなされます:
my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)
警告
The values for keys such as bar
, spam
and answer
in
the above example should not be configuration dictionaries or references such
as cfg://foo
or ext://bar
, because they will not be processed by the
configuration machinery, but passed to the callable as-is.
キー '()'
が特殊キーとして使われるのは、キーワードパラメータ名として不正で、呼び出しに使われるキーワード引数と衝突し得ないからです。'()'
はまた、対応する値が呼び出し可能オブジェクトであると覚えやすくします。
特殊なキーワード '.'
を指定することもできます。この場合その値には属性名とその値のマッピングをあらわす辞書を指定します。指定された属性は、もしそれが見つかった場合、戻り値のユーザー定義オブジェクトに設定されます。したがって、以下のように設定すると:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42,
'.' {
'foo': 'bar',
'baz': 'bozz'
}
}
戻り値のフォーマッタは属性 foo
と``baz`` をもち、それぞれの値は 'bar'
と 'bozz'
に設定されます。
警告
The values for attributes such as foo
and baz
in
the above example should not be configuration dictionaries or references such
as cfg://foo
or ext://bar
, because they will not be processed by the
configuration machinery, but set as attribute values as-is.
Handler configuration order¶
Handlers are configured in alphabetical order of their keys, and a configured
handler replaces the configuration dictionary in (a working copy of) the
handlers
dictionary in the schema. If you use a construct such as
cfg://handlers.foo
, then initially handlers['foo']
points to the
configuration dictionary for the handler named foo
, and later (once that
handler has been configured) it points to the configured handler instance.
Thus, cfg://handlers.foo
could resolve to either a dictionary or a handler
instance. In general, it is wise to name handlers in a way such that dependent
handlers are configured _after_ any handlers they depend on; that allows
something like cfg://handlers.foo
to be used in configuring a handler that
depends on handler foo
. If that dependent handler were named bar
,
problems would result, because the configuration of bar
would be attempted
before that of foo
, and foo
would not yet have been configured.
However, if the dependent handler were named foobar
, it would be configured
after foo
, with the result that cfg://handlers.foo
would resolve to
configured handler foo
, and not its configuration dictionary.
外部オブジェクトへのアクセス¶
環境設定が、例えば sys.stderr
のような、設定の外部のオブジェクトへの参照を必要とすることがあります。設定辞書が Python コードで構成されていれば話は簡単ですが、これがテキストファイル (JSON, YAML 等) を通して提供されていると問題となります。テキストファイルでは、sys.stderr
をリテラル文字列 'sys.stderr'
と区別する標準の方法がありません。この区別を容易にするため、環境設定システムは、文字列中の特定の特殊接頭辞を見つけ、それらを特殊に扱います。例えば、リテラル文字列 'ext://sys.stderr'
が設定中の値として与えられたら、この ext://
は剥ぎ取られ、この値の残りが普通のインポート機構で処理されます。
このような接頭辞の処理は、プロトコルの処理と同じようになされます。どちらの機構も、正規表現 ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$
にマッチする接頭辞を検索し、それによって prefix
が認識されたなら、接頭辞に応じたやり方で suffix
が処理され、その処理の結果によって文字列値が置き換えられます。接頭辞が認識されなければ、その文字列値はそのまま残されます。
内部オブジェクトへのアクセス¶
外部オブジェクトと同様、環境設定内部のオブジェクトへのアクセスを必要とすることもあります。これは、その各オブジェクトを司る環境設定システムによって暗黙に行われます。例えば、ロガーやハンドラの level
に対する文字列値 'DEBUG'
は、自動的に値 logging.DEBUG
に変換されますし、handlers
, filters
および formatter
の項目は、オブジェクト id を取って、適切な送信先オブジェクトを決定します。
しかし、ユーザ定義モジュールには、 logging
モジュールには分からないような、より一般的な機構が必要です。例えば、 logging.handlers.MemoryHandler
があって、委譲する先の別のハンドラである target
引数を取るとします。システムはこのクラスをすでに知っていますから、設定中で、与えられた target
は関連するターゲットハンドラのオブジェクト id でさえあればよく、システムはその id からハンドラを決定します。しかし、ユーザが my.package.MyHandler
を定義して、それが alternate
ハンドラを持つなら、設定システムは alternate
がハンドラを参照していることを知りません。これを知らせるのに、一般的な解析システムで、ユーザはこのように指定できます:
handlers:
file:
# configuration of file handler goes here
custom:
(): my.package.MyHandler
alternate: cfg://handlers.file
リテラル文字列 'cfg://handlers.file'
は、ext://
接頭辞が付いた文字列と同じように分析されますが、インポート名前空間ではなく、環境設定自体が検索されます。この機構は str.format
でできるのと同じようにドットやインデックスのアクセスができます。従って、環境設定において以下のコード片が与えられれば:
handlers:
email:
class: logging.handlers.SMTPHandler
mailhost: localhost
fromaddr: my_app@domain.tld
toaddrs:
- support_team@domain.tld
- dev_team@domain.tld
subject: Houston, we have a problem.
文字列 'cfg://handlers'
は、キー handlers
をもつ辞書であると分析され、文字列 'cfg://handlers.email'
は、handlers
辞書内の、email
キーをもつ辞書であると分析されます。文字列 'cfg://handlers.email.toaddrs[1]
は、'dev_team@domain.tld'
と分析され、'cfg://handlers.email.toaddrs[0]'
は値 'support_team@domain.tld'
と分析されます。subject
の値には、'cfg://handlers.email.subject'
または等価な 'cfg://handlers.email[subject]'
でアクセスできます。後者が必要なのは、キーがスペースや非アルファベット文字を含むときのみです。インデックス値が十進数字のみで構成されているなら、まず対応する整数値を使ってアクセスが試みられ、必要なら文字列値で代替します。
文字列 cfg://handlers.myhandler.mykey.123
が与えられると、これは config_dict['handlers']['myhandler']['mykey']['123']
と分析されます。文字列が cfg://handlers.myhandler.mykey[123]
と指定されたら、システムは config_dict['handlers']['myhandler']['mykey'][123]
から値を引き出そうとし、失敗したら config_dict['handlers']['myhandler']['mykey']['123']
で代替します。
インポート解決とカスタムインポーター¶
インポート解決は、デフォルトではインポートを行うために __import__()
組み込み関数を使用します。これを独自のインポートメカニズムに置き換えたいと思うかもしれません: もしそうなら、 DictConfigurator
あるいはその上位クラスである BaseConfigurator
クラスの importer
属性を置換することができます。ただし、この関数はクラスからディスクリプタ経由でアクセスされる点に注意する必要があります。インポートを行うために Python callable を使用していて、それをインスタンスレベルではなくクラスレベルで定義したければ、 staticmethod()
でそれをラップする必要があります。例えば:
from importlib import import_module
from logging.config import BaseConfigurator
BaseConfigurator.importer = staticmethod(import_module)
configurator インスタンス に対してインポート callable をセットする場合は、 staticmethod()
でラップする必要はありません。
環境設定ファイルの書式¶
fileConfig()
が解釈できる環境設定ファイルの形式は、 configparser
の機能に基づいています。ファイルには、 [loggers]
, [handlers]
, [formatters]
といったセクションが入っていなければならず、各セクションではファイル中で定義されている各タイプのエンティティを名前で指定しています。こうしたエンティティの各々について、そのエンティティをどう設定するかを示した個別のセクションがあります。すなわち、 log01
という名前の [loggers]
セクションにあるロガーに対しては、対応する詳細設定がセクション [logger_log01]
に収められています。同様に、 hand01
という名前の [handlers]
セクションにあるハンドラは [handler_hand01]
と呼ばれるセクションに設定をもつことになり、 [formatters]
セクションにある form01
は [formatter_form01]
というセクションで設定が指定されています。ルートロガーの設定は [logger_root]
と呼ばれるセクションで指定されていなければなりません。
注釈
fileConfig()
API は dictConfig()
API よりも古く、ロギングのある種の側面についてカバーする機能に欠けています。たとえば fileConfig()
では数値レベルを超えたメッセージを単に拾うフィルタリングを行う Filter
オブジェクトを構成出来ません。 Filter
のインスタンスをロギングの設定において持つ必要があるならば、 dictConfig()
を使う必要があるでしょう。設定の機能における将来の拡張は dictConfig()
に対して行われることに注意してください。ですから、そうするのが便利であるときに新しい API に乗り換えるのは良い考えです。
ファイルにおけるこれらのセクションの例を以下に示します。
[loggers]
keys=root,log02,log03,log04,log05,log06,log07
[handlers]
keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
[formatters]
keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
ルートロガーでは、レベルとハンドラのリストを指定しなければなりません。ルートロガーのセクションの例を以下に示します。
[logger_root]
level=NOTSET
handlers=hand01
level
エントリは DEBUG, INFO, WARNING, ERROR, CRITICAL
のうちの一つか、 NOTSET
になります。ルートロガーの場合にのみ、 NOTSET
はすべてのメッセージがログ記録されることを意味します。レベル値は logging
パッケージの名前空間のコンテキストにおいて eval()
されます。
handlers
エントリはコンマで区切られたハンドラ名からなるリストで、[handlers]
セクションになくてはなりません。また、これらの各ハンドラの名前に対応するセクションが設定ファイルに存在しなければなりません。
ルートロガー以外のロガーでは、いくつか追加の情報が必要になります。これは以下の例のように表されます。
[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser
level
および handlers
エントリはルートロガーのエントリと同様に解釈されますが、非ルートロガーのレベルが NOTSET
に指定された場合、ロギングシステムはロガー階層のより上位のロガーにロガーの実効レベルを問い合わせるところが違います。propagate
エントリは、メッセージをロガー階層におけるこのロガーの上位のハンドラに伝播させることを示す 1 に設定されるか、メッセージを階層の上位に伝播 しない ことを示す 0 に設定されます。qualname
エントリはロガーのチャネル名を階層的に表したもの、すなわちアプリケーションがこのロガーを取得する際に使う名前になります。
ハンドラの環境設定を指定しているセクションは以下の例のようになります。
[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)
class
エントリはハンドラのクラス (logging
パッケージの名前空間において eval()
で決定されます) を示します。 level
はロガーの場合と同じように解釈され、 NOTSET
は "すべてを記録する (log everything)" と解釈されます。
formatter
エントリはこのハンドラのフォーマッタに対するキー名を表します。空文字列の場合、デフォルトのフォーマッタ (logging._defaultFormatter
) が使われます。名前が指定されている場合、その名前は [formatters]
セクションになくてはならず、対応するセクションが設定ファイル中になければなりません。
args
エントリは、 logging
パッケージの名前空間のコンテキストで eval()
される際、ハンドラクラスのコンストラクタに対する引数からなるリストになります。典型的なエントリがどうやって作成されるかについては、対応するハンドラのコンストラクタか、以下の例を参照してください。もし指定しなかった場合にはデフォルトは ()
となります。
オプションの kwargs
エントリーは、 eval()
が logging
パッケージの名前空間のコンテキストで利用された時に、ハンドラークラスのコンストラクタに渡されるキーワード引数辞書となります。指定されなかったときのデフォルトは {}
です。
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')
[handler_hand03]
class=handlers.SocketHandler
level=INFO
formatter=form03
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
[handler_hand04]
class=handlers.DatagramHandler
level=WARN
formatter=form04
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
[handler_hand05]
class=handlers.SysLogHandler
level=ERROR
formatter=form05
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
[handler_hand06]
class=handlers.NTEventLogHandler
level=CRITICAL
formatter=form06
args=('Python Application', '', 'Application')
[handler_hand07]
class=handlers.SMTPHandler
level=WARN
formatter=form07
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
kwargs={'timeout': 10.0}
[handler_hand08]
class=handlers.MemoryHandler
level=NOTSET
formatter=form08
target=
args=(10, ERROR)
[handler_hand09]
class=handlers.HTTPHandler
level=NOTSET
formatter=form09
args=('localhost:9022', '/log', 'GET')
kwargs={'secure': True}
フォーマッタの環境設定を指定しているセクションは以下のような形式です。
[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s
datefmt=
style=%
validate=True
class=logging.Formatter
フォーマッターのセクション の辞書スキーマと同じキーを持つ、フォーマッター設定の引数です。
注釈
eval()
を使用していることで、上述のようにソケット経由で設定を送受信するために listen()
を使用していることに起因する潜在的なセキュリティリスクがあります。そのリスクは、相互に信頼できない多数のユーザが同じマシン上でコードを実行する場合に制限されています; 詳細は listen()
ドキュメンテーションを参照してください。
参考
logging
モジュールlogging モジュールの API リファレンス。
logging.handlers
モジュールlogging モジュールに含まれる、便利なハンドラです。