Monitoramento
Nesta página
O driver permite que o aplicativo seja notificado quando determinados eventos acontecem. Esses eventos são organizados nas seguintes categorias:
Monitoramento de comandos
Ciclo de vida da topologia
Ciclo de vida do servidor
Heartbeats do servidor
pool de conexões e conexões
A topologia e os eventos do servidor fazem parte da Descoberta e Monitoramento do Servidor (SDAM).
Monitoramento de comandos
Todos os comandos iniciados pelo usuário que são enviados para o servidor publicam eventos que podem ser assinados para obter informações refinadas. A API de monitoramento publica um evento de início garantido para cada comando e, em seguida, um evento bem-sucedido ou um evento com falha. Um assinante deve implementar 3 métodos: started
, succeeded
e failed
, cada um deles usando um único parâmetro para o evento. Veja a seguir um exemplo de assinante de registro com base em um assinante de registro usado internamente pelo driver:
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
Para registrar um assinante personalizado, você pode fazer isso globalmente para todos os clientes ou por cliente:
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 )
Saída de amostra:
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
Descoberta e monitoramento de servidores
O Ruby driver implementa a especificação MongoDB Server Discovery and Monitoring (SDAM). e disponibiliza os seguintes eventos para o aplicativo:
Abertura de topologia
Abertura do servidor
Descrição do servidor alterada
topologia alterada
servidor fechado
topologia fechada
Evento de pulsação (analisados abaixo em uma seção separada)
Para todos os eventos que não sejam os eventos de pulsação, o método succeeded
será chamado em cada assinante do evento com o evento como o único argumento. Os dados disponíveis para eventos variam, portanto, para registrar os eventos, é necessária uma classe separada para cada tipo de evento. Um simples assinante de registro do SDAM pode ter a seguinte aparência:
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
Para assinar eventos SDAM globalmente:
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)
Assinar eventos SDAM para um único cliente é um pouco mais trabalhoso, pois os eventos podem ser publicados durante a construção do cliente:
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)
Saída de amostra:
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.
Observação
:sdam_proc
a opção do cliente se aplica apenas ao cliente durante cuja construção é fornecida. Quando determinadas opções do cliente são alteradas por meio da chamada Client#with
, um novo cluster pode ser criado pelo driver com um conjunto padrão de assinantes de eventos. Se isso acontecer, o :sdam_proc
fornecido não será chamado e o aplicativo poderá perder eventos.
servidor Heartbeats
O aplicativo pode ser notificado de cada pulsação do servidor assinando o tópico SERVER_HEARTBATE. Um ouvinte de pulsação do servidor deve implementar três métodos: started
, succeeded
e failed
. Cada pulsação invoca o método started
no ouvinte e, em seguida, o método succeeded
ou failed
, dependendo do resultado da pulsação.
Todos os eventos de pulsação contêm o endereço do servidor para o qual a pulsação foi enviada. Evento bem-sucedidos e com falha contêm o tempo de ida e volta para o comando hello ou legado hello. O evento com falha também contém a instância de exceção que foi gerada durante a execução do comando hello ou hello legado. Revise a documentação da API para ServerHeatbeatStarted, ServerHearbeatSucceeded e ServerHearbeatFailed para obter detalhes do atributo do evento.
Veja a seguir um exemplo de registro de assinante de eventos de pulsação:
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
Da mesma forma que os eventos de comando, o aplicativo pode se inscrever em eventos de pulsação globalmente ou para um cliente específico:
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 )
Saída de amostra:
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
Intervalos de eventos de pulsação
Quando conectado ao MongoDB 4.2 e a servidores anteriores, o driver Ruby, por padrão, emite pulsações a cada :heartbeat_frequency
(opção do cliente Ruby) segundos, e as pulsações não se sobrepõem (é garantido que o evento bem-sucedido para uma pulsação seja publicados antes do evento iniciado para o o próximo heartbeat é publicados). Quando conectado ao MongoDB 4.4 e a servidores posteriores, o driver usa vários threads de monitoramento e um protocolo de pulsação mais complexo projetado para detectar alterações no estado do servidor mais rapidamente; como resultado, os intervalos de eventos de pulsação podem ser mais irregulares e os eventos de pulsação podem se sobrepor. Especificamente, uma pulsação esperada pode começar ou terminar enquanto uma pulsação não esperada está em andamento e vice-versa. Use os métodos ServerHeartbeatStarted#awaited?
, ServerHeartbeatSucceeded#awaited?
e ServerHeartbeatFailed#awaited?
para distinguir entre pulsações não esperadas e aguardadas.
Quando um cliente está tentando executar uma operação e não tem um servidor adequado, a implantação é verificada com mais frequência - cada servidor pode ser pesquisado a cada 500 milissegundos. Também é possível que o aplicativo solicite uma verificação manual de um servidor específico; o driver força o intervalo mínimo de 500 milissegundos entre as verificações.
pool de conexões e monitoramento de conexões
Cada cliente mantém um pool de conexões para cada servidor na implantação que conhece e publica eventos para pools de conexões e conexões individuais. Para assinar esses eventos, defina uma classe de assinante implementando o método pubished
que usa um único parâmetro para o evento que está sendo publicados. Observe que versões futuras do driver podem introduzir eventos adicionais publicados por esse mecanismo.
Os seguintes eventos são atualmente implementados pelo condutor, seguindo a especificação CMAP:
PoolCreated
PoolLimpo
PoolClosed
connectionCreated
connectionReady
connectionClosed
connectionCheckOutStarted
connectionCheckOutFailed
ConnectionCheckOutSucceeded
connectionCheckedIn
O driver fornece um assinante de registro que pode ser usado para registrar todo o pool de conexões e eventos relacionados à conexão. Esse assinante não está habilitado por padrão porque criará entradas de registro para cada operação executada pelo aplicativo. Para habilitar este assinante globalmente ou por cliente:
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 )
Saída de amostra:
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>
Desabilitar o monitoramento
Para desativar o monitoramento, defina a opção de monitoramento do cliente como false
:
client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test', :monitoring => false )
Eventos excluídos e editados
O driver Ruby não publica e, ocasionalmente, edita alguns eventos por meio do mecanismo de monitoramento de comandos:
Se o comando pertencer a um subconjunto específico de comandos editados ou contiver chaves que trigger a redação da carga útil, uma carga vazia será fornecida por motivos de segurança. O payload completo pode ser acessado definindo a variável de ambiente
MONGO_RUBY_DRIVER_UNREDACT_EVENTS
como1
,true
ouyes
. Os seguintes comandos são suprimidos:authenticate
saslStart
saslContinue
getnonce
createUser
updateUser
copydbgetnonce
copydbsaslstart
copydb
Se o comando for um comando de handshake,
ismaster
ouhello
, em uma conexão de não monitoramento, nenhum evento será publicados.Os comandos enviados por conexões de monitoramento (como isMaster e hello) não publicam eventos de monitoramento de comandos. Em vez disso, toda vez que um servidor é marcado, um evento de pulsação do servidor é publicados. Os eventos de pulsação do servidor não incluem cargas úteis de comando ou resposta.
Se o comando for um comando de handshake e as opções
speculativeAuthenticate
foremtrue
, o comando será suprimido e uma carga útil vazia será fornecida.