文档菜单
文档首页
/ / /
Ruby MongoDB 驱动程序
/

监控

本页内容

  • 命令监控
  • 服务器发现和监控
  • 服务器心跳
  • 连接池和连接监控
  • 禁用监控
  • 排除和编辑事件

该驱动允许应用程序在发生某些事件时被通知。这些事件组织成以下类别

  • 命令监控

  • 拓扑生命周期

  • 服务器生命周期

  • 服务器心跳

  • 连接池和连接

拓扑和服务器事件是服务器发现和监控(SDAM)的一部分。

所有由用户发起发送到服务器的命令都会发布可以被订阅的事件,以获取更详细的信息。监控API为每个命令发布一个保证启动事件,然后是一个成功或失败事件。订阅者必须实现3个方法startedsucceededfailed,每个方法都接受一个事件的单个参数。以下是基于驱动内部使用的日志订阅者示例的日志订阅者示例

class CommandLogSubscriber
include Mongo::Loggable
def started(event)
# The default inspection of a command which is a BSON document gets
# truncated in the middle. To get the full rendering of the command, the
# ``to_json`` method can be called on the document.
log_debug("#{prefix(event)} | STARTED | #{format_command(event.command.to_json)}")
end
def succeeded(event)
log_debug("#{prefix(event)} | SUCCEEDED | #{event.duration}s")
end
def failed(event)
log_debug("#{prefix(event)} | FAILED | #{event.message} | #{event.duration}s")
end
private
def logger
Mongo::Logger.logger
end
def format_command(args)
begin
args.inspect
rescue Exception
'<Unable to inspect arguments>'
end
end
def format_message(message)
format("COMMAND | %s".freeze, message)
end
def prefix(event)
"#{event.address.to_s} | #{event.database_name}.#{event.command_name}"
end
end

要注册自定义订阅者,您可以为所有客户端全局或按客户端进行

subscriber = CommandLogSubscriber.new
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::COMMAND, subscriber)
client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test' )
client.subscribe( Mongo::Monitoring::COMMAND, subscriber )

示例输出

D, [2018-09-23T13:47:31.258020 #4692] DEBUG -- : COMMAND | 127.0.0.1:27027 | test.hello | STARTED | {"hello"=>1, "$readPreference"=>{"mode"=>"primary"}, "lsid"=>{"id"=><BSON::Binary:0x47111693353080 type=uuid data=0x730341e880dc40a2...>}}
D, [2018-09-23T13:47:31.259145 #4692] DEBUG -- : COMMAND | 127.0.0.1:27027 | test.hello | SUCCEEDED | 0.000791175s

Ruby驱动实现服务器发现与监控(SDAM)规范. 并向应用程序提供以下事件

  • 拓扑打开

  • 服务器打开

  • 服务器描述更改

  • 拓扑更改

  • 服务器关闭

  • 拓扑关闭

  • 心跳事件(如下文单独章节所述)

对于除心跳事件之外的所有事件,每个事件订阅者将调用 succeeded 方法,事件作为唯一参数。事件可用数据不同,因此要记录事件,需要为每种事件类型创建一个单独的类。一个简单的SDAM日志订阅者可能如下所示

class SDAMLogSubscriber
include Mongo::Loggable
def succeeded(event)
log_debug(format_event(event))
end
private
def logger
Mongo::Logger.logger
end
def format_message(message)
format("SDAM | %s".freeze, message)
end
end
class TopologyOpeningLogSubscriber < SDAMLogSubscriber
private
def format_event(event)
"Topology type '#{event.topology.display_name}' initializing."
end
end
class ServerOpeningLogSubscriber < SDAMLogSubscriber
private
def format_event(event)
"Server #{event.address} initializing."
end
end
class ServerDescriptionChangedLogSubscriber < SDAMLogSubscriber
private
def format_event(event)
"Server description for #{event.address} changed from " +
"'#{event.previous_description.server_type}' to '#{event.new_description.server_type}'."
end
end
class TopologyChangedLogSubscriber < SDAMLogSubscriber
private
def format_event(event)
if event.previous_topology != event.new_topology
"Topology type '#{event.previous_topology.display_name}' changed to " +
"type '#{event.new_topology.display_name}'."
else
"There was a change in the members of the '#{event.new_topology.display_name}' " +
"topology."
end
end
end
class ServerClosedLogSubscriber < SDAMLogSubscriber
private
def format_event(event)
"Server #{event.address} connection closed."
end
end
class TopologyClosedLogSubscriber < SDAMLogSubscriber
private
def format_event(event)
"Topology type '#{event.topology.display_name}' closed."
end
end

全局订阅SDAM事件

topology_opening_subscriber = TopologyOpeningLogSubscriber.new
server_opening_subscriber = ServerOpeningLogSubscriber.new
server_description_changed_subscriber = ServerDescriptionChangedLogSubscriber.new
topology_changed_subscriber = TopologyChangedLogSubscriber.new
server_closed_subscriber = ServerClosedLogSubscriber.new
topology_closed_subscriber = TopologyClosedLogSubscriber.new
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::TOPOLOGY_OPENING,
topology_opening_subscriber)
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::SERVER_OPENING,
server_opening_subscriber)
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::SERVER_DESCRIPTION_CHANGED,
server_description_changed_subscriber)
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::TOPOLOGY_CHANGED,
topology_changed_subscriber)
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::SERVER_CLOSED,
server_closed_subscriber)
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::TOPOLOGY_CLOSED,
topology_closed_subscriber)

