ActiveSupport に独立したログレベルを持つ ProxyLogger を実装
ActiveSupport に ProxyLogger が追加され、既存ロガーへ透過的にログを転送しながら、プロキシ側で別個の severity レベルを制御できるようになりました。これにより、外部ライブラリが大量出力する場合でも、アプリ全体のロガー設定を変えずに抑制が可能です。
背景
Rails アプリケーションでは Rails.logger が標準のロギング入口となりますが、サードパーティのライブラリが独自に Logger インスタンスを保持しているケースがあります。そのまま利用すると、ライブラリ側のデフォルトレベル(多くは DEBUG)で大量ログが出力され、実運用での可視性が低下します。PR #57931 は、同一ロガーを共有しつつレベルだけを個別に設定できる 手段として ProxyLogger を導入しています。
技術的な変更
ProxyLogger の実装 は activesupport/lib/active_support/proxy_logger.rb に新規追加されました。主要なポイントは次の通りです。
-
initialize(logger, level = ::Logger::DEBUG)で内部ロガーと独立レベルを保持し、::Logger::Severity.coerceによりシンボル・文字列・整数のいずれも受け取ります。 -
levelアクセサとlevel=セッターを提供し、自ロガーのレベルだけを変更 できるインターフェイスを実装しました。 -
LoggerSilenceと::Logger::Severityを mixin し、標準 Logger が持つdebug?,info?などの判定メソッドをそのまま使用可能です。 -
closeとreopenにより、内部ロガーの切り替えや無効化が可能です。close後はログが無視され、reopenで再度出力できます。
class ProxyLogger
include LoggerSilence
include ::Logger::Severity
def initialize(logger, level = ::Logger::DEBUG)
@logger = logger
@level = ::Logger::Severity.coerce(level)
end
attr_reader :level
def level=(severity)
@level = ::Logger::Severity.coerce(severity)
end
def close
@logger = nil
end
def reopen(logger)
@logger = logger
end
# ... (各種 delegator が省略されているが、Logger インターフェイスをほぼすべて実装)
end
autoload の追加 により、ActiveSupport がロードされた段階で ProxyLogger が自動的に利用可能になります。activesupport/lib/active_support.rb に次の行が挿入されました。
autoload :ProxyLogger
テスト は activesupport/test/proxy_logger_test.rb に実装され、独立レベルの動作、元ロガー側レベル変更時の挙動、close/reopen の機能、全 delegator メソッドの正常動作を検証しています。
def test_own_level_interface
@real_logger.debug("REAL-1")
@logger.debug("PROXY-1")
@logger.level = :error
@real_logger.debug("REAL-2")
@logger.debug("PROXY-2")
assert_equal %w(REAL-1 PROXY-1 REAL-2), @io.string.split("\n")
end
設計判断
この PR では 既存キーの拡張 という設計方針が取られました。ActiveSupport の他コンポーネントは autoload で遅延ロードを行うため、新クラスを同様に autoload で提供し、名前空間の一貫性を保ちつつロードコストを増加させませんでした。さらに、LoggerSilence を mixin することで、ActiveSupport::Logger と同様のサイレント機構がそのまま利用でき、コードベース全体への影響を最小限に抑えています。
別途 ActiveSupport::LoggerThreadSafeLevel の削除が行われていますが、ProxyLogger はスレッド安全性を直接扱わず、純粋にレベルと転送のロジックだけに集中 することでシンプルさを追求しました。この選択は、ProxyLogger が補助的なユーティリティであり、単体テストで十分にカバーできることを前提にしています。
まとめ
ActiveSupport::ProxyLogger の導入により、アプリ全体のロガー設定を変更せずに外部ライブラリのログ出力量を抑制できる手段が提供されました。独立した severity レベル、close/reopen によるロガー切り替え、そして標準 Logger インターフェイスのほぼ完全な委譲という設計は、既存コードとの互換性と使い勝手の両立を実現しています。