Docs 菜单
Docs 主页
/ / /
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驱动程序实施MongoDB Server 发现和监控 (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 或旧版 hello 命令的往返时间。失败事件还包含在执行 hello 或旧版 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 客户端选项)秒发出一次心跳,并且心跳不重叠(保证心跳的成功事件在心跳的启动事件之前发布)。已发布下一个心跳)。 当连接到 MongoDB 4.4 及更高版本的服务器时,该驱动程序使用多个监控线程和更复杂的心跳协议,旨在更快地检测服务器状态的变化;因此,心跳事件间隔可能会更加不规则,并且心跳事件可能会重叠。 具体来说,等待的心跳可以在非等待的心跳正在进行时开始或结束,反之亦然。 使用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. 如果该命令属于日志校订命令的特定子集,或包含trigger有效负载日志校订的密钥,则出于安全原因,将提供空有效负载。可以通过将MONGO_RUBY_DRIVER_UNREDACT_EVENTS环境变量设置为1trueyes来访问完整的有效负载。 以下命令已编辑:

    • authenticate

    • saslStart

    • saslContinue

    • getnonce

    • createUser

    • updateUser

    • copydbgetnonce

    • copydbsaslstart

    • copydb

  2. 如果该命令是握手命令(在非监控连接上为ismasterhello ),则根本不会发布任何事件。

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

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

后退

身份验证