为单个客户端订阅SDAM事件稍微复杂一些,因为事件可能在客户端构建期间发布

topology_opening_subscriber = TopologyOpeningLogSubscriber.new
server_opening_subscriber = ServerOpeningLogSubscriber.new
server_description_changed_subscriber = ServerDescriptionChangedLogSubscriber.new
topology_changed_subscriber = TopologyChangedLogSubscriber.new
server_closed_subscriber = ServerClosedLogSubscriber.new
topology_closed_subscriber = TopologyClosedLogSubscriber.new
sdam_proc = Proc.new do |client|
client.subscribe(Mongo::Monitoring::TOPOLOGY_OPENING,
topology_opening_subscriber)
client.subscribe(Mongo::Monitoring::SERVER_OPENING,
server_opening_subscriber)
client.subscribe(Mongo::Monitoring::SERVER_DESCRIPTION_CHANGED,
server_description_changed_subscriber)
client.subscribe(Mongo::Monitoring::TOPOLOGY_CHANGED,
topology_changed_subscriber)
client.subscribe(Mongo::Monitoring::SERVER_CLOSED,
server_closed_subscriber)
client.subscribe(Mongo::Monitoring::TOPOLOGY_CLOSED,
topology_closed_subscriber)
end
client = Mongo::Client.new(['127.0.0.1:27017'], database: 'test',
sdam_proc: sdam_proc)

示例输出

