ライブラリ vs アプリケーション: 根本的に異なるロギング要件
- アプリケーションのロギング: 開発者が直接制御する環境で、明示的に設定・管理される
- ライブラリのロギング: 他者のプロジェクトに組み込まれるため、ユーザー環境と選択権を尊重する必要がある
- 既存方式の限界: アプリケーション中心のロガー(winston、Pino)をライブラリに適用すると、強制性の問題が生じる
- ライブラリ作者のジレンマ: デバッグ情報を提供したい一方で、ユーザーに負担をかけたくない
現在のライブラリロギングの問題点
- 断片化したロギングエコシステム: Express は
DEBUG=express:*、Mongoose は mongoose.set('debug', true) のように、それぞれ異なる方式を使っている
- 依存関係のジレンマ: winston や Pino のようなアプリケーション中心ライブラリを使うと、ユーザーに望まない依存関係や設定を強いることになる
- 沈黙 vs 強制: ロギングを完全に諦めるか、ユーザーにロギング方式を強制するかという両極端な選択肢
- 依存性注入の複雑さ: より洗練されたアプローチではあるが、API の複雑さが増し、ユーザー負担も重くなる
LogTape の「ライブラリ優先」哲学
- 条件付き有効化: ロギングが設定されていなければ完全に無動作、設定されれば統合的に管理される
- ユーザーの選択権を保証: ライブラリがロギング方式を強制せず、ユーザーが望むときだけ有効化できる
- ゼロ依存: 5.3KB のサイズで、サプライチェーンのセキュリティリスクを排除し、バージョン衝突を防ぐ
- ESM/CJS 完全対応: 互換性チェーンの問題を解決し、tree shaking によるバンドル最適化も可能
実用的な利点
- 性能最適化: 無効時はほぼゼロオーバーヘッド、有効時は優れたコンソール出力性能を発揮
- 名前空間の分離:
["my-lib", "feature"] 形式の階層的カテゴリにより衝突を防ぐ
- TypeScript 優先設計: 追加の型パッケージなしで完全な型安全性を提供
- 既存システムとのブリッジ: winston、Pino アダプターによって段階的な導入を支援
現実的な考慮事項
- アダプターの意味: まだエコシステム標準ではないという現実を認めたうえでの、実用的な妥協策
- Python エコシステムからの着想: 標準
logging ライブラリによって統合された Python の成功事例を参照
- 未来志向のアプローチ: ライブラリエコシステムを段階的に改善していくための一つの選択肢として提示
7件のコメント
設定していないときに無動作だという点が、いまいちよく理解できません。
getLoggerの時点ですでにロガーを生成していて、debugを出力すれば動作しているわけですから。私がコードを見た限りでは、ただ動作していないように見せているだけで、
文字列演算を遅延させているわけでもないので、
結局のところ、ログレベルを設定すると出力しない他のライブラリと、無動作がどう違うのかよく分かりません
あれ、
configure()/configureSync()を呼び出していないのにログが出力されるんですか? どこに出力されるんですか? コンソール画面に表示されるんですか?ああ、ここで言う「動作する」というのは、
consoleやファイルにログが保存されることを意味しているのではなく、関数が実行されて実質的なオーバーヘッドがあるかどうか、という話をしていたのです。誤解を招きそうですね
もちろん、ロガーの主なオーバーヘッドが system call であることを踏まえると、オーバーヘッドがないとは言えませんが、
それが他のロガーとの差別化要素なのか?と言われると、他のロガーも同じように動作するため、そうではないということです
ああ、そういう意味だったのですね。ひとまず、null output を基準にベンチマークを回してみたところ、オーバーヘッドはほとんどないと見てよさそうでした。ですが、性能面でのオーバーヘッドよりもさらに重要だと思ったのは、デフォルトの動作が no-op かどうかという点でした。ライブラリ作者の立場としては、ライブラリ内でログを出力するとしても、そのライブラリを使うアプリケーションの実行時に、勝手にコンソールやファイルへログが出力されてしまうと困るからです。
ああ、SHOW GNだったんですね。
最近のエコシステムでは、ロガーを外部から注入する形を採ることが多いので、あまり共感できなかった部分もあった気がします。
設定されていなければ、当然動作しませんからね。
それでも、これまでそのエコシステムにはなかったロガーインターフェースでもありますし、自由度が高いぶん、より良いように思います。
いただいたベンチマーク基準の場合、system call を除外して null output を出力しているため、
この点については内部ロガーの形式によって確かに変わりうると思います。
この点では、Pino と最大で3倍の差が出るんですね。うーん。
FYI: さらに、私が申し上げていた外部から注入されるロガーの形は、Openai Node sdk を見るだけでも、ロガーを外部から注入して出力する形になっているので、簡単に確認できると思います。
https://github.com/dahlia/logtape/…