如何打印 Sequel 的 postgres "raise notice" 输出?

How to print postgres "raise notice" output from Sequel?

引发通知通常用于调试 postgres 中的 PSQL 脚本 (link)。

The docs say that there's some kind of support for printing notices when using the pg gem,但没有关于如何使用此过程、它产生的结果、可能(可能?)注意事项等的信息。

有人有生产 and/or 开发的工作代码示例吗?理想情况下,我正在寻找一种解决方案,允许在启用 Sequel 日志记录时在开发中打印出 PG 通知。

当我这样做时:

DB = Sequel.connect(
  ENV['DATABASE_URL'],
  notice_receiver: lambda{ |x| binding.pry }
)

一旦我执行一个引发通知的函数,notice_receiver lambda 就永远不会被调用。即

[1] pry(#<Psql::CalculateMasterBalancesTest>)> DB.select{ |o| Sequel.function(:emit_notice) }.first
I, [2017-05-17T16:51:56.746003 #23139]  INFO -- : (0.000335s) SELECT emit_notice() LIMIT 1
=> {:emit_notice=>""}

发出通知的地方是:

CREATE OR REPLACE FUNCTION emit_notice()
  RETURNS VOID AS $$

BEGIN
  RAISE NOTICE 'NOTICE ME!!!';
END;
$$ LANGUAGE plpgsql;

它在 PgAdmin 中有效:

NOTICE:  NOTICE ME!!!
Total query runtime: 21 ms.
1 row retrieved.

更新

Alejandro C 给出了一个很好的工作示例,似乎通知没有通过 notice_receiver 挂钩分发。例如:

Sequel.connect(DB.opts.merge(:notice_receiver=>proc{|r| puts r.result_error_message})){ |db|
  db.do("BEGIN\nRAISE NOTICE 'foo';\nEND;")
}

不打印任何内容,并且:

Sequel.connect(DB.opts.merge(:notice_receiver=>proc{|r| puts r.result_error_message})){ |db|
  db.do("BEGIN\nRAISE WARNING 'foo';\nEND;")
}

版画

WARNING: foo

因为 Sequel just calls set_notice_receiver from PG,我想我应该向 PG 提交错误报告。

编辑 2

然而,当我尝试使用 PG gem 时,我得到了

conn = PG.connect( :dbname => 'db_test', user: 'test', password: 'test', host: '127.0.0.1' )
conn.set_notice_receiver{|r| puts r.result_error_message }
conn.exec("SELECT emit_notice()")
NOTICE:  NOTICE ME!!!
=> #<PG::Result:0x0000000405ac18 status=PGRES_TUPLES_OK ntuples=1 nfields=1 cmd_tuples=1>

所以在这一点上我有点困惑...

编辑 3

Posted an issue GitHub...

编辑 4

啊,显然你还需要使用其他选项,client_min_messages 需要设置为 :notice,如下所示:

DB = Sequel.connect(
  ENV['DATABASE_URL'],
  notice_receiver: proc{|r| puts r.result_error_message},
  client_min_messages: :notice
)

这有效

您传入自己的 proc,它以字符串形式获取通知。要让它在通知而非 just warnings and above 时触发,请使用 client_min_messages。例如:

a = nil
Sequel.connect(
  DB.opts.merge(
      notice_receiver: proc{|r| a = r.result_error_message}, 
      client_min_messages: :notice)) { |db|
  db.do("BEGIN\nRAISE WARNING 'foo';\nEND;")
}
a == "WARNING:  foo\n" # true