Query Log Tagsにクエリ本文を渡せるように変更
query_log_tagsのコンテキストにSQL文字列が追加され、クエリの内容に応じた動的なタグ付けが可能になりました。これにより、SQLクエリの特性に基づいた詳細なデバッグ情報の付与が実現します。
背景
本番環境でSQLクエリがデータベースレプリカにヒットしない問題をデバッグする際、既存のバックトレース行だけでは情報が不足していました。ActiveSupport::Notifications.subscribe("sql.active_record")を使ったカスタムロジックでも解決可能ですが、設定ベースのアプローチの方がシンプルです。#56683は、クエリログタグの仕組みにSQL文字列を渡すことで、この課題を解決しています。
クエリの内容に応じて異なるデバッグ情報を付与したいというニーズは、レプリカ振り分けのデバッグ以外にも、クエリの複雑さやパフォーマンス特性の分析など、幅広いユースケースに応用できます。
技術的な変更
コンテキストへのSQL追加が主要な変更です。activerecord/lib/active_record/query_logs.rbのcallメソッドが、SQL文字列をコンテキストに含めるよう修正されました。
変更前:
def call(sql, connection)
comment = self.comment(connection)
# ...
end
変更後:
def call(sql, connection)
comment = self.comment(sql: sql, connection: connection)
# ...
end
commentメソッドおよびuncached_commentメソッドのシグネチャも、単一のconnection引数からextra_contextハッシュに変更されています。これにより、:sqlキーでSQL文字列にアクセスできるようになりました。
使用例は以下の通りです。クエリの長さをタグとして記録する場合:
config.active_record.query_log_tags = [
sql_length: ->(context) { context[:sql].length }
]
実行されるクエリには/*sql_length:8*/のような形式でタグが付与されます。
コンテキストキーの文書化も同時に行われました。activerecord/lib/active_record/query_logs.rbのモジュールコメントに、コンテキストに含まれる4つのキー(:controller、:job、:connection、:sql)の説明が追加されています。
セキュリティへの配慮
SQL文字列の直接ログ出力に対する警告が文書に追加されました。
CHANGELOGとモジュールコメントの両方に、:sqlをタグとして直接使用することの危険性が明記されています。SQL文字列にはセンシティブなデータが含まれる可能性があり、フィルタリングなしでログに出力することは安全ではありません。
# 安全でない例
config.active_record.query_log_tags = [:sql]
# 安全な例
config.active_record.query_log_tags = [
sql_length: ->(context) { context[:sql].length }
]
この警告は、新機能の提供と同時に誤用を防ぐための設計判断を示しています。SQL文字列そのものではなく、その派生情報(長さ、パターンマッチの結果など)を使用することを推奨しています。
まとめ
本PRは、クエリログタグのコンテキストにSQL文字列を追加することで、クエリの特性に基づいた動的なタグ付けを可能にしました。既存の設定インターフェースを拡張する形での実装により、ActiveSupport::Notificationsを使ったカスタムロジックよりもシンプルな解決策を提供しています。同時に、SQL文字列の直接ログ出力に対する明確な警告を含めることで、セキュリティリスクの軽減も図られています。