我遇到了一个问题,在我看来,对于大多数铁路用户来说一定是个问题,但我找不到任何解决方案。
例如,当执行可能较大的二进制文件的文件上载并将其存储在数据库中时,您肯定不希望rails或ActiveRecord在开发模式下记录此特定字段(日志文件,标准输出) 。如果文件相当大,这会导致查询执行中断并几乎终止我的终端。
是否有任何可靠且非hacky的方法来禁用特定字段的日志记录?请记住,我不谈论禁用请求参数的日志记录 - 这已经很好地解决了。
感谢有关的任何信息!
答案 0 :(得分: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 :(得分:5)
在config / initializers中创建一个文件,如下所示修改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个字符的所有字段。
答案 2 :(得分:4)
注意:与rails 3一起使用,但显然不是4(在回答此问题时未发布)
在application.rb文件中:
config.filter_parameters << :parameter_name
这将删除日志中显示的该属性,并将其替换为[FILTERED]
过滤参数的常见用例当然是密码,但我认为没有理由不应该使用二进制文件字段。
答案 3 :(得分: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个字节和后10个字节,并指示从中间删除了多少字节/字符。它不会编辑,除非编辑文本比替换文本长(即如果没有至少20个字符要删除,那么“[删除xx字符]”将比替换文本长,所以没有意义) 。我没有进行性能测试来确定使用贪婪或延迟重复的编辑块是否更快。我的本能是懒惰,所以我做了,但贪婪可能更快,特别是如果SQL中只有一个二进制字段。
答案 4 :(得分:2)
在rails 5中你可以把它放在初始化器中:
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_data
,value
和timeline
。
答案 5 :(得分:1)
这是一个Rails 5版本。开箱即用Rails 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
答案 6 :(得分:0)
我也没有找到太多相关内容,尽管你可以做的一件事是
ActiveRecord::Base.logger = nil
完全禁用日志记录,但您可能不希望这样做。一个更好的解决方案可能是将ActiveRecord记录器设置为某个自定义子类,该子类不记录超过特定大小的消息,或者做一些更聪明的事情来解析消息的特定部分太大。
这似乎并不理想,但它看起来似乎是一个可行的解决方案,尽管我没有看过具体的实现细节。我真的很想听听任何更好的解决方案。
答案 7 :(得分:0)
我遇到了同样的问题,但我无法找到问题的干净解决方案。我最后为过滤掉blob的Rails记录器编写了a custom formatter。
上面的代码需要放在config / initializers中,并将file_dat
a替换为要删除的列,将file_name
替换为正则表达式中显示的列。
答案 8 :(得分:0)
Rails 5.2及更高版本的版本
module LogTruncater
def render_bind(attr, value)
num_chars = Integer(ENV['ACTIVERECORD_SQL_LOG_MAX_VALUE']) rescue 120
half_num_chars = num_chars / 2
if attr.is_a?(Array)
attr = attr.first
elsif attr.type.binary? && attr.value
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
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
[attr && attr.name, value]
end
end
class ActiveRecord::LogSubscriber
prepend LogTruncater
end
答案 9 :(得分:0)
这对我来说适用于Rails 6:
# initializers/scrub_logs.rb
module ActiveSupport
module TaggedLogging
module Formatter # :nodoc:
# Hide PlaygroundTemplate#yaml column from SQL queries because it's huge.
def scrub_yaml_source(input)
input.gsub(/\["yaml", ".*, \["/, '["yaml", "REDACTED"], ["')
end
alias orig_call call
def call(severity, timestamp, progname, msg)
orig_call(severity, timestamp, progname, scrub_yaml_source(msg))
end
end
end
end
用列名替换yaml
。