D, [2018-10-09T13:58:03.489461 #22079] DEBUG -- : SDAM | Topology type 'Unknown' initializing.
D, [2018-10-09T13:58:03.489699 #22079] DEBUG -- : SDAM | Server 127.0.0.1:27100 initializing.
D, [2018-10-09T13:58:03.491384 #22079] DEBUG -- : SDAM | Server description for 127.0.0.1:27100 changed from 'unknown' to 'unknown'.
D, [2018-10-09T13:58:03.491642 #22079] DEBUG -- : SDAM | Server localhost:27100 initializing.
D, [2018-10-09T13:58:03.493199 #22079] DEBUG -- : SDAM | Server description for localhost:27100 changed from 'unknown' to 'primary'.
D, [2018-10-09T13:58:03.493473 #22079] DEBUG -- : SDAM | Server localhost:27101 initializing.
D, [2018-10-09T13:58:03.494874 #22079] DEBUG -- : SDAM | Server description for localhost:27101 changed from 'unknown' to 'secondary'.
D, [2018-10-09T13:58:03.495139 #22079] DEBUG -- : SDAM | Server localhost:27102 initializing.
D, [2018-10-09T13:58:03.496504 #22079] DEBUG -- : SDAM | Server description for localhost:27102 changed from 'unknown' to 'secondary'.
D, [2018-10-09T13:58:03.496777 #22079] DEBUG -- : SDAM | Topology type 'Unknown' changed to type 'ReplicaSetNoPrimary'.
D, [2018-10-09T13:58:03.497306 #22079] DEBUG -- : SDAM | Server 127.0.0.1:27100 connection closed.
D, [2018-10-09T13:58:03.497606 #22079] DEBUG -- : SDAM | Topology type 'ReplicaSetNoPrimary' changed to type 'ReplicaSetWithPrimary'.
# client.close
D, [2018-10-09T13:58:05.342057 #22079] DEBUG -- : SDAM | Server localhost:27100 connection closed.
D, [2018-10-09T13:58:05.342299 #22079] DEBUG -- : SDAM | Server localhost:27101 connection closed.
D, [2018-10-09T13:58:05.342565 #22079] DEBUG -- : SDAM | Server localhost:27102 connection closed.
D, [2018-10-09T13:58:05.342693 #22079] DEBUG -- : SDAM | Topology type 'ReplicaSetWithPrimary' closed.

注意

:sdam_proc 客户端选项仅适用于在构建期间提供的客户端。当通过 Client#with 调用更改某些客户端选项时,驱动程序可能会创建一个新的集群,并带有默认的事件订阅者集。如果发生这种情况,提供的 :sdam_proc 不会被调用,应用程序可能会错过事件。

应用程序可以通过订阅 SERVER_HEARTBEAT 主题来接收每个服务器的心跳通知。服务器心跳监听器必须实现三个方法:startedsucceededfailed。每次心跳都会在监听器上调用 started 方法,然后根据心跳的结果调用 succeededfailed 方法。

所有心跳事件都包含发送心跳的服务器地址。成功和失败事件包含用于 hello 或 legacy hello 命令的往返时间。失败事件还包含在 hello 或 legacy hello 命令执行过程中引发的异常实例。请查阅 ServerHeartbeatStarted、ServerHeartbeatSucceeded 和 ServerHeartbeatFailed 的 API 文档以获取事件属性详细信息。

以下是一个示例心跳事件订阅器

class HeartbeatLogSubscriber
include Mongo::Loggable
def started(event)
log_debug("#{event.address} | STARTED")
end
def succeeded(event)
log_debug("#{event.address} | SUCCEEDED | #{event.duration}s")
end
def failed(event)
log_debug("#{event.address} | FAILED | #{event.error.class}: #{event.error.message} | #{event.duration}s")
end
private
def logger
Mongo::Logger.logger
end
def format_message(message)
format("HEARTBEAT | %s".freeze, message)
end
end

类似于命令事件,应用程序可以全局订阅心跳事件或特定客户端的心跳事件

subscriber = HeartbeatLogSubscriber.new
Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::SERVER_HEARTBEAT, subscriber)
client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test' )
client.subscribe( Mongo::Monitoring::SERVER_HEARTBEAT, subscriber )

示例输出

D, [2018-09-23T13:44:10.707018 #1739] DEBUG -- : HEARTBEAT | 127.0.0.1:27027 | STARTED
D, [2018-09-23T13:44:10.707778 #1739] DEBUG -- : HEARTBEAT | 127.0.0.1:27027 | SUCCEEDED | 0.000772381s

当连接到 MongoDB 4.2 及更早版本的服务器时,Ruby 驱动默认在 :heartbeat_frequency(Ruby 客户端选项)秒内发出心跳,心跳是非重叠的(心跳的成功事件保证在下一个心跳的 started 事件发布之前发布)。当连接到 MongoDB 4.4 及更高版本的服务器时,驱动程序使用多个监控线程和一个更复杂的心跳协议,旨在更快地检测服务器状态的变化;因此,心跳事件间隔可能更不规则,心跳事件可能会重叠。具体来说,一个 awaited heartbeat 可能在一个 non-awaited heartbeat 正在进行时开始或完成,反之亦然。使用 ServerHeartbeatStarted#awaited?ServerHeartbeatSucceeded#awaited?ServerHeartbeatFailed#awaited? 方法来区分非等待和等待的心跳。

当客户端尝试执行操作但没有合适的服务器时,部署会更频繁地扫描 - 每个服务器可以每 500 毫秒被轮询一次。应用程序还可以请求手动扫描特定服务器;驱动程序强制执行扫描之间的最小间隔为 500 毫秒。

每个客户端为其所知的每个服务器维护一个连接池,并发布连接池和单个连接的事件。要订阅这些事件,定义一个实现方法 pubished 的订阅者类,该方法接受一个参数,表示正在发布的事件。请注意,驱动程序的后续版本可能通过此机制引入其他事件。

驱动程序目前实现了以下事件,遵循 CMAP 规范

  • PoolCreated

  • PoolCleared

  • PoolClosed

  • ConnectionCreated

  • ConnectionReady

  • ConnectionClosed

  • ConnectionCheckOutStarted

  • ConnectionCheckOutFailed

  • ConnectionCheckOutSucceeded

  • ConnectionCheckedIn

驱动程序提供了一个日志订阅者,可用于记录所有连接池和连接相关事件。此订阅者默认不启用,因为它将为应用程序执行的每个操作创建日志条目。要全局或按客户端启用此订阅者

Mongo::Monitoring::Global.subscribe(
Mongo::Monitoring::CONNECTION_POOL,
Mongo::Monitoring::CmapLogSubscriber.new)
client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test' )
subscriber = Mongo::Monitoring::CmapLogSubscriber.new
client.subscribe( Mongo::Monitoring::CONNECTION_POOL, subscriber )

示例输出

D, [2019-05-06T17:23:21.595412 #8576] DEBUG -- : MONGODB | EVENT: #<PoolCreated address=127.0.0.1:27741 options={...}>
D, [2019-05-06T17:23:21.595584 #8576] DEBUG -- : MONGODB | EVENT: #<PoolCleared address=127.0.0.1:27741>
D, [2019-05-06T17:23:21.603549 #8576] DEBUG -- : MONGODB | EVENT: #<PoolCreated address=localhost:27741 options={...}>
D, [2019-05-06T17:23:21.603616 #8576] DEBUG -- : MONGODB | EVENT: #<ConnectionCheckOutStarted address=localhost:27741>
D, [2019-05-06T17:23:21.603684 #8576] DEBUG -- : MONGODB | EVENT: #<ConnectionCreated address=localhost:27741 connection_id=1>
D, [2019-05-06T17:23:21.604079 #8576] DEBUG -- : MONGODB | EVENT: #<ConnectionCheckedOut address=localhost:27741 connection_id=1>
D, [2019-05-06T17:23:21.605759 #8576] DEBUG -- : MONGODB | EVENT: #<ConnectionReady address=localhost:27741 connection_id=1>
D, [2019-05-06T17:23:21.605784 #8576] DEBUG -- : MONGODB | EVENT: #<ConnectionCheckedIn address=localhost:27741 connection_id=1>
D, [2019-05-06T17:23:21.605817 #8576] DEBUG -- : MONGODB | EVENT: #<PoolCleared address=localhost:27741>
D, [2019-05-06T17:23:21.605852 #8576] DEBUG -- : MONGODB | EVENT: #<ConnectionClosed address=localhost:27741 connection_id=1 reason=stale>

要关闭监控,将客户端监控选项设置为 false

client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test', :monitoring => false )

Ruby 驱动程序不会通过命令监控机制发布某些事件,偶尔还会编辑这些事件。

  1. 如果命令属于特定子集的编辑命令,或者包含触发有效载荷编辑的密钥,出于安全考虑,将提供空的有效载荷。可以通过将环境变量 MONGO_RUBY_DRIVER_UNREDACT_EVENTS 设置为 1trueyes 来访问完整的有效载荷。以下命令将被编辑

    • authenticate

    • saslStart

    • saslContinue

    • getnonce

    • createUser

    • updateUser

    • copydbgetnonce

    • copydbsaslstart

    • copydb

  2. 如果命令是握手命令,即非监控连接上的 ismasterhello,则完全不发布事件。

  3. 通过监控连接(如 ismasterhello)发送的命令不发布命令监控事件。相反,每次检查服务器时都会发布服务器心跳事件。服务器心跳事件不包含命令或回复有效载荷。

  4. 如果命令是握手命令,并且 speculativeAuthenticate 选项为 true,则命令将被编辑,并提供空的有效载荷。

返回

身份验证