2012-10-24 10 views
10

私の意見では、ほとんどのレールユーザにとっては問題でなければならない問題に遭遇していますが、それでも解決策が見つかりませんでした。特定の列のActiveRecordロギングを無効にする方法はありますか?

潜在的に大きなバイナリファイルのファイルアップロードを実行してデータベースに格納する場合、レールやActiveRecordが開発モードでこの特定のフィールドをログに記録しないようにすることが最も確実です(ログファイルstdout )。非常に大きなファイルの場合、これはクエリの実行を中断させ、私の端末をほぼ殺します。

特定のフィールドのロギングを無効にする信頼性の高い、非ハッキリな方法はありますか?覚えておいてください、私はではありません。はリクエストパラメータのロギングを無効にすることについて話しています。これは非常にうまく解決されています。

ありがとうございました!

+0

パスワードのようなものをフィルタリングするオプションがありますが、それが役立つかどうかわかりません。 ActiveRecordを上書きしてハッキーを実行することを検討しますか?そうでなければあなたのヒントがあります。 –

答えて

0

あなたができる一つのことは、あなたはおそらくそれを行うにはしたくないだろうが、完全にロギングを無効にする

ActiveRecord::Base.logger = nil 

ですが、私は、このいずれかの多くを見つけることができませんでした。より良い解決策は、一定のサイズ以上のメッセージを記録しないカスタムサブクラスにActiveRecordロガーを設定することです。メッセージの特定の部分を解析するためにはスマートな方法があります。

これは理想的ではありませんが、具体的な実装の詳細は見ていませんが、実行可能なソリューションのようです。私は本当に良い解決策を聞くことに興味があります。

+0

これは唯一の可能性ですが、このソリューションは、この呼び出しがログに記録されるようにしたいので、このソリューションはかなり醜いものです。 「完璧な」答えが得られない場合は、ログステートメントを解析するカスタムロガーを実装することもできます。 – Remo

+0

Loggerの "add"メソッドをオーバーライドしたいと思われるように、サブクラス化されたバージョンは解析を行い、スーパークラスaddメソッドを呼び出して、解析されたメッセージと他のパラメータを渡します。 –

4

注:お使いのapplication.rbファイル(この質問に回答されたときに解放されなかった)レール3で動作しますが、どうやらない4

config.filter_parameters << :parameter_name 

これはそれを削除しますあなたのログに表示されないようにしてください。[FILTERED] もちろん、フィルタリングパラメータの一般的な使用例はパスワードですが、私はバイナリファイルフィールドでは動作しません。

+1

これは、SQLログのパラメータではなくHTTPリクエストパラメータをフィルタリングするだけではありませんか? – Remo

+0

いいえ、レールログのすべてをフィルタリングします。受信リクエスト上のparamsハッシュとログに記録されたSQLステートメントは[FILTERED]と表示されます – agmin

+0

ありがとうございます!私はそれを試み、できるだけ早く報告するつもりです。 – Remo

5

が設定/初期化子内のファイルを作成しますwhitchそうのようなActiveRecord::ConnectionAdapters::AbstractAdapterを変更します。

class ActiveRecord::ConnectionAdapters::AbstractAdapter 
    protected 

    def log_with_trunkate(sql, name="SQL", binds=[], &block) 
    b = binds.map {|k,v| 
     v = v.truncate(20) if v.is_a? String and v.size > 20 
     [k,v] 
    } 
    log_without_trunkate(sql, name, b, &block) 
    end 

    alias_method_chain :log, :trunkate 
end 

これは出力ログで20文字よりも長くなっているすべてのフィールドをtrunkateます。

+0

これは挿入要求だけを切り捨てることにも注意してください。更新の際には、SQLのパラメータですべてがスローされるため、切り捨てる必要もあります。 – Patrik

+0

Rails 3.0.9の 'log_without_trunkate'コールで引数の数が間違っています(3の場合は2)。 – CHsurfer

+0

3.0.xレールのlogメソッドは、 'sql'と 'name'の2つの引数しか取らないlogメソッドを使用します。バインドとブロックを引数から削除し、sql引数からフィルタを外します。 – Patrik

0

同じ問題が発生しましたが、問題の解決策を見つけられませんでした。私はブロブをフィルタリングするRailsロガーのためにa custom formatterと書いてしまった。

上記のコードは、config/initializersに配置する必要があります。file_dataを削除する列に置き換え、file_nameを正規表現の後に表示される列に置き換えます。

3

@Patrikが提案するアプローチの実装は、PostgreSQLに対する挿入と更新の両方に対応しています。正規表現は、他のデータベース用のSQLのフォーマットに応じて微調整する必要があります。

