Python学習【365日チャレンジ!】128日目のマスターU(@Udemy11)です。
3日続けてキングダムの話題になりますが、キングダムにハマってから、秦の始皇帝に対するイメージがかなり変わってきました。
というのも、中国の歴史で一番最初に興味を持ったのが、司馬遼太郎の【項羽と劉邦】だったので、始皇帝は悪政の限りを尽くし、人民を苦しめていたと理解していたからです。
国の支配者もいろいろな側面があるので、一つの側面からしか見れていなかったような気がしています。
キングダムは基本的に史実に基づいてストーリーが進んでいくので(歴史の流れ以外はフィクションだけど)、実際の歴史を学習しながら、こことここは違うなとか、この人物はこんな功績を上げたのかということを学習しながら読めるので、ほんとハマるし、歴史の勉強にもなるんですよね。
ほんと知らなかったことを知るというのは楽しいですね。
それでは、今日もPython学習をはじめましょう!
昨日の復習
昨日は、ロギングのフィルタを使ってログの出力をコントロールする方法について学習しました。
パスワードなどの情報を間違ってログに出力しないようにするためのフィルタがロギングフィルタでした。
プログラムが大きくなってくるとそんな間違いを犯してしまうことがあるのかと疑問に思う反面、そこまでしっかりとフォローしてプログラムを書かないといけないんだなと感じました。
そんなロギングフィルタの使い方についてはこちらの記事をごらんください。
今日は、ロギングの設定をまとめられるロギングコンフィグを学習します。
ロギングコンフィグ
コンフィグは、【configration(コンフィグレーション)】の略で、日本語だと【設定】となります。
つまり、ロギングコンフィグは、ロギングの設定ということです。
これまでの学習で、ロガーを個別に生成して、それぞれのレベルや名前、出力する属性などを指定してログを出力していましたが、必要な設定をすべて一つにまとめて置くことでコードが非常にシンプルになります。
MVCモデルでのアプリ開発同様に、必要なものをまとめることでわかりやすくきれいなコードが書けるということですね。
basicConfig
を使ってロギングのレベルを指定したり、出力するファイルを指定したりできましたが、今回は、コンフィグの設定を記述したファイルやコードをまとめる役割を持つfileConfig
とdictConfig
について学びましょう。
fileConfig
fileConfig
は、その名のとおり、ファイルに設定を書き込んだもので、その設定ファイルを読み込んで使うことができます。
設定するファイルはconfigparser形式で書く必要があり、一例として、次のように書くことができます。
[loggers]
keys=root,testLogger
[handlers]
keys=streamHandler
[formatters]
keys=formatter
[logger_root]
level=WARNING
handlers=streamHandler
[logger_testLogger]
level=DEBUG
handlers=streamHandler
propagate=0
qualname=testLogger
[handler_streamHandler]
class=StreamHandler
level=DEBUG
formatter=formatter
args=(sys.stderr,)
[formatter_formatter]
format=%(asctime)s %(name)-10s %(levelname)-8s %(message)s
詳しい環境設定ファイルの書式はこちらのPython公式ドキュメントをごらんください。
[loggers]
,[handlers]
,[formatters]
の3つは必須のセクションです。
これらのセクションで指定したkeys
に対応する詳細セクションの記載も必要で、[logger_root]
には、level
とhandlers
を指定する必要があります。
ルートロガー以外のロガー(今回の設定では[logger_testLogger]
)セクションには、次の4つの値を指定します。
- level
- handlers
- propagate
- qualname
propagate
は、上位ロガーにも反映する1
かこのロガーだけの値にする0
に指定し、qualname
は、このロガーを使うための名前(今回はtestLogger
)になります。
次のhandler
のセクション([handler_streamHandler]
)には、一例として次の4つの値を指定しています。
- class
- level
- formatter
- args
class
は、ハンドラのクラス(今回はStreamHandler
)を指定し、level
は、ルートロガーの場合はルートが優先されます。
formatter
で指定した名前(formatter
)は、26行目の[formatter_formatter]
で使われ、27行目でフォーマットを指定しています。
args
には、write
メソッドを持った標準エラーを出力するファイルオブジェクトsys.stderr
を指定しています。
最後の27行目のformat
の指定で-12
や-8
が入っているのは、取得するname
やlevelname
の最長のlength
を指定し、属性出力の見た目を揃えるためです。
例えばname
は、root
かtestLogger
になるので、最長のlength
は10
なので、%(name)-10s
にしていて、%(levelname)-8s
はCRITICAL
が最長の8
ということです。
fileConfigを使ったログ出力
上記のconfig.ini
を使ってログ出力をしてみます。
まずは次のコードです。
import logging.config
logging.config.fileConfig('config.ini')
logger = logging.getLogger(__name__)
logger.debug('debug test')
logger.info('info test')
logger.warning('warning test')
logger.error('error test')
logger.critical('critical test')
出力結果
2020-06-17 22:39:23,562 __main__ WARNING warning test
2020-06-17 22:39:23,562 __main__ ERROR error test
2020-06-17 22:39:23,562 __main__ CRITICAL critical test
ロガーが__main__
、つまりroot
になるので、config.ini
の[logger_root]
で指定されているレベルWARNING
までしか出力されません。
続いて5行目だけ次のように__name__
をtestLogger
に変えてみます。
logger = logging.getLogger('testLogger')
出力結果
2020-06-17 22:42:38,329 testLogger DEBUG debug test
2020-06-17 22:42:38,329 testLogger INFO info test
2020-06-17 22:42:38,329 testLogger WARNING warning test
2020-06-17 22:42:38,329 testLogger ERROR error test
2020-06-17 22:42:38,329 testLogger CRITICAL critical test
生成されるロガーの名前がtestLogger
になるので、config.ini
の[logger_testLogger]
で指定されているレベルであるDEBUG
まで出力されています。
ロギングの設定を外部ファイルに切り分けることで、メインのコードをスッキリできることが理解できたかと思います。
次に、この設定をまとめて実行ファイルに記述するdictConfig
を学習しましょう。
dictConfig
fileConfig
同様に設定をまとめることができ、外部設定ファイルではなく、dict
型でPythonファイルに直接記述することができます。
実際のコードをみてみましょう。
import logging.config
logging.config.dictConfig({
'version': 1,
'formatters': {
'testFormatter':{
'format': '%(asctime)s %(name)-10s %(levelname)-8s %(message)s'}
},
'handlers': {
'testHandlers': {
'class': 'logging.StreamHandler',
'formatter': 'testFormatter',
'level': logging.DEBUG
}
},
'root': {
'handlers': ['testHandlers'],
'level': logging.WARNING
},
'loggers': {
'testLogger': {
'handlers': ['testHandlers'],
'level': logging.DEBUG,
'propagate': 0
}
}
})
logger = logging.getLogger(__name__)
logger.debug('debug test')
logger.info('info test')
logger.warning('warning test')
logger.error('error test')
logger.critical('critical test')
fileConfig
と比べると指定する値が減っているような感じです。
dictConfig
でロギング設定をするには、環境設定辞書スキーマに従った記述でキーを設定する必要があります。
今回設定しているキーは、
- version
- formatters
- handlers
- root
- loggers
の5つです。
必須のキーはversion
だけで、現状で指定できるのは1
だけです。
formatters
で、生成するインスタンス名をtestFormatter
に指定し、format
メソッドに、属性を指定しています。
handlers
では、生成するインスタンス名をtestHandlers
とし、クラスをStreamHandler
、formatter
に先に設定しているtestFormatter
、level
にDEBUG
を指定しています。
root
には、handler
とlevel
を指定しています。
testHandler
が指定されていて、そちらのlevel
はDEBUG
ですが、root
で指定しているレベルのWARNING
が優先されます。
最後のloggers
は、testLogger
がロガー名になり、次の4つのキーを指定することができます。
- level
- handlers
- filters
- propagate
今回は、filter
を指定せずに、3つのキーを指定していますが、これらのキーは必須ではなく、任意で指定することができます。
dictConfigのログ出力
fileConfig
のログ出力同様に、30行目の__name__
でログ出力をすると17行目から20行目で設定したWARNING
レベルまでが出力されます。
30行目の__name__
を21行目から27行目で設定しているtestLogger
に変更すると、レベルはDEBUG
になるので、32行目から36行目のログが出力されます。
dictConfigのほうが使われる?
fileConfig
とdictConfig
を学習してきましたが、よく使われているのはdictConfig
の方だそうです。
これは、Webアプリケーションなどの開発で、dictConfig
を使って、setting.py
などの設定ファイルを作ってインポートする使い方が主流となっているためのようです。
最初はちんぷんかんぷん
コンフィグに関するコードを見るとちょっとモチベーションがさがっちゃうんですよね。
一つ一つのコードを読み解きながら理解しないといけないので、めっちゃ時間がかかるんです。
ある程度コードを読み解いてきたとはいえ、わからないコードがたくさん出てくるので、最初はまったくもってちんぷんかんぷんで、レクチャーを受講したあとは、Pythonの公式ドキュメントやWeb上の記事とにらめっこしながら理解しなければなりません。
ほんと根気が必要なんですよね。
わからないことをすぐに答えてくれる人が近くにいると、すぐに問題は解決するんでしょうけど、それだと十分に理解できていないまま次に進むことになります。
自分で右往左往しながらきっちりと理解して、ちょっとずつ進んでいかないとなかなか自分のものにはできません。
今回のConfig
についても、カバーできていないセクションやキーがありますが、公式ドキュメントを読めば理解できるということがわかったので、実践しながらスキルを磨いていこうと思っています。
ということで、今日はこのへんで終了します。
それでは明日も、Good Python!