ruby - 哪个查询去了哪个数据库的 ActiveRecord 日志

标签 ruby logging rails-activerecord

在与不同数据库有多个连接的 ActiveRecord 应用程序中,日志中没有任何内容表明哪个查询去了哪个数据库。这些查询分离数据库:

Base1.connection.select_value("select * from foo")
Base2.connection.select_value("select * from foo")

发出这些日志条目:

D, [2017-03-13T09:27:11.844395 #22112] DEBUG -- :    (0.6ms)  select * from foo
D, [2017-03-13T09:27:11.844539 #22112] DEBUG -- :    (0.1ms)  select * from foo

如何使 ActiveRecord 数据库日志指示正在对哪个数据库进行查询?

独立示例

begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required."
  raise e
end

gemfile(true) do
  source "https://rubygems.org"
  # Activate the gem you are reporting the issue against.
  gem "activerecord", "4.2.8"
  gem "sqlite3"
end

require "active_record"
require "logger"

class Base1 < ActiveRecord::Base
  self.abstract_class = true
end

class Base2 < ActiveRecord::Base
  self.abstract_class = true
end

Base1.establish_connection(adapter: "sqlite3", database: ":memory:")
Base2.establish_connection(adapter: "sqlite3", database: ":memory:")

ActiveRecord::Base.logger = Logger.new(STDOUT)

Base1.connection.execute("create table foo(i int)")
Base2.connection.execute("create table foo(i int)")
Base1.connection.execute("insert into foo(i) values (1)")
Base2.connection.execute("insert into foo(i) values (2)")
raise unless Base1.connection.select_value("select * from foo") == 1
raise unless Base2.connection.select_value("select * from foo") == 2

输出:

D, [2017-03-13T09:27:11.842939 #22112] DEBUG -- :    (0.2ms)  create table foo(i int)
D, [2017-03-13T09:27:11.843478 #22112] DEBUG -- :    (0.2ms)  create table foo(i int)
D, [2017-03-13T09:27:11.843612 #22112] DEBUG -- :    (0.1ms)  insert into foo(i) values (1)
D, [2017-03-13T09:27:11.843720 #22112] DEBUG -- :    (0.0ms)  insert into foo(i) values (2)
D, [2017-03-13T09:27:11.844395 #22112] DEBUG -- :    (0.6ms)  select * from foo
D, [2017-03-13T09:27:11.844539 #22112] DEBUG -- :    (0.1ms)  select * from foo

我尝试为每个连接创建一个单独的记录器

我尝试为每个连接提供自己的记录器,以便我可以更改每个日志的格式:

Base1.logger = Logger.new(STDOUT)
Base2.logger = Logger.new(STDOUT)

但是,不幸的是,ActiveRecord 中似乎只有一个记录器,如这一行所示,它不会引发异常:

raise unless Base1.logger.object_id == Base2.logger.object_id

版本

  • ruby-2.3.3
  • 事件记录 4.2.8
  • 本例中,sqlite3 1.13.3 (1)
  • 在生产环境中,mysql2 0.4.5 (1) 和 activerecord-sqlserver-adapter 4.2.15 (1)

(1) 此问题并非特定于任何特定的数据库适配器。为了完整起见,我列出了适配器版本。

最佳答案

据我所知,您不能在 native 使用 ActiveRecord 来完成此操作。但是如果你真的需要它,你可以覆盖 AbstractAdapter 中的 log 方法:

class ActiveRecord::ConnectionAdapters::AbstractAdapter
  alias :original_log :log
  def log(sql, name = "SQL", binds = [], statement_name = nil)
    #add info that you want to display to name
    name = "#{name} #{@connection.hash}" 
    original_log(sql, name, binds, statement_name) { yield }
  end
end

输出:

D, [2017-03-15T20:55:59.200533 #73440] DEBUG -- :    -4111614587995646180 (0.5ms)  create table foo(i int)
D, [2017-03-15T20:55:59.201178 #73440] DEBUG -- :    -4097137311320758185 (0.1ms)  create table foo(i int)
D, [2017-03-15T20:55:59.201298 #73440] DEBUG -- :    -4111614587995646180 (0.0ms)  insert into foo(i) values (1)
D, [2017-03-15T20:55:59.201426 #73440] DEBUG -- :    -4097137311320758185 (0.1ms)  insert into foo(i) values (2)
D, [2017-03-15T20:55:59.202229 #73440] DEBUG -- :    -4111614587995646180 (0.7ms)  select * from foo
D, [2017-03-15T20:55:59.202360 #73440] DEBUG -- :    -4097137311320758185 (0.0ms)  select * from foo

更加人性化

上面的代码记录了连接散列,这足以区分一个连接和另一个连接。如果你想记录比这更人性化的东西,你需要有点技巧。

我们可以做的是用一个方法来装饰抽象适配器以返回一个人类友好的连接名称。在程序初始化期间,为每个连接适配器添加一个#log_name 方法:

Base1.connection.define_singleton_method(:log_name) { "one" }
Base2.connection.define_singleton_method(:log_name) { "two" }

monkey-patch 现在可以使用#log_name 方法:

class ActiveRecord::ConnectionAdapters::AbstractAdapter
  alias :original_log :log
  def log(sql, name = "SQL", binds = [], statement_name = nil)
    connection_name = respond_to?(:log_name) ? log_name : nil
    name = [connection_name, name].compact.join(" ")
    original_log(sql, name, binds, statement_name) { yield }
  end
end

输出:

D, [2017-03-21T10:10:53.330021 #22147] DEBUG -- :   one (0.3ms)  create table foo(i int)
D, [2017-03-21T10:10:53.330380 #22147] DEBUG -- :   two (0.2ms)  create table foo(i int)
D, [2017-03-21T10:10:53.330464 #22147] DEBUG -- :   one (0.0ms)  insert into foo(i) values (1)
D, [2017-03-21T10:10:53.330536 #22147] DEBUG -- :   two (0.0ms)  insert into foo(i) values (2)
D, [2017-03-21T10:10:53.331002 #22147] DEBUG -- :   one (0.4ms)  select * from foo
D, [2017-03-21T10:10:53.331104 #22147] DEBUG -- :   two (0.0ms)  select * from foo

关于ruby - 哪个查询去了哪个数据库的 ActiveRecord 日志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42769122/

相关文章:

ruby-on-rails - 在 Rails 中使用带有 has_many 的委托(delegate)?

mysql - 在 activerecord 中可能使用连接将两个 SQL 查询减少为一个

ruby - 我可以使用全局变量初始化类变量吗? ( ruby )

ruby-on-rails - Rails 改变 new.html.erb 页面的背景

node.js - 在 EC2 上观看 NodeJS 日志

java - 使用 Spring 时,如何让 log4j 使用 log4j.xml 文件而不写入控制台?

java - 有没有一种好方法使用 Slf4j 将某些事件记录到单独的日志文件中?

html - 如何将 CSS 类添加到此 Ruby 注入(inject)中?

ruby - Gmail gem 上的未知命令

ruby-on-rails - 当没有明确定义的顺序时,什么是默认顺序?