class ActiveRecord::ConnectionAdapters::AbstractAdapter 
    protected 

    def log_with_binary_truncate(sql, name="SQL", binds=[], &block) 
    binds = binds.map do |col, data| 
     if col.type == :binary && data.is_a?(String) && data.size > 27 
     data = "#{data[0,10]}[REDACTED #{data.size - 20} bytes]#{data[-10,10]}" 
     end 
     [col, data] 
    end 

    sql = sql.gsub(/(?<='\\x[0-9a-f]{20})[0-9a-f]{20,}?(?=[0-9a-f]{20}')/) do |match| 
     "[REDACTED #{match.size} chars]" 
    end 

    log_without_binary_truncate(sql, name, binds, &block) 
    end 

    alias_method_chain :log, :binary_truncate 
end 

私はそれに満足していませんが、今は十分です。バイナリ文字列の最初と最後の10バイトを保持し、途中から何バイト/文字が削除されたかを示します。編集されたテキストが置き換えられたテキストより長い場合を除いては編集は行われません(つまり、削除する文字数が20文字以上でない場合、 "[REDACTED xx chars]"は置き換えられたテキストより長くなります) 。私は、編集されたチャンクの貪欲なまたは怠惰な繰り返しの使用がより速かったかどうかを判断するために、パフォーマンステストを行っていませんでした。私の本能は怠惰になってしまったので、私はしましたが、特にSQLにバイナリフィールドが1つしかない場合、欲張りが速くなる可能性があります。

+0

IMHOについて下記のdbortzソリューションを参照してください。これがこの問題の最良の解決策です。 – reto

+0

これはmysqlの正規表現です。ソリューションに追加しますか? /(α<= x '[0-9a-f] {20})[0-9a-f] {20、= [0-9a-f] {20} ')/ – reto

6

誰にでも役立つ場合は、上記のスニペットのRails 4.1互換バージョンであり、非バイナリバインドパラメータ(テキストやjson列など)の改ざんも含まれ、編集前に100文字に増加します。誰もが助けてくれてありがとう!

class ActiveRecord::ConnectionAdapters::AbstractAdapter 
    protected 

    def log_with_binary_truncate(sql, name="SQL", binds=[], statement_name = nil, &block) 
    binds = binds.map do |col, data| 
     if data.is_a?(String) && data.size > 100 
     data = "#{data[0,10]} [REDACTED #{data.size - 20} bytes] #{data[-10,10]}" 
     end 
     [col, data] 
    end 

    sql = sql.gsub(/(?<='\\x[0-9a-f]{100})[0-9a-f]{100,}?(?=[0-9a-f]{100}')/) do |match| 
     "[REDACTED #{match.size} chars]" 
    end 

    log_without_binary_truncate(sql, name, binds, statement_name, &block) 
    end 

    alias_method_chain :log, :binary_truncate 
end 
+1

これは、Rails 4.2までは間違いなく動作しますが、5.0+では動作しません。 Railsには同様の機能が組み込まれているようだから、Rails 5には必要ない。 – Ritchie

+1

@Ritchie何が機能に組み込まれているの? – abonec

0

ここにはRails 5バージョンがあります。ボックス外のRails 5ではバイナリデータは切り詰められますが、長いテキストカラムは切り詰められません。レール5に

module LogTruncater 
    def render_bind(attribute) 
    num_chars = Integer(ENV['ACTIVERECORD_SQL_LOG_MAX_VALUE']) rescue 120 
    half_num_chars = num_chars/2 
    value = if attribute.type.binary? && attribute.value 
     if attribute.value.is_a?(Hash) 
     "<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>" 
     else 
     "<#{attribute.value.bytesize} bytes of binary data>" 
     end 
    else 
     attribute.value_for_database 
    end 

    if value.is_a?(String) && value.size > num_chars 
     value = "#{value[0,half_num_chars]} [REDACTED #{value.size - num_chars} chars] #{value[-half_num_chars,half_num_chars]}" 
    end 

    [attribute.name, value] 
    end 

end 

class ActiveRecord::LogSubscriber 
    prepend LogTruncater 
end 
0

あなたは初期化子でそれを置くことができます:フィルタの

module SqlLogFilter 

    FILTERS = Set.new(%w(geo_data value timeline)) 
    def render_bind(attribute) 
    return [attribute.name, '<filtered>'] if FILTERS.include?(attribute.name) 
    super 
    end 

end 
ActiveRecord::LogSubscriber.prepend SqlLogFilter 

は、例えばgeo_datavaluetimeline属性。

関連する問題