カスタムロガーでログ出力を拡張し、デバッグ設定を置き換える

hotwired/hotwire-native-android

Hotwire Native は従来の Logcat 直出力と単一の debugLoggingEnabled スイッチから、プラグイン可能なロガーシステムへと移行し、アプリ側でログの取得・フィルタリング・転送が可能になりました。

背景

従来 Hotwire は Android の Logcat に直接ログを書き込み、デバッグ出力はブール値 debugLoggingEnabled でオンオフを切り替えるだけでした。これにより、アプリがライブラリのログをキャプチャして独自のロギングフレームワークやクラッシュレポートに流す手段がなく、ログの粒度調整も不可能でした。結果として、デバッグ情報の取得が制限され、運用上の可観測性が低下していました。

技術的な変更

HotwireLogger インターフェースと HotwireLogLevel 列挙型が新規追加され、ログレベルで出力を制御できる汎用的なロギング API が提供されました。

interface HotwireLogger {
    var logLevel: HotwireLogLevel
    fun v(tag: String, msg: () -> String)
    fun d(tag: String, msg: () -> String)
    fun i(tag: String, msg: () -> String)
    fun w(tag: String, msg: () -> String)
    fun e(tag: String, throwable: Throwable?, msg: () -> String)
}

DefaultHotwireLogger が実装として追加され、Logcat へ出力しつつ logLevel に応じてメッセージをフィルタリングします。レイジー評価 (() -> String) により不要な文字列生成が回避されます。

internal object DefaultHotwireLogger : HotwireLogger {
    override var logLevel = HotwireLogLevel.NONE
    override fun v(tag: String, msg: () -> String) { if (logLevel.priority <= HotwireLogLevel.VERBOSE.priority) Log.v(tag, msg()) }
    override fun d(tag: String, msg: () -> String) { if (logLevel.priority <= HotwireLogLevel.DEBUG.priority)   Log.d(tag, msg()) }
    // i, w, e ... 同様に実装
}

HotwireConfiglogger: HotwireLogger プロパティが導入され、従来の debugLoggingEnabled が削除されました。デフォルトは DefaultHotwireLogger です。

var logger: HotwireLogger = DefaultHotwireLogger
// 旧: var debugLoggingEnabled = false

コアとナビゲーションのロガー実装 (CoreLog.kt, NavigationLog.kt) が Hotwire.config.logger 経由に置き換えられ、logEvent 系メソッドは logDebug·logVerbose へ統一されました。HTTP 通信のログは HotwireHttpLoggerOkHttp のインターセプタに注入され、常時有効化されます。

internal class HotwireHttpLogger : HttpLoggingInterceptor.Logger {
    override fun log(message: String) { Hotwire.config.logger.d(DEFAULT_TAG) { message } }
}

コードベース全体で logEventlogDebug / logVerbose への置換が行われ、各コンポーネントは同一インターフェース経由でログを出力します。これにより、ロギングロジックが一元化され、設定変更が全体に波及します。

設計判断

logger プロパティを単一化し、旧来のブールフラグを廃止した判断は、設定 API のシンプルさと拡張性を両立させる狙いがありました。デフォルト実装を保持しつつ、アプリ側で任意のロガーを注入できるため、後方互換性が保たれています。

インターフェースを介した依存性注入は、クリーンアーキテクチャの原則に沿い、テストやモジュール分離を容易にします。デモアプリの DemoApplication.kt ではビルドタイプに応じて Hotwire.config.logger.logLevel を設定し、実際の利用方法が示されています。

HotwireLogLevel とラムダベースのメッセージ提供は、ログレベル制御とオーバーヘッド削減という二つの設計目標を同時に満たす選択です。ログレベルが NONE のときは全ての出力が抑制され、パフォーマンスに影響しません。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
9bf33347

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ⚠ WARNING

Title, Context, Technical Detailの存在と明確さ

リード文・背景・技術的変更は揃っているが、記事末尾にまとめ(結論)セクションがなく、リード文の繰り返しでもないため、結論が欠落していると判断した。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックのファイル名付きハイライトは正しい形式だが、PRリンクが "[PR #159](URL)" となっており、要求された "[#159](URL)" 形式と微妙に異なる。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門エンジニア向けの深い技術解説が中心で、過度な初心者向け説明は見られない。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論→結論の構成を概ね保ち、段落はトピックセンテンスで始まり、1段落1トピック、長さも適切に区切られている。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffに含まれる変更と一致しており、抜粋・省略も内容理解に支障なし。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語はPRで使用されているものと一致し、誤用や不適切な表現は見受けられない。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な主張はPRやDiffで裏付けられ、論理的に正確である。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の全ての主張はPRの説明・Diffのコードと一致し、根拠のない推測や外部知識の付加はない。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #159、クラス名・ファイルパスなど数値・固有名詞は正確に記載されている。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの趣旨(カスタムロガー提供)を日本語で適切に表現している。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事内にPRに無関係なバージョン情報やリリース予定等の外部知識は含まれていない。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PRの記述と合致している。