1414
1515"""Tools to monitor driver events. 
1616
17+ .. versionadded:: 3.1 
18+ 
1719Use :func:`register` to register global listeners for specific events. 
1820Listeners must inherit from one of the abstract classes below and implement 
1921the correct functions for that class. 
@@ -45,6 +47,74 @@ def failed(self, event):
4547
4648 monitoring.register(CommandLogger()) 
4749
50+ Server discovery and monitoring events are also available. For example:: 
51+ 
52+  class ServerLogger(monitoring.ServerListener): 
53+ 
54+  def opened(self, event): 
55+  logging.info("Server {0.server_address} added to topology " 
56+  "{0.topology_id}".format(event)) 
57+ 
58+  def description_changed(self, event): 
59+  previous_server_type = event.previous_description.server_type 
60+  new_server_type = event.new_description.server_type 
61+  if new_server_type != previous_server_type: 
62+  # server_type_name was added in PyMongo 3.4 
63+  logging.info( 
64+  "Server {0.server_address} changed type from " 
65+  "{0.previous_description.server_type_name} to " 
66+  "{0.new_description.server_type_name}".format(event)) 
67+ 
68+  def closed(self, event): 
69+  logging.warning("Server {0.server_address} removed from topology " 
70+  "{0.topology_id}".format(event)) 
71+ 
72+ 
73+  class HeartbeatLogger(monitoring.ServerHeartbeatListener): 
74+ 
75+  def started(self, event): 
76+  logging.info("Heartbeat sent to server " 
77+  "{0.connection_id}".format(event)) 
78+ 
79+  def succeeded(self, event): 
80+  # The reply.document attribute was added in PyMongo 3.4. 
81+  logging.info("Heartbeat to server {0.connection_id} " 
82+  "succeeded with reply " 
83+  "{0.reply.document}".format(event)) 
84+ 
85+  def failed(self, event): 
86+  logging.warning("Heartbeat to server {0.connection_id} " 
87+  "failed with error {0.reply}".format(event)) 
88+ 
89+  class TopologyLogger(monitoring.TopologyListener): 
90+ 
91+  def opened(self, event): 
92+  logging.info("Topology with id {0.topology_id} " 
93+  "opened".format(event)) 
94+ 
95+  def description_changed(self, event): 
96+  logging.info("Topology description updated for " 
97+  "topology id {0.topology_id}".format(event)) 
98+  previous_topology_type = event.previous_description.topology_type 
99+  new_topology_type = event.new_description.topology_type 
100+  if new_topology_type != previous_topology_type: 
101+  # topology_type_name was added in PyMongo 3.4 
102+  logging.info( 
103+  "Topology {0.topology_id} changed type from " 
104+  "{0.previous_description.topology_type_name} to " 
105+  "{0.new_description.topology_type_name}".format(event)) 
106+  # The has_writable_server and has_readable_server methods 
107+  # were added in PyMongo 3.4. 
108+  if not event.new_description.has_writable_server(): 
109+  logging.warning("No writable servers available.") 
110+  if not event.new_description.has_readable_server(): 
111+  logging.warning("No readable servers available.") 
112+ 
113+  def closed(self, event): 
114+  logging.info("Topology with id {0.topology_id} " 
115+  "closed".format(event)) 
116+ 
117+ 
48118Event listeners can also be registered per instance of 
49119:class:`~pymongo.mongo_client.MongoClient`:: 
50120
@@ -78,13 +148,13 @@ def failed(self, event):
78148
79149
80150class  _EventListener (object ):
81-  """Abstract base class for all event listeners.  """ 
151+  """Abstract base class for all event listeners.""" 
82152
83153
84154class  CommandListener (_EventListener ):
85155 """Abstract base class for command listeners. 
86156 Handles `CommandStartedEvent`, `CommandSucceededEvent`, 
87-  and `CommandFailedEvent`""" 
157+  and `CommandFailedEvent`. """ 
88158
89159 def  started (self , event ):
90160 """Abstract method to handle a `CommandStartedEvent`. 
@@ -114,7 +184,10 @@ def failed(self, event):
114184class  ServerHeartbeatListener (_EventListener ):
115185 """Abstract base class for server heartbeat listeners. 
116186 Handles `ServerHeartbeatStartedEvent`, `ServerHeartbeatSucceededEvent`, 
117-  and `ServerHeartbeatFailedEvent`.""" 
187+  and `ServerHeartbeatFailedEvent`. 
188+ 
189+  .. versionadded:: 3.3 
190+  """ 
118191
119192 def  started (self , event ):
120193 """Abstract method to handle a `ServerHeartbeatStartedEvent`. 
@@ -144,7 +217,10 @@ def failed(self, event):
144217class  TopologyListener (_EventListener ):
145218 """Abstract base class for topology monitoring listeners. 
146219 Handles `TopologyOpenedEvent`, `TopologyDescriptionChangedEvent`, and 
147-  `TopologyClosedEvent`.""" 
220+  `TopologyClosedEvent`. 
221+ 
222+  .. versionadded:: 3.3 
223+  """ 
148224
149225 def  opened (self , event ):
150226 """Abstract method to handle a `TopologyOpenedEvent`. 
@@ -174,7 +250,10 @@ def closed(self, event):
174250class  ServerListener (_EventListener ):
175251 """Abstract base class for server listeners. 
176252 Handles `ServerOpeningEvent`, `ServerDescriptionChangedEvent`, and 
177-  `ServerClosedEvent`.""" 
253+  `ServerClosedEvent`. 
254+ 
255+  .. versionadded:: 3.3 
256+  """ 
178257
179258 def  opened (self , event ):
180259 """Abstract method to handle a `ServerOpeningEvent`. 
@@ -405,7 +484,10 @@ def topology_id(self):
405484
406485
407486class  ServerDescriptionChangedEvent (_ServerEvent ):
408-  """Published when server description changes.""" 
487+  """Published when server description changes. 
488+ 
489+  .. versionadded:: 3.3 
490+  """ 
409491
410492 __slots__  =  ('__previous_description' , '__new_description' )
411493
@@ -416,25 +498,33 @@ def __init__(self, previous_description, new_description, *args):
416498
417499 @property  
418500 def  previous_description (self ):
419-  """The previous server description.""" 
501+  """The previous 
502+  :class:`~pymongo.server_description.ServerDescription`.""" 
420503 return  self .__previous_description 
421504
422505 @property  
423506 def  new_description (self ):
424-  """The new server description.""" 
507+  """The new 
508+  :class:`~pymongo.server_description.ServerDescription`.""" 
425509 return  self .__new_description 
426510
427511
428512class  ServerOpeningEvent (_ServerEvent ):
429-  """Published when server is initialized.""" 
513+  """Published when server is initialized. 
514+ 
515+  .. versionadded:: 3.3 
516+  """ 
430517
431518
432519class  ServerClosedEvent (_ServerEvent ):
433-  """Published when server is closed.""" 
520+  """Published when server is closed. 
521+ 
522+  .. versionadded:: 3.3 
523+  """ 
434524
435525
436526class  TopologyEvent (object ):
437-  """Base class for topology description events""" 
527+  """Base class for topology description events. """ 
438528
439529 __slots__  =  ('__topology_id' )
440530
@@ -448,7 +538,10 @@ def topology_id(self):
448538
449539
450540class  TopologyDescriptionChangedEvent (TopologyEvent ):
451-  """Published when the topology description changes.""" 
541+  """Published when the topology description changes. 
542+ 
543+  .. versionadded:: 3.3 
544+  """ 
452545
453546 __slots__  =  ('__previous_description' , '__new_description' )
454547
@@ -459,25 +552,33 @@ def __init__(self, previous_description, new_description, *args):
459552
460553 @property  
461554 def  previous_description (self ):
462-  """The old topology description.""" 
555+  """The previous 
556+  :class:`~pymongo.topology_description.TopologyDescription`.""" 
463557 return  self .__previous_description 
464558
465559 @property  
466560 def  new_description (self ):
467-  """The new topology description.""" 
561+  """The new 
562+  :class:`~pymongo.topology_description.TopologyDescription`.""" 
468563 return  self .__new_description 
469564
470565
471566class  TopologyOpenedEvent (TopologyEvent ):
472-  """Published when the topology is initialized.""" 
567+  """Published when the topology is initialized. 
568+ 
569+  .. versionadded:: 3.3 
570+  """ 
473571
474572
475573class  TopologyClosedEvent (TopologyEvent ):
476-  """Published when the topology is closed.""" 
574+  """Published when the topology is closed. 
575+ 
576+  .. versionadded:: 3.3 
577+  """ 
477578
478579
479580class  _ServerHeartbeatEvent (object ):
480-  """Base class for server heartbeat events""" 
581+  """Base class for server heartbeat events. """ 
481582
482583 __slots__  =  ('__connection_id' )
483584
@@ -486,17 +587,23 @@ def __init__(self, connection_id):
486587
487588 @property  
488589 def  connection_id (self ):
489-  """" The address (host, port) of the server this heartbeat was sent 
490-    to.""" 
590+  """The address (host, port) of the server this heartbeat was sent 
591+  to.""" 
491592 return  self .__connection_id 
492593
493594
494595class  ServerHeartbeatStartedEvent (_ServerHeartbeatEvent ):
495-  """"Published when a heartbeat is started.""" 
596+  """Published when a heartbeat is started. 
597+ 
598+  .. versionadded:: 3.3 
599+  """ 
496600
497601
498602class  ServerHeartbeatSucceededEvent (_ServerHeartbeatEvent ):
499-  """Fired when the server heartbeat succeeds.""" 
603+  """Fired when the server heartbeat succeeds. 
604+ 
605+  .. versionadded:: 3.3 
606+  """ 
500607
501608 __slots__  =  ('__duration' , '__reply' )
502609
@@ -512,13 +619,16 @@ def duration(self):
512619
513620 @property  
514621 def  reply (self ):
515-  """The command reply .""" 
622+  """An instance of :class:`~pymongo.ismaster.IsMaster` .""" 
516623 return  self .__reply 
517624
518625
519626class  ServerHeartbeatFailedEvent (_ServerHeartbeatEvent ):
520627 """Fired when the server heartbeat fails, either with an "ok: 0" 
521-  or a socket exception.""" 
628+  or a socket exception. 
629+ 
630+  .. versionadded:: 3.3 
631+  """ 
522632
523633 __slots__  =  ('__duration' , '__reply' )
524634
@@ -534,7 +644,7 @@ def duration(self):
534644
535645 @property  
536646 def  reply (self ):
537-  """The command reply .""" 
647+  """A subclass of :exc:`Exception` .""" 
538648 return  self .__reply 
539649
540650
0 commit comments