ログAPI構想
基本的な考え
「ログをどう取りたいか」という問題はあるが、少なくともログの名前(カテゴリ)と、ログとしてデータを出力する意思が見えればよいはずである。
API とはその意思がインターフェースとして現れたらそれでおしまいのはずである。
ロガーのインスタンスをカテゴリごとに分けるべきか?
カテゴリを引数にすると、カテゴリの辞書検索処理が必ず発生する。これはコストがとても高い。
カテゴリごとにロガーのインスタンスを分けた方が無難。
ロガーが固定化される問題がある。
依存性注入を使えばいいはず。
「ログを取らない」という意思がある場合、ログ用データを加工する処理はスキップしたい。
取るか取らないかを単なる2値フラグで扱うよりは、ログレベルで扱う方がよい。
ログレベルは数値にするのがよい。判定が少なくて済む。
ログを出力するところは、可能な限り加工を避けるようにするのが望ましい。
見栄えのために同じような加工が必要なのであれば、ログの出力段で行うべきでプログラムはデータを渡すだけにすべき。
モジュールごとに制御したい場合はどうするか?
ロガー作成時、または、ログ出力時に、モジュール情報を取り出せるか?
スタックトレースから取り出せる場合
プリプロセッサマクロで取り出せる場合
ログは管理者が見る物で、ユーザーが見るものではない。いわゆる「ユーザーインターフェース」として考えてはならない。
翻訳して母国語で出すなどの配慮は無駄な努力である。
検索して見つけやすいのは結局英語である。
あくまで自社向けであれば母国語で書くだけで良い。翻訳はほとんどの場合不要。
汎用モジュールにするならば英語一択になる。
安全に出せるメッセージは ASCII 範囲というのがよくある。
ログはログを出そうとしたところが、出したい内容を最も良く知っているはずである。
呼び出し側は呼び出し側の内部情報を持っていて、呼び出された側は呼び出された側の内部情報を持っている。
ということは、両方で出さないと状況が分からない。
しかし、基本的なルーチンでは、ログよりはエラー情報を呼び出し元に返すべき。
それが本当にエラーなのかを判断するのは、アプリケーションの仕事である。
ログの処理過程は以下のようになる
ログの初期設定の読み出し
ロガーの生成(ロガーによる出力が必要なクラスで呼び出す)
ログ出力の要否判別(ログレベルによるフィルタ)
ログ出力データの収集
ログ出力
出力されたログの取捨選別(ログ内容によるフィルタ)
filter とよく呼ばれる
filter-formatter-appender はつなげられるようにしたい。
特に appender に強く依存する。この全体を appender と考える方法もある。
不要なログの除去
既知の不要なログの除去
同じメッセージの大量発生の除去
ログのフォーマット
formatter とよく呼ばれる
ログの実出力(画面出力やファイル出力や別のログ出力機能への転送)
appender, transporter とよく呼ばれる
出力と共に外部への何らかのトリガーを行ってもよい。(logwatch など)
code:pseudo
// ロガーはカテゴリごとに作る。
mylogger = new Logger("mylog");
// 何も付けない、あるいは空文字列だとデフォルトロガーになる。特にカテゴリを気にせず使うならデフォルトロガーを使う。
logger = new Logger();
code:pseudo
ログの設定はどうなっているのが望ましいのか?
JSON ファイルで書いてあると、読み込みが楽。
ログの設定はいつ誰がどうやって読み込むのか?
ワークディレクトリから、パッケージ名.conf で?
設定の読み出しは直接行わず、オブジェクトの読み込みのみ?
モジュールを読み出すとしたら、どうすべき?
ES2015 で動的 import も存在するが、Promise となることに注意。(出力順が保証されない。)
どうしてまともなログAPIがないのか?
ログ出力が重要と捉えられていない。オマケと考えられている。
ログ出力は「メッセージを出力するもの」と思い込まれている。
実際には状況を確認するために付加情報がとても重要だが、そこが考えられていない。
ログを取り過ぎると負荷が大きくなるため、実用的ではないと考えられている。