sensu-plugins-mongodb-mrtrotl 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +27 -0
  5. data/bin/check-mongodb-metric.rb +144 -0
  6. data/bin/check-mongodb-query-count.rb +267 -0
  7. data/bin/check-mongodb.py +1644 -0
  8. data/bin/check-mongodb.rb +5 -0
  9. data/bin/metrics-mongodb-replication.rb +254 -0
  10. data/bin/metrics-mongodb.rb +133 -0
  11. data/lib/bson/__init__.py +1347 -0
  12. data/lib/bson/__pycache__/__init__.cpython-310.pyc +0 -0
  13. data/lib/bson/__pycache__/_helpers.cpython-310.pyc +0 -0
  14. data/lib/bson/__pycache__/binary.cpython-310.pyc +0 -0
  15. data/lib/bson/__pycache__/code.cpython-310.pyc +0 -0
  16. data/lib/bson/__pycache__/codec_options.cpython-310.pyc +0 -0
  17. data/lib/bson/__pycache__/dbref.cpython-310.pyc +0 -0
  18. data/lib/bson/__pycache__/decimal128.cpython-310.pyc +0 -0
  19. data/lib/bson/__pycache__/errors.cpython-310.pyc +0 -0
  20. data/lib/bson/__pycache__/int64.cpython-310.pyc +0 -0
  21. data/lib/bson/__pycache__/json_util.cpython-310.pyc +0 -0
  22. data/lib/bson/__pycache__/max_key.cpython-310.pyc +0 -0
  23. data/lib/bson/__pycache__/min_key.cpython-310.pyc +0 -0
  24. data/lib/bson/__pycache__/objectid.cpython-310.pyc +0 -0
  25. data/lib/bson/__pycache__/raw_bson.cpython-310.pyc +0 -0
  26. data/lib/bson/__pycache__/regex.cpython-310.pyc +0 -0
  27. data/lib/bson/__pycache__/son.cpython-310.pyc +0 -0
  28. data/lib/bson/__pycache__/timestamp.cpython-310.pyc +0 -0
  29. data/lib/bson/__pycache__/tz_util.cpython-310.pyc +0 -0
  30. data/lib/bson/_cbson.cpython-310-x86_64-linux-gnu.so +0 -0
  31. data/lib/bson/_helpers.py +41 -0
  32. data/lib/bson/binary.py +364 -0
  33. data/lib/bson/code.py +101 -0
  34. data/lib/bson/codec_options.py +414 -0
  35. data/lib/bson/codec_options.pyi +100 -0
  36. data/lib/bson/dbref.py +133 -0
  37. data/lib/bson/decimal128.py +314 -0
  38. data/lib/bson/errors.py +35 -0
  39. data/lib/bson/int64.py +39 -0
  40. data/lib/bson/json_util.py +874 -0
  41. data/lib/bson/max_key.py +55 -0
  42. data/lib/bson/min_key.py +55 -0
  43. data/lib/bson/objectid.py +286 -0
  44. data/lib/bson/py.typed +2 -0
  45. data/lib/bson/raw_bson.py +175 -0
  46. data/lib/bson/regex.py +135 -0
  47. data/lib/bson/son.py +208 -0
  48. data/lib/bson/timestamp.py +124 -0
  49. data/lib/bson/tz_util.py +52 -0
  50. data/lib/gridfs/__init__.py +1015 -0
  51. data/lib/gridfs/__pycache__/__init__.cpython-310.pyc +0 -0
  52. data/lib/gridfs/__pycache__/errors.cpython-310.pyc +0 -0
  53. data/lib/gridfs/__pycache__/grid_file.cpython-310.pyc +0 -0
  54. data/lib/gridfs/errors.py +33 -0
  55. data/lib/gridfs/grid_file.py +907 -0
  56. data/lib/gridfs/py.typed +2 -0
  57. data/lib/pymongo/__init__.py +185 -0
  58. data/lib/pymongo/__pycache__/__init__.cpython-310.pyc +0 -0
  59. data/lib/pymongo/__pycache__/_csot.cpython-310.pyc +0 -0
  60. data/lib/pymongo/__pycache__/aggregation.cpython-310.pyc +0 -0
  61. data/lib/pymongo/__pycache__/auth.cpython-310.pyc +0 -0
  62. data/lib/pymongo/__pycache__/auth_aws.cpython-310.pyc +0 -0
  63. data/lib/pymongo/__pycache__/bulk.cpython-310.pyc +0 -0
  64. data/lib/pymongo/__pycache__/change_stream.cpython-310.pyc +0 -0
  65. data/lib/pymongo/__pycache__/client_options.cpython-310.pyc +0 -0
  66. data/lib/pymongo/__pycache__/client_session.cpython-310.pyc +0 -0
  67. data/lib/pymongo/__pycache__/collation.cpython-310.pyc +0 -0
  68. data/lib/pymongo/__pycache__/collection.cpython-310.pyc +0 -0
  69. data/lib/pymongo/__pycache__/command_cursor.cpython-310.pyc +0 -0
  70. data/lib/pymongo/__pycache__/common.cpython-310.pyc +0 -0
  71. data/lib/pymongo/__pycache__/compression_support.cpython-310.pyc +0 -0
  72. data/lib/pymongo/__pycache__/cursor.cpython-310.pyc +0 -0
  73. data/lib/pymongo/__pycache__/daemon.cpython-310.pyc +0 -0
  74. data/lib/pymongo/__pycache__/database.cpython-310.pyc +0 -0
  75. data/lib/pymongo/__pycache__/driver_info.cpython-310.pyc +0 -0
  76. data/lib/pymongo/__pycache__/encryption.cpython-310.pyc +0 -0
  77. data/lib/pymongo/__pycache__/encryption_options.cpython-310.pyc +0 -0
  78. data/lib/pymongo/__pycache__/errors.cpython-310.pyc +0 -0
  79. data/lib/pymongo/__pycache__/event_loggers.cpython-310.pyc +0 -0
  80. data/lib/pymongo/__pycache__/hello.cpython-310.pyc +0 -0
  81. data/lib/pymongo/__pycache__/helpers.cpython-310.pyc +0 -0
  82. data/lib/pymongo/__pycache__/max_staleness_selectors.cpython-310.pyc +0 -0
  83. data/lib/pymongo/__pycache__/message.cpython-310.pyc +0 -0
  84. data/lib/pymongo/__pycache__/mongo_client.cpython-310.pyc +0 -0
  85. data/lib/pymongo/__pycache__/monitor.cpython-310.pyc +0 -0
  86. data/lib/pymongo/__pycache__/monitoring.cpython-310.pyc +0 -0
  87. data/lib/pymongo/__pycache__/network.cpython-310.pyc +0 -0
  88. data/lib/pymongo/__pycache__/ocsp_cache.cpython-310.pyc +0 -0
  89. data/lib/pymongo/__pycache__/ocsp_support.cpython-310.pyc +0 -0
  90. data/lib/pymongo/__pycache__/operations.cpython-310.pyc +0 -0
  91. data/lib/pymongo/__pycache__/periodic_executor.cpython-310.pyc +0 -0
  92. data/lib/pymongo/__pycache__/pool.cpython-310.pyc +0 -0
  93. data/lib/pymongo/__pycache__/pyopenssl_context.cpython-310.pyc +0 -0
  94. data/lib/pymongo/__pycache__/read_concern.cpython-310.pyc +0 -0
  95. data/lib/pymongo/__pycache__/read_preferences.cpython-310.pyc +0 -0
  96. data/lib/pymongo/__pycache__/response.cpython-310.pyc +0 -0
  97. data/lib/pymongo/__pycache__/results.cpython-310.pyc +0 -0
  98. data/lib/pymongo/__pycache__/saslprep.cpython-310.pyc +0 -0
  99. data/lib/pymongo/__pycache__/server.cpython-310.pyc +0 -0
  100. data/lib/pymongo/__pycache__/server_api.cpython-310.pyc +0 -0
  101. data/lib/pymongo/__pycache__/server_description.cpython-310.pyc +0 -0
  102. data/lib/pymongo/__pycache__/server_selectors.cpython-310.pyc +0 -0
  103. data/lib/pymongo/__pycache__/server_type.cpython-310.pyc +0 -0
  104. data/lib/pymongo/__pycache__/settings.cpython-310.pyc +0 -0
  105. data/lib/pymongo/__pycache__/socket_checker.cpython-310.pyc +0 -0
  106. data/lib/pymongo/__pycache__/srv_resolver.cpython-310.pyc +0 -0
  107. data/lib/pymongo/__pycache__/ssl_context.cpython-310.pyc +0 -0
  108. data/lib/pymongo/__pycache__/ssl_support.cpython-310.pyc +0 -0
  109. data/lib/pymongo/__pycache__/topology.cpython-310.pyc +0 -0
  110. data/lib/pymongo/__pycache__/topology_description.cpython-310.pyc +0 -0
  111. data/lib/pymongo/__pycache__/typings.cpython-310.pyc +0 -0
  112. data/lib/pymongo/__pycache__/uri_parser.cpython-310.pyc +0 -0
  113. data/lib/pymongo/__pycache__/write_concern.cpython-310.pyc +0 -0
  114. data/lib/pymongo/_cmessage.cpython-310-x86_64-linux-gnu.so +0 -0
  115. data/lib/pymongo/_csot.py +118 -0
  116. data/lib/pymongo/aggregation.py +229 -0
  117. data/lib/pymongo/auth.py +549 -0
  118. data/lib/pymongo/auth_aws.py +94 -0
  119. data/lib/pymongo/bulk.py +513 -0
  120. data/lib/pymongo/change_stream.py +457 -0
  121. data/lib/pymongo/client_options.py +302 -0
  122. data/lib/pymongo/client_session.py +1112 -0
  123. data/lib/pymongo/collation.py +224 -0
  124. data/lib/pymongo/collection.py +3204 -0
  125. data/lib/pymongo/command_cursor.py +353 -0
  126. data/lib/pymongo/common.py +984 -0
  127. data/lib/pymongo/compression_support.py +149 -0
  128. data/lib/pymongo/cursor.py +1345 -0
  129. data/lib/pymongo/daemon.py +141 -0
  130. data/lib/pymongo/database.py +1202 -0
  131. data/lib/pymongo/driver_info.py +42 -0
  132. data/lib/pymongo/encryption.py +884 -0
  133. data/lib/pymongo/encryption_options.py +221 -0
  134. data/lib/pymongo/errors.py +365 -0
  135. data/lib/pymongo/event_loggers.py +221 -0
  136. data/lib/pymongo/hello.py +219 -0
  137. data/lib/pymongo/helpers.py +259 -0
  138. data/lib/pymongo/max_staleness_selectors.py +114 -0
  139. data/lib/pymongo/message.py +1440 -0
  140. data/lib/pymongo/mongo_client.py +2144 -0
  141. data/lib/pymongo/monitor.py +440 -0
  142. data/lib/pymongo/monitoring.py +1801 -0
  143. data/lib/pymongo/network.py +311 -0
  144. data/lib/pymongo/ocsp_cache.py +87 -0
  145. data/lib/pymongo/ocsp_support.py +372 -0
  146. data/lib/pymongo/operations.py +507 -0
  147. data/lib/pymongo/periodic_executor.py +183 -0
  148. data/lib/pymongo/pool.py +1660 -0
  149. data/lib/pymongo/py.typed +2 -0
  150. data/lib/pymongo/pyopenssl_context.py +383 -0
  151. data/lib/pymongo/read_concern.py +75 -0
  152. data/lib/pymongo/read_preferences.py +609 -0
  153. data/lib/pymongo/response.py +109 -0
  154. data/lib/pymongo/results.py +217 -0
  155. data/lib/pymongo/saslprep.py +113 -0
  156. data/lib/pymongo/server.py +247 -0
  157. data/lib/pymongo/server_api.py +170 -0
  158. data/lib/pymongo/server_description.py +285 -0
  159. data/lib/pymongo/server_selectors.py +153 -0
  160. data/lib/pymongo/server_type.py +32 -0
  161. data/lib/pymongo/settings.py +159 -0
  162. data/lib/pymongo/socket_checker.py +104 -0
  163. data/lib/pymongo/srv_resolver.py +126 -0
  164. data/lib/pymongo/ssl_context.py +39 -0
  165. data/lib/pymongo/ssl_support.py +99 -0
  166. data/lib/pymongo/topology.py +890 -0
  167. data/lib/pymongo/topology_description.py +639 -0
  168. data/lib/pymongo/typings.py +39 -0
  169. data/lib/pymongo/uri_parser.py +624 -0
  170. data/lib/pymongo/write_concern.py +129 -0
  171. data/lib/pymongo-4.2.0.dist-info/INSTALLER +1 -0
  172. data/lib/pymongo-4.2.0.dist-info/LICENSE +201 -0
  173. data/lib/pymongo-4.2.0.dist-info/METADATA +250 -0
  174. data/lib/pymongo-4.2.0.dist-info/RECORD +167 -0
  175. data/lib/pymongo-4.2.0.dist-info/REQUESTED +0 -0
  176. data/lib/pymongo-4.2.0.dist-info/WHEEL +6 -0
  177. data/lib/pymongo-4.2.0.dist-info/top_level.txt +3 -0
  178. data/lib/sensu-plugins-mongodb/metrics.rb +391 -0
  179. data/lib/sensu-plugins-mongodb/version.rb +9 -0
  180. data/lib/sensu-plugins-mongodb.rb +1 -0
  181. metadata +407 -0
@@ -0,0 +1,1801 @@
1
+ # Copyright 2015-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
4
+ # may not use this file except in compliance with the License. You
5
+ # may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ # implied. See the License for the specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ """Tools to monitor driver events.
16
+
17
+ .. versionadded:: 3.1
18
+
19
+ .. attention:: Starting in PyMongo 3.11, the monitoring classes outlined below
20
+ are included in the PyMongo distribution under the
21
+ :mod:`~pymongo.event_loggers` submodule.
22
+
23
+ Use :func:`register` to register global listeners for specific events.
24
+ Listeners must inherit from one of the abstract classes below and implement
25
+ the correct functions for that class.
26
+
27
+ For example, a simple command logger might be implemented like this::
28
+
29
+ import logging
30
+
31
+ from pymongo import monitoring
32
+
33
+ class CommandLogger(monitoring.CommandListener):
34
+
35
+ def started(self, event):
36
+ logging.info("Command {0.command_name} with request id "
37
+ "{0.request_id} started on server "
38
+ "{0.connection_id}".format(event))
39
+
40
+ def succeeded(self, event):
41
+ logging.info("Command {0.command_name} with request id "
42
+ "{0.request_id} on server {0.connection_id} "
43
+ "succeeded in {0.duration_micros} "
44
+ "microseconds".format(event))
45
+
46
+ def failed(self, event):
47
+ logging.info("Command {0.command_name} with request id "
48
+ "{0.request_id} on server {0.connection_id} "
49
+ "failed in {0.duration_micros} "
50
+ "microseconds".format(event))
51
+
52
+ monitoring.register(CommandLogger())
53
+
54
+ Server discovery and monitoring events are also available. For example::
55
+
56
+ class ServerLogger(monitoring.ServerListener):
57
+
58
+ def opened(self, event):
59
+ logging.info("Server {0.server_address} added to topology "
60
+ "{0.topology_id}".format(event))
61
+
62
+ def description_changed(self, event):
63
+ previous_server_type = event.previous_description.server_type
64
+ new_server_type = event.new_description.server_type
65
+ if new_server_type != previous_server_type:
66
+ # server_type_name was added in PyMongo 3.4
67
+ logging.info(
68
+ "Server {0.server_address} changed type from "
69
+ "{0.previous_description.server_type_name} to "
70
+ "{0.new_description.server_type_name}".format(event))
71
+
72
+ def closed(self, event):
73
+ logging.warning("Server {0.server_address} removed from topology "
74
+ "{0.topology_id}".format(event))
75
+
76
+
77
+ class HeartbeatLogger(monitoring.ServerHeartbeatListener):
78
+
79
+ def started(self, event):
80
+ logging.info("Heartbeat sent to server "
81
+ "{0.connection_id}".format(event))
82
+
83
+ def succeeded(self, event):
84
+ # The reply.document attribute was added in PyMongo 3.4.
85
+ logging.info("Heartbeat to server {0.connection_id} "
86
+ "succeeded with reply "
87
+ "{0.reply.document}".format(event))
88
+
89
+ def failed(self, event):
90
+ logging.warning("Heartbeat to server {0.connection_id} "
91
+ "failed with error {0.reply}".format(event))
92
+
93
+ class TopologyLogger(monitoring.TopologyListener):
94
+
95
+ def opened(self, event):
96
+ logging.info("Topology with id {0.topology_id} "
97
+ "opened".format(event))
98
+
99
+ def description_changed(self, event):
100
+ logging.info("Topology description updated for "
101
+ "topology id {0.topology_id}".format(event))
102
+ previous_topology_type = event.previous_description.topology_type
103
+ new_topology_type = event.new_description.topology_type
104
+ if new_topology_type != previous_topology_type:
105
+ # topology_type_name was added in PyMongo 3.4
106
+ logging.info(
107
+ "Topology {0.topology_id} changed type from "
108
+ "{0.previous_description.topology_type_name} to "
109
+ "{0.new_description.topology_type_name}".format(event))
110
+ # The has_writable_server and has_readable_server methods
111
+ # were added in PyMongo 3.4.
112
+ if not event.new_description.has_writable_server():
113
+ logging.warning("No writable servers available.")
114
+ if not event.new_description.has_readable_server():
115
+ logging.warning("No readable servers available.")
116
+
117
+ def closed(self, event):
118
+ logging.info("Topology with id {0.topology_id} "
119
+ "closed".format(event))
120
+
121
+ Connection monitoring and pooling events are also available. For example::
122
+
123
+ class ConnectionPoolLogger(ConnectionPoolListener):
124
+
125
+ def pool_created(self, event):
126
+ logging.info("[pool {0.address}] pool created".format(event))
127
+
128
+ def pool_cleared(self, event):
129
+ logging.info("[pool {0.address}] pool cleared".format(event))
130
+
131
+ def pool_closed(self, event):
132
+ logging.info("[pool {0.address}] pool closed".format(event))
133
+
134
+ def connection_created(self, event):
135
+ logging.info("[pool {0.address}][conn #{0.connection_id}] "
136
+ "connection created".format(event))
137
+
138
+ def connection_ready(self, event):
139
+ logging.info("[pool {0.address}][conn #{0.connection_id}] "
140
+ "connection setup succeeded".format(event))
141
+
142
+ def connection_closed(self, event):
143
+ logging.info("[pool {0.address}][conn #{0.connection_id}] "
144
+ "connection closed, reason: "
145
+ "{0.reason}".format(event))
146
+
147
+ def connection_check_out_started(self, event):
148
+ logging.info("[pool {0.address}] connection check out "
149
+ "started".format(event))
150
+
151
+ def connection_check_out_failed(self, event):
152
+ logging.info("[pool {0.address}] connection check out "
153
+ "failed, reason: {0.reason}".format(event))
154
+
155
+ def connection_checked_out(self, event):
156
+ logging.info("[pool {0.address}][conn #{0.connection_id}] "
157
+ "connection checked out of pool".format(event))
158
+
159
+ def connection_checked_in(self, event):
160
+ logging.info("[pool {0.address}][conn #{0.connection_id}] "
161
+ "connection checked into pool".format(event))
162
+
163
+
164
+ Event listeners can also be registered per instance of
165
+ :class:`~pymongo.mongo_client.MongoClient`::
166
+
167
+ client = MongoClient(event_listeners=[CommandLogger()])
168
+
169
+ Note that previously registered global listeners are automatically included
170
+ when configuring per client event listeners. Registering a new global listener
171
+ will not add that listener to existing client instances.
172
+
173
+ .. note:: Events are delivered **synchronously**. Application threads block
174
+ waiting for event handlers (e.g. :meth:`~CommandListener.started`) to
175
+ return. Care must be taken to ensure that your event handlers are efficient
176
+ enough to not adversely affect overall application performance.
177
+
178
+ .. warning:: The command documents published through this API are *not* copies.
179
+ If you intend to modify them in any way you must copy them in your event
180
+ handler first.
181
+ """
182
+
183
+ import datetime
184
+ from collections import abc, namedtuple
185
+ from typing import TYPE_CHECKING, Any, Dict, Optional
186
+
187
+ from bson.objectid import ObjectId
188
+ from pymongo.hello import Hello, HelloCompat
189
+ from pymongo.helpers import _handle_exception
190
+ from pymongo.typings import _Address, _DocumentOut
191
+
192
+ if TYPE_CHECKING:
193
+ from pymongo.server_description import ServerDescription
194
+ from pymongo.topology_description import TopologyDescription
195
+
196
+
197
+ _Listeners = namedtuple(
198
+ "_Listeners",
199
+ (
200
+ "command_listeners",
201
+ "server_listeners",
202
+ "server_heartbeat_listeners",
203
+ "topology_listeners",
204
+ "cmap_listeners",
205
+ ),
206
+ )
207
+
208
+ _LISTENERS = _Listeners([], [], [], [], [])
209
+
210
+
211
+ class _EventListener(object):
212
+ """Abstract base class for all event listeners."""
213
+
214
+
215
+ class CommandListener(_EventListener):
216
+ """Abstract base class for command listeners.
217
+
218
+ Handles `CommandStartedEvent`, `CommandSucceededEvent`,
219
+ and `CommandFailedEvent`.
220
+ """
221
+
222
+ def started(self, event: "CommandStartedEvent") -> None:
223
+ """Abstract method to handle a `CommandStartedEvent`.
224
+
225
+ :Parameters:
226
+ - `event`: An instance of :class:`CommandStartedEvent`.
227
+ """
228
+ raise NotImplementedError
229
+
230
+ def succeeded(self, event: "CommandSucceededEvent") -> None:
231
+ """Abstract method to handle a `CommandSucceededEvent`.
232
+
233
+ :Parameters:
234
+ - `event`: An instance of :class:`CommandSucceededEvent`.
235
+ """
236
+ raise NotImplementedError
237
+
238
+ def failed(self, event: "CommandFailedEvent") -> None:
239
+ """Abstract method to handle a `CommandFailedEvent`.
240
+
241
+ :Parameters:
242
+ - `event`: An instance of :class:`CommandFailedEvent`.
243
+ """
244
+ raise NotImplementedError
245
+
246
+
247
+ class ConnectionPoolListener(_EventListener):
248
+ """Abstract base class for connection pool listeners.
249
+
250
+ Handles all of the connection pool events defined in the Connection
251
+ Monitoring and Pooling Specification:
252
+ :class:`PoolCreatedEvent`, :class:`PoolClearedEvent`,
253
+ :class:`PoolClosedEvent`, :class:`ConnectionCreatedEvent`,
254
+ :class:`ConnectionReadyEvent`, :class:`ConnectionClosedEvent`,
255
+ :class:`ConnectionCheckOutStartedEvent`,
256
+ :class:`ConnectionCheckOutFailedEvent`,
257
+ :class:`ConnectionCheckedOutEvent`,
258
+ and :class:`ConnectionCheckedInEvent`.
259
+
260
+ .. versionadded:: 3.9
261
+ """
262
+
263
+ def pool_created(self, event: "PoolCreatedEvent") -> None:
264
+ """Abstract method to handle a :class:`PoolCreatedEvent`.
265
+
266
+ Emitted when a Connection Pool is created.
267
+
268
+ :Parameters:
269
+ - `event`: An instance of :class:`PoolCreatedEvent`.
270
+ """
271
+ raise NotImplementedError
272
+
273
+ def pool_ready(self, event: "PoolReadyEvent") -> None:
274
+ """Abstract method to handle a :class:`PoolReadyEvent`.
275
+
276
+ Emitted when a Connection Pool is marked ready.
277
+
278
+ :Parameters:
279
+ - `event`: An instance of :class:`PoolReadyEvent`.
280
+
281
+ .. versionadded:: 4.0
282
+ """
283
+ raise NotImplementedError
284
+
285
+ def pool_cleared(self, event: "PoolClearedEvent") -> None:
286
+ """Abstract method to handle a `PoolClearedEvent`.
287
+
288
+ Emitted when a Connection Pool is cleared.
289
+
290
+ :Parameters:
291
+ - `event`: An instance of :class:`PoolClearedEvent`.
292
+ """
293
+ raise NotImplementedError
294
+
295
+ def pool_closed(self, event: "PoolClosedEvent") -> None:
296
+ """Abstract method to handle a `PoolClosedEvent`.
297
+
298
+ Emitted when a Connection Pool is closed.
299
+
300
+ :Parameters:
301
+ - `event`: An instance of :class:`PoolClosedEvent`.
302
+ """
303
+ raise NotImplementedError
304
+
305
+ def connection_created(self, event: "ConnectionCreatedEvent") -> None:
306
+ """Abstract method to handle a :class:`ConnectionCreatedEvent`.
307
+
308
+ Emitted when a Connection Pool creates a Connection object.
309
+
310
+ :Parameters:
311
+ - `event`: An instance of :class:`ConnectionCreatedEvent`.
312
+ """
313
+ raise NotImplementedError
314
+
315
+ def connection_ready(self, event: "ConnectionReadyEvent") -> None:
316
+ """Abstract method to handle a :class:`ConnectionReadyEvent`.
317
+
318
+ Emitted when a Connection has finished its setup, and is now ready to
319
+ use.
320
+
321
+ :Parameters:
322
+ - `event`: An instance of :class:`ConnectionReadyEvent`.
323
+ """
324
+ raise NotImplementedError
325
+
326
+ def connection_closed(self, event: "ConnectionClosedEvent") -> None:
327
+ """Abstract method to handle a :class:`ConnectionClosedEvent`.
328
+
329
+ Emitted when a Connection Pool closes a Connection.
330
+
331
+ :Parameters:
332
+ - `event`: An instance of :class:`ConnectionClosedEvent`.
333
+ """
334
+ raise NotImplementedError
335
+
336
+ def connection_check_out_started(self, event: "ConnectionCheckOutStartedEvent") -> None:
337
+ """Abstract method to handle a :class:`ConnectionCheckOutStartedEvent`.
338
+
339
+ Emitted when the driver starts attempting to check out a connection.
340
+
341
+ :Parameters:
342
+ - `event`: An instance of :class:`ConnectionCheckOutStartedEvent`.
343
+ """
344
+ raise NotImplementedError
345
+
346
+ def connection_check_out_failed(self, event: "ConnectionCheckOutFailedEvent") -> None:
347
+ """Abstract method to handle a :class:`ConnectionCheckOutFailedEvent`.
348
+
349
+ Emitted when the driver's attempt to check out a connection fails.
350
+
351
+ :Parameters:
352
+ - `event`: An instance of :class:`ConnectionCheckOutFailedEvent`.
353
+ """
354
+ raise NotImplementedError
355
+
356
+ def connection_checked_out(self, event: "ConnectionCheckedOutEvent") -> None:
357
+ """Abstract method to handle a :class:`ConnectionCheckedOutEvent`.
358
+
359
+ Emitted when the driver successfully checks out a Connection.
360
+
361
+ :Parameters:
362
+ - `event`: An instance of :class:`ConnectionCheckedOutEvent`.
363
+ """
364
+ raise NotImplementedError
365
+
366
+ def connection_checked_in(self, event: "ConnectionCheckedInEvent") -> None:
367
+ """Abstract method to handle a :class:`ConnectionCheckedInEvent`.
368
+
369
+ Emitted when the driver checks in a Connection back to the Connection
370
+ Pool.
371
+
372
+ :Parameters:
373
+ - `event`: An instance of :class:`ConnectionCheckedInEvent`.
374
+ """
375
+ raise NotImplementedError
376
+
377
+
378
+ class ServerHeartbeatListener(_EventListener):
379
+ """Abstract base class for server heartbeat listeners.
380
+
381
+ Handles `ServerHeartbeatStartedEvent`, `ServerHeartbeatSucceededEvent`,
382
+ and `ServerHeartbeatFailedEvent`.
383
+
384
+ .. versionadded:: 3.3
385
+ """
386
+
387
+ def started(self, event: "ServerHeartbeatStartedEvent") -> None:
388
+ """Abstract method to handle a `ServerHeartbeatStartedEvent`.
389
+
390
+ :Parameters:
391
+ - `event`: An instance of :class:`ServerHeartbeatStartedEvent`.
392
+ """
393
+ raise NotImplementedError
394
+
395
+ def succeeded(self, event: "ServerHeartbeatSucceededEvent") -> None:
396
+ """Abstract method to handle a `ServerHeartbeatSucceededEvent`.
397
+
398
+ :Parameters:
399
+ - `event`: An instance of :class:`ServerHeartbeatSucceededEvent`.
400
+ """
401
+ raise NotImplementedError
402
+
403
+ def failed(self, event: "ServerHeartbeatFailedEvent") -> None:
404
+ """Abstract method to handle a `ServerHeartbeatFailedEvent`.
405
+
406
+ :Parameters:
407
+ - `event`: An instance of :class:`ServerHeartbeatFailedEvent`.
408
+ """
409
+ raise NotImplementedError
410
+
411
+
412
+ class TopologyListener(_EventListener):
413
+ """Abstract base class for topology monitoring listeners.
414
+ Handles `TopologyOpenedEvent`, `TopologyDescriptionChangedEvent`, and
415
+ `TopologyClosedEvent`.
416
+
417
+ .. versionadded:: 3.3
418
+ """
419
+
420
+ def opened(self, event: "TopologyOpenedEvent") -> None:
421
+ """Abstract method to handle a `TopologyOpenedEvent`.
422
+
423
+ :Parameters:
424
+ - `event`: An instance of :class:`TopologyOpenedEvent`.
425
+ """
426
+ raise NotImplementedError
427
+
428
+ def description_changed(self, event: "TopologyDescriptionChangedEvent") -> None:
429
+ """Abstract method to handle a `TopologyDescriptionChangedEvent`.
430
+
431
+ :Parameters:
432
+ - `event`: An instance of :class:`TopologyDescriptionChangedEvent`.
433
+ """
434
+ raise NotImplementedError
435
+
436
+ def closed(self, event: "TopologyClosedEvent") -> None:
437
+ """Abstract method to handle a `TopologyClosedEvent`.
438
+
439
+ :Parameters:
440
+ - `event`: An instance of :class:`TopologyClosedEvent`.
441
+ """
442
+ raise NotImplementedError
443
+
444
+
445
+ class ServerListener(_EventListener):
446
+ """Abstract base class for server listeners.
447
+ Handles `ServerOpeningEvent`, `ServerDescriptionChangedEvent`, and
448
+ `ServerClosedEvent`.
449
+
450
+ .. versionadded:: 3.3
451
+ """
452
+
453
+ def opened(self, event: "ServerOpeningEvent") -> None:
454
+ """Abstract method to handle a `ServerOpeningEvent`.
455
+
456
+ :Parameters:
457
+ - `event`: An instance of :class:`ServerOpeningEvent`.
458
+ """
459
+ raise NotImplementedError
460
+
461
+ def description_changed(self, event: "ServerDescriptionChangedEvent") -> None:
462
+ """Abstract method to handle a `ServerDescriptionChangedEvent`.
463
+
464
+ :Parameters:
465
+ - `event`: An instance of :class:`ServerDescriptionChangedEvent`.
466
+ """
467
+ raise NotImplementedError
468
+
469
+ def closed(self, event: "ServerClosedEvent") -> None:
470
+ """Abstract method to handle a `ServerClosedEvent`.
471
+
472
+ :Parameters:
473
+ - `event`: An instance of :class:`ServerClosedEvent`.
474
+ """
475
+ raise NotImplementedError
476
+
477
+
478
+ def _to_micros(dur):
479
+ """Convert duration 'dur' to microseconds."""
480
+ return int(dur.total_seconds() * 10e5)
481
+
482
+
483
+ def _validate_event_listeners(option, listeners):
484
+ """Validate event listeners"""
485
+ if not isinstance(listeners, abc.Sequence):
486
+ raise TypeError("%s must be a list or tuple" % (option,))
487
+ for listener in listeners:
488
+ if not isinstance(listener, _EventListener):
489
+ raise TypeError(
490
+ "Listeners for %s must be either a "
491
+ "CommandListener, ServerHeartbeatListener, "
492
+ "ServerListener, TopologyListener, or "
493
+ "ConnectionPoolListener." % (option,)
494
+ )
495
+ return listeners
496
+
497
+
498
+ def register(listener: _EventListener) -> None:
499
+ """Register a global event listener.
500
+
501
+ :Parameters:
502
+ - `listener`: A subclasses of :class:`CommandListener`,
503
+ :class:`ServerHeartbeatListener`, :class:`ServerListener`,
504
+ :class:`TopologyListener`, or :class:`ConnectionPoolListener`.
505
+ """
506
+ if not isinstance(listener, _EventListener):
507
+ raise TypeError(
508
+ "Listeners for %s must be either a "
509
+ "CommandListener, ServerHeartbeatListener, "
510
+ "ServerListener, TopologyListener, or "
511
+ "ConnectionPoolListener." % (listener,)
512
+ )
513
+ if isinstance(listener, CommandListener):
514
+ _LISTENERS.command_listeners.append(listener)
515
+ if isinstance(listener, ServerHeartbeatListener):
516
+ _LISTENERS.server_heartbeat_listeners.append(listener)
517
+ if isinstance(listener, ServerListener):
518
+ _LISTENERS.server_listeners.append(listener)
519
+ if isinstance(listener, TopologyListener):
520
+ _LISTENERS.topology_listeners.append(listener)
521
+ if isinstance(listener, ConnectionPoolListener):
522
+ _LISTENERS.cmap_listeners.append(listener)
523
+
524
+
525
+ # Note - to avoid bugs from forgetting which if these is all lowercase and
526
+ # which are camelCase, and at the same time avoid having to add a test for
527
+ # every command, use all lowercase here and test against command_name.lower().
528
+ _SENSITIVE_COMMANDS = set(
529
+ [
530
+ "authenticate",
531
+ "saslstart",
532
+ "saslcontinue",
533
+ "getnonce",
534
+ "createuser",
535
+ "updateuser",
536
+ "copydbgetnonce",
537
+ "copydbsaslstart",
538
+ "copydb",
539
+ ]
540
+ )
541
+
542
+
543
+ # The "hello" command is also deemed sensitive when attempting speculative
544
+ # authentication.
545
+ def _is_speculative_authenticate(command_name, doc):
546
+ if (
547
+ command_name.lower() in ("hello", HelloCompat.LEGACY_CMD)
548
+ and "speculativeAuthenticate" in doc
549
+ ):
550
+ return True
551
+ return False
552
+
553
+
554
+ class _CommandEvent(object):
555
+ """Base class for command events."""
556
+
557
+ __slots__ = ("__cmd_name", "__rqst_id", "__conn_id", "__op_id", "__service_id")
558
+
559
+ def __init__(
560
+ self,
561
+ command_name: str,
562
+ request_id: int,
563
+ connection_id: _Address,
564
+ operation_id: Optional[int],
565
+ service_id: Optional[ObjectId] = None,
566
+ ) -> None:
567
+ self.__cmd_name = command_name
568
+ self.__rqst_id = request_id
569
+ self.__conn_id = connection_id
570
+ self.__op_id = operation_id
571
+ self.__service_id = service_id
572
+
573
+ @property
574
+ def command_name(self) -> str:
575
+ """The command name."""
576
+ return self.__cmd_name
577
+
578
+ @property
579
+ def request_id(self) -> int:
580
+ """The request id for this operation."""
581
+ return self.__rqst_id
582
+
583
+ @property
584
+ def connection_id(self) -> _Address:
585
+ """The address (host, port) of the server this command was sent to."""
586
+ return self.__conn_id
587
+
588
+ @property
589
+ def service_id(self) -> Optional[ObjectId]:
590
+ """The service_id this command was sent to, or ``None``.
591
+
592
+ .. versionadded:: 3.12
593
+ """
594
+ return self.__service_id
595
+
596
+ @property
597
+ def operation_id(self) -> Optional[int]:
598
+ """An id for this series of events or None."""
599
+ return self.__op_id
600
+
601
+
602
+ class CommandStartedEvent(_CommandEvent):
603
+ """Event published when a command starts.
604
+
605
+ :Parameters:
606
+ - `command`: The command document.
607
+ - `database_name`: The name of the database this command was run against.
608
+ - `request_id`: The request id for this operation.
609
+ - `connection_id`: The address (host, port) of the server this command
610
+ was sent to.
611
+ - `operation_id`: An optional identifier for a series of related events.
612
+ - `service_id`: The service_id this command was sent to, or ``None``.
613
+ """
614
+
615
+ __slots__ = ("__cmd", "__db")
616
+
617
+ def __init__(
618
+ self,
619
+ command: _DocumentOut,
620
+ database_name: str,
621
+ request_id: int,
622
+ connection_id: _Address,
623
+ operation_id: Optional[int],
624
+ service_id: Optional[ObjectId] = None,
625
+ ) -> None:
626
+ if not command:
627
+ raise ValueError("%r is not a valid command" % (command,))
628
+ # Command name must be first key.
629
+ command_name = next(iter(command))
630
+ super(CommandStartedEvent, self).__init__(
631
+ command_name, request_id, connection_id, operation_id, service_id=service_id
632
+ )
633
+ cmd_name = command_name.lower()
634
+ if cmd_name in _SENSITIVE_COMMANDS or _is_speculative_authenticate(cmd_name, command):
635
+ self.__cmd: _DocumentOut = {}
636
+ else:
637
+ self.__cmd = command
638
+ self.__db = database_name
639
+
640
+ @property
641
+ def command(self) -> _DocumentOut:
642
+ """The command document."""
643
+ return self.__cmd
644
+
645
+ @property
646
+ def database_name(self) -> str:
647
+ """The name of the database this command was run against."""
648
+ return self.__db
649
+
650
+ def __repr__(self):
651
+ return ("<%s %s db: %r, command: %r, operation_id: %s, service_id: %s>") % (
652
+ self.__class__.__name__,
653
+ self.connection_id,
654
+ self.database_name,
655
+ self.command_name,
656
+ self.operation_id,
657
+ self.service_id,
658
+ )
659
+
660
+
661
+ class CommandSucceededEvent(_CommandEvent):
662
+ """Event published when a command succeeds.
663
+
664
+ :Parameters:
665
+ - `duration`: The command duration as a datetime.timedelta.
666
+ - `reply`: The server reply document.
667
+ - `command_name`: The command name.
668
+ - `request_id`: The request id for this operation.
669
+ - `connection_id`: The address (host, port) of the server this command
670
+ was sent to.
671
+ - `operation_id`: An optional identifier for a series of related events.
672
+ - `service_id`: The service_id this command was sent to, or ``None``.
673
+ """
674
+
675
+ __slots__ = ("__duration_micros", "__reply")
676
+
677
+ def __init__(
678
+ self,
679
+ duration: datetime.timedelta,
680
+ reply: _DocumentOut,
681
+ command_name: str,
682
+ request_id: int,
683
+ connection_id: _Address,
684
+ operation_id: Optional[int],
685
+ service_id: Optional[ObjectId] = None,
686
+ ) -> None:
687
+ super(CommandSucceededEvent, self).__init__(
688
+ command_name, request_id, connection_id, operation_id, service_id=service_id
689
+ )
690
+ self.__duration_micros = _to_micros(duration)
691
+ cmd_name = command_name.lower()
692
+ if cmd_name in _SENSITIVE_COMMANDS or _is_speculative_authenticate(cmd_name, reply):
693
+ self.__reply: _DocumentOut = {}
694
+ else:
695
+ self.__reply = reply
696
+
697
+ @property
698
+ def duration_micros(self) -> int:
699
+ """The duration of this operation in microseconds."""
700
+ return self.__duration_micros
701
+
702
+ @property
703
+ def reply(self) -> _DocumentOut:
704
+ """The server failure document for this operation."""
705
+ return self.__reply
706
+
707
+ def __repr__(self):
708
+ return ("<%s %s command: %r, operation_id: %s, duration_micros: %s, service_id: %s>") % (
709
+ self.__class__.__name__,
710
+ self.connection_id,
711
+ self.command_name,
712
+ self.operation_id,
713
+ self.duration_micros,
714
+ self.service_id,
715
+ )
716
+
717
+
718
+ class CommandFailedEvent(_CommandEvent):
719
+ """Event published when a command fails.
720
+
721
+ :Parameters:
722
+ - `duration`: The command duration as a datetime.timedelta.
723
+ - `failure`: The server reply document.
724
+ - `command_name`: The command name.
725
+ - `request_id`: The request id for this operation.
726
+ - `connection_id`: The address (host, port) of the server this command
727
+ was sent to.
728
+ - `operation_id`: An optional identifier for a series of related events.
729
+ - `service_id`: The service_id this command was sent to, or ``None``.
730
+ """
731
+
732
+ __slots__ = ("__duration_micros", "__failure")
733
+
734
+ def __init__(
735
+ self,
736
+ duration: datetime.timedelta,
737
+ failure: _DocumentOut,
738
+ command_name: str,
739
+ request_id: int,
740
+ connection_id: _Address,
741
+ operation_id: Optional[int],
742
+ service_id: Optional[ObjectId] = None,
743
+ ) -> None:
744
+ super(CommandFailedEvent, self).__init__(
745
+ command_name, request_id, connection_id, operation_id, service_id=service_id
746
+ )
747
+ self.__duration_micros = _to_micros(duration)
748
+ self.__failure = failure
749
+
750
+ @property
751
+ def duration_micros(self) -> int:
752
+ """The duration of this operation in microseconds."""
753
+ return self.__duration_micros
754
+
755
+ @property
756
+ def failure(self) -> _DocumentOut:
757
+ """The server failure document for this operation."""
758
+ return self.__failure
759
+
760
+ def __repr__(self):
761
+ return (
762
+ "<%s %s command: %r, operation_id: %s, duration_micros: %s, "
763
+ "failure: %r, service_id: %s>"
764
+ ) % (
765
+ self.__class__.__name__,
766
+ self.connection_id,
767
+ self.command_name,
768
+ self.operation_id,
769
+ self.duration_micros,
770
+ self.failure,
771
+ self.service_id,
772
+ )
773
+
774
+
775
+ class _PoolEvent(object):
776
+ """Base class for pool events."""
777
+
778
+ __slots__ = ("__address",)
779
+
780
+ def __init__(self, address: _Address) -> None:
781
+ self.__address = address
782
+
783
+ @property
784
+ def address(self) -> _Address:
785
+ """The address (host, port) pair of the server the pool is attempting
786
+ to connect to.
787
+ """
788
+ return self.__address
789
+
790
+ def __repr__(self):
791
+ return "%s(%r)" % (self.__class__.__name__, self.__address)
792
+
793
+
794
+ class PoolCreatedEvent(_PoolEvent):
795
+ """Published when a Connection Pool is created.
796
+
797
+ :Parameters:
798
+ - `address`: The address (host, port) pair of the server this Pool is
799
+ attempting to connect to.
800
+
801
+ .. versionadded:: 3.9
802
+ """
803
+
804
+ __slots__ = ("__options",)
805
+
806
+ def __init__(self, address: _Address, options: Dict[str, Any]) -> None:
807
+ super(PoolCreatedEvent, self).__init__(address)
808
+ self.__options = options
809
+
810
+ @property
811
+ def options(self) -> Dict[str, Any]:
812
+ """Any non-default pool options that were set on this Connection Pool."""
813
+ return self.__options
814
+
815
+ def __repr__(self):
816
+ return "%s(%r, %r)" % (self.__class__.__name__, self.address, self.__options)
817
+
818
+
819
+ class PoolReadyEvent(_PoolEvent):
820
+ """Published when a Connection Pool is marked ready.
821
+
822
+ :Parameters:
823
+ - `address`: The address (host, port) pair of the server this Pool is
824
+ attempting to connect to.
825
+
826
+ .. versionadded:: 4.0
827
+ """
828
+
829
+ __slots__ = ()
830
+
831
+
832
+ class PoolClearedEvent(_PoolEvent):
833
+ """Published when a Connection Pool is cleared.
834
+
835
+ :Parameters:
836
+ - `address`: The address (host, port) pair of the server this Pool is
837
+ attempting to connect to.
838
+ - `service_id`: The service_id this command was sent to, or ``None``.
839
+
840
+ .. versionadded:: 3.9
841
+ """
842
+
843
+ __slots__ = ("__service_id",)
844
+
845
+ def __init__(self, address: _Address, service_id: Optional[ObjectId] = None) -> None:
846
+ super(PoolClearedEvent, self).__init__(address)
847
+ self.__service_id = service_id
848
+
849
+ @property
850
+ def service_id(self) -> Optional[ObjectId]:
851
+ """Connections with this service_id are cleared.
852
+
853
+ When service_id is ``None``, all connections in the pool are cleared.
854
+
855
+ .. versionadded:: 3.12
856
+ """
857
+ return self.__service_id
858
+
859
+ def __repr__(self):
860
+ return "%s(%r, %r)" % (self.__class__.__name__, self.address, self.__service_id)
861
+
862
+
863
+ class PoolClosedEvent(_PoolEvent):
864
+ """Published when a Connection Pool is closed.
865
+
866
+ :Parameters:
867
+ - `address`: The address (host, port) pair of the server this Pool is
868
+ attempting to connect to.
869
+
870
+ .. versionadded:: 3.9
871
+ """
872
+
873
+ __slots__ = ()
874
+
875
+
876
+ class ConnectionClosedReason(object):
877
+ """An enum that defines values for `reason` on a
878
+ :class:`ConnectionClosedEvent`.
879
+
880
+ .. versionadded:: 3.9
881
+ """
882
+
883
+ STALE = "stale"
884
+ """The pool was cleared, making the connection no longer valid."""
885
+
886
+ IDLE = "idle"
887
+ """The connection became stale by being idle for too long (maxIdleTimeMS).
888
+ """
889
+
890
+ ERROR = "error"
891
+ """The connection experienced an error, making it no longer valid."""
892
+
893
+ POOL_CLOSED = "poolClosed"
894
+ """The pool was closed, making the connection no longer valid."""
895
+
896
+
897
+ class ConnectionCheckOutFailedReason(object):
898
+ """An enum that defines values for `reason` on a
899
+ :class:`ConnectionCheckOutFailedEvent`.
900
+
901
+ .. versionadded:: 3.9
902
+ """
903
+
904
+ TIMEOUT = "timeout"
905
+ """The connection check out attempt exceeded the specified timeout."""
906
+
907
+ POOL_CLOSED = "poolClosed"
908
+ """The pool was previously closed, and cannot provide new connections."""
909
+
910
+ CONN_ERROR = "connectionError"
911
+ """The connection check out attempt experienced an error while setting up
912
+ a new connection.
913
+ """
914
+
915
+
916
+ class _ConnectionEvent(object):
917
+ """Private base class for some connection events."""
918
+
919
+ __slots__ = ("__address", "__connection_id")
920
+
921
+ def __init__(self, address: _Address, connection_id: int) -> None:
922
+ self.__address = address
923
+ self.__connection_id = connection_id
924
+
925
+ @property
926
+ def address(self) -> _Address:
927
+ """The address (host, port) pair of the server this connection is
928
+ attempting to connect to.
929
+ """
930
+ return self.__address
931
+
932
+ @property
933
+ def connection_id(self) -> int:
934
+ """The ID of the Connection."""
935
+ return self.__connection_id
936
+
937
+ def __repr__(self):
938
+ return "%s(%r, %r)" % (self.__class__.__name__, self.__address, self.__connection_id)
939
+
940
+
941
+ class ConnectionCreatedEvent(_ConnectionEvent):
942
+ """Published when a Connection Pool creates a Connection object.
943
+
944
+ NOTE: This connection is not ready for use until the
945
+ :class:`ConnectionReadyEvent` is published.
946
+
947
+ :Parameters:
948
+ - `address`: The address (host, port) pair of the server this
949
+ Connection is attempting to connect to.
950
+ - `connection_id`: The integer ID of the Connection in this Pool.
951
+
952
+ .. versionadded:: 3.9
953
+ """
954
+
955
+ __slots__ = ()
956
+
957
+
958
+ class ConnectionReadyEvent(_ConnectionEvent):
959
+ """Published when a Connection has finished its setup, and is ready to use.
960
+
961
+ :Parameters:
962
+ - `address`: The address (host, port) pair of the server this
963
+ Connection is attempting to connect to.
964
+ - `connection_id`: The integer ID of the Connection in this Pool.
965
+
966
+ .. versionadded:: 3.9
967
+ """
968
+
969
+ __slots__ = ()
970
+
971
+
972
+ class ConnectionClosedEvent(_ConnectionEvent):
973
+ """Published when a Connection is closed.
974
+
975
+ :Parameters:
976
+ - `address`: The address (host, port) pair of the server this
977
+ Connection is attempting to connect to.
978
+ - `connection_id`: The integer ID of the Connection in this Pool.
979
+ - `reason`: A reason explaining why this connection was closed.
980
+
981
+ .. versionadded:: 3.9
982
+ """
983
+
984
+ __slots__ = ("__reason",)
985
+
986
+ def __init__(self, address, connection_id, reason):
987
+ super(ConnectionClosedEvent, self).__init__(address, connection_id)
988
+ self.__reason = reason
989
+
990
+ @property
991
+ def reason(self):
992
+ """A reason explaining why this connection was closed.
993
+
994
+ The reason must be one of the strings from the
995
+ :class:`ConnectionClosedReason` enum.
996
+ """
997
+ return self.__reason
998
+
999
+ def __repr__(self):
1000
+ return "%s(%r, %r, %r)" % (
1001
+ self.__class__.__name__,
1002
+ self.address,
1003
+ self.connection_id,
1004
+ self.__reason,
1005
+ )
1006
+
1007
+
1008
+ class ConnectionCheckOutStartedEvent(object):
1009
+ """Published when the driver starts attempting to check out a connection.
1010
+
1011
+ :Parameters:
1012
+ - `address`: The address (host, port) pair of the server this
1013
+ Connection is attempting to connect to.
1014
+
1015
+ .. versionadded:: 3.9
1016
+ """
1017
+
1018
+ __slots__ = ("__address",)
1019
+
1020
+ def __init__(self, address):
1021
+ self.__address = address
1022
+
1023
+ @property
1024
+ def address(self):
1025
+ """The address (host, port) pair of the server this connection is
1026
+ attempting to connect to.
1027
+ """
1028
+ return self.__address
1029
+
1030
+ def __repr__(self):
1031
+ return "%s(%r)" % (self.__class__.__name__, self.__address)
1032
+
1033
+
1034
+ class ConnectionCheckOutFailedEvent(object):
1035
+ """Published when the driver's attempt to check out a connection fails.
1036
+
1037
+ :Parameters:
1038
+ - `address`: The address (host, port) pair of the server this
1039
+ Connection is attempting to connect to.
1040
+ - `reason`: A reason explaining why connection check out failed.
1041
+
1042
+ .. versionadded:: 3.9
1043
+ """
1044
+
1045
+ __slots__ = ("__address", "__reason")
1046
+
1047
+ def __init__(self, address: _Address, reason: str) -> None:
1048
+ self.__address = address
1049
+ self.__reason = reason
1050
+
1051
+ @property
1052
+ def address(self) -> _Address:
1053
+ """The address (host, port) pair of the server this connection is
1054
+ attempting to connect to.
1055
+ """
1056
+ return self.__address
1057
+
1058
+ @property
1059
+ def reason(self) -> str:
1060
+ """A reason explaining why connection check out failed.
1061
+
1062
+ The reason must be one of the strings from the
1063
+ :class:`ConnectionCheckOutFailedReason` enum.
1064
+ """
1065
+ return self.__reason
1066
+
1067
+ def __repr__(self):
1068
+ return "%s(%r, %r)" % (self.__class__.__name__, self.__address, self.__reason)
1069
+
1070
+
1071
+ class ConnectionCheckedOutEvent(_ConnectionEvent):
1072
+ """Published when the driver successfully checks out a Connection.
1073
+
1074
+ :Parameters:
1075
+ - `address`: The address (host, port) pair of the server this
1076
+ Connection is attempting to connect to.
1077
+ - `connection_id`: The integer ID of the Connection in this Pool.
1078
+
1079
+ .. versionadded:: 3.9
1080
+ """
1081
+
1082
+ __slots__ = ()
1083
+
1084
+
1085
+ class ConnectionCheckedInEvent(_ConnectionEvent):
1086
+ """Published when the driver checks in a Connection into the Pool.
1087
+
1088
+ :Parameters:
1089
+ - `address`: The address (host, port) pair of the server this
1090
+ Connection is attempting to connect to.
1091
+ - `connection_id`: The integer ID of the Connection in this Pool.
1092
+
1093
+ .. versionadded:: 3.9
1094
+ """
1095
+
1096
+ __slots__ = ()
1097
+
1098
+
1099
+ class _ServerEvent(object):
1100
+ """Base class for server events."""
1101
+
1102
+ __slots__ = ("__server_address", "__topology_id")
1103
+
1104
+ def __init__(self, server_address: _Address, topology_id: ObjectId) -> None:
1105
+ self.__server_address = server_address
1106
+ self.__topology_id = topology_id
1107
+
1108
+ @property
1109
+ def server_address(self) -> _Address:
1110
+ """The address (host, port) pair of the server"""
1111
+ return self.__server_address
1112
+
1113
+ @property
1114
+ def topology_id(self) -> ObjectId:
1115
+ """A unique identifier for the topology this server is a part of."""
1116
+ return self.__topology_id
1117
+
1118
+ def __repr__(self):
1119
+ return "<%s %s topology_id: %s>" % (
1120
+ self.__class__.__name__,
1121
+ self.server_address,
1122
+ self.topology_id,
1123
+ )
1124
+
1125
+
1126
+ class ServerDescriptionChangedEvent(_ServerEvent):
1127
+ """Published when server description changes.
1128
+
1129
+ .. versionadded:: 3.3
1130
+ """
1131
+
1132
+ __slots__ = ("__previous_description", "__new_description")
1133
+
1134
+ def __init__(
1135
+ self,
1136
+ previous_description: "ServerDescription",
1137
+ new_description: "ServerDescription",
1138
+ *args: Any
1139
+ ) -> None:
1140
+ super(ServerDescriptionChangedEvent, self).__init__(*args)
1141
+ self.__previous_description = previous_description
1142
+ self.__new_description = new_description
1143
+
1144
+ @property
1145
+ def previous_description(self) -> "ServerDescription":
1146
+ """The previous
1147
+ :class:`~pymongo.server_description.ServerDescription`."""
1148
+ return self.__previous_description
1149
+
1150
+ @property
1151
+ def new_description(self) -> "ServerDescription":
1152
+ """The new
1153
+ :class:`~pymongo.server_description.ServerDescription`."""
1154
+ return self.__new_description
1155
+
1156
+ def __repr__(self):
1157
+ return "<%s %s changed from: %s, to: %s>" % (
1158
+ self.__class__.__name__,
1159
+ self.server_address,
1160
+ self.previous_description,
1161
+ self.new_description,
1162
+ )
1163
+
1164
+
1165
+ class ServerOpeningEvent(_ServerEvent):
1166
+ """Published when server is initialized.
1167
+
1168
+ .. versionadded:: 3.3
1169
+ """
1170
+
1171
+ __slots__ = ()
1172
+
1173
+
1174
+ class ServerClosedEvent(_ServerEvent):
1175
+ """Published when server is closed.
1176
+
1177
+ .. versionadded:: 3.3
1178
+ """
1179
+
1180
+ __slots__ = ()
1181
+
1182
+
1183
+ class TopologyEvent(object):
1184
+ """Base class for topology description events."""
1185
+
1186
+ __slots__ = "__topology_id"
1187
+
1188
+ def __init__(self, topology_id: ObjectId) -> None:
1189
+ self.__topology_id = topology_id
1190
+
1191
+ @property
1192
+ def topology_id(self) -> ObjectId:
1193
+ """A unique identifier for the topology this server is a part of."""
1194
+ return self.__topology_id
1195
+
1196
+ def __repr__(self):
1197
+ return "<%s topology_id: %s>" % (self.__class__.__name__, self.topology_id)
1198
+
1199
+
1200
+ class TopologyDescriptionChangedEvent(TopologyEvent):
1201
+ """Published when the topology description changes.
1202
+
1203
+ .. versionadded:: 3.3
1204
+ """
1205
+
1206
+ __slots__ = ("__previous_description", "__new_description")
1207
+
1208
+ def __init__(
1209
+ self,
1210
+ previous_description: "TopologyDescription",
1211
+ new_description: "TopologyDescription",
1212
+ *args: Any
1213
+ ) -> None:
1214
+ super(TopologyDescriptionChangedEvent, self).__init__(*args)
1215
+ self.__previous_description = previous_description
1216
+ self.__new_description = new_description
1217
+
1218
+ @property
1219
+ def previous_description(self) -> "TopologyDescription":
1220
+ """The previous
1221
+ :class:`~pymongo.topology_description.TopologyDescription`."""
1222
+ return self.__previous_description
1223
+
1224
+ @property
1225
+ def new_description(self) -> "TopologyDescription":
1226
+ """The new
1227
+ :class:`~pymongo.topology_description.TopologyDescription`."""
1228
+ return self.__new_description
1229
+
1230
+ def __repr__(self):
1231
+ return "<%s topology_id: %s changed from: %s, to: %s>" % (
1232
+ self.__class__.__name__,
1233
+ self.topology_id,
1234
+ self.previous_description,
1235
+ self.new_description,
1236
+ )
1237
+
1238
+
1239
+ class TopologyOpenedEvent(TopologyEvent):
1240
+ """Published when the topology is initialized.
1241
+
1242
+ .. versionadded:: 3.3
1243
+ """
1244
+
1245
+ __slots__ = ()
1246
+
1247
+
1248
+ class TopologyClosedEvent(TopologyEvent):
1249
+ """Published when the topology is closed.
1250
+
1251
+ .. versionadded:: 3.3
1252
+ """
1253
+
1254
+ __slots__ = ()
1255
+
1256
+
1257
+ class _ServerHeartbeatEvent(object):
1258
+ """Base class for server heartbeat events."""
1259
+
1260
+ __slots__ = "__connection_id"
1261
+
1262
+ def __init__(self, connection_id: _Address) -> None:
1263
+ self.__connection_id = connection_id
1264
+
1265
+ @property
1266
+ def connection_id(self) -> _Address:
1267
+ """The address (host, port) of the server this heartbeat was sent
1268
+ to."""
1269
+ return self.__connection_id
1270
+
1271
+ def __repr__(self):
1272
+ return "<%s %s>" % (self.__class__.__name__, self.connection_id)
1273
+
1274
+
1275
+ class ServerHeartbeatStartedEvent(_ServerHeartbeatEvent):
1276
+ """Published when a heartbeat is started.
1277
+
1278
+ .. versionadded:: 3.3
1279
+ """
1280
+
1281
+ __slots__ = ()
1282
+
1283
+
1284
+ class ServerHeartbeatSucceededEvent(_ServerHeartbeatEvent):
1285
+ """Fired when the server heartbeat succeeds.
1286
+
1287
+ .. versionadded:: 3.3
1288
+ """
1289
+
1290
+ __slots__ = ("__duration", "__reply", "__awaited")
1291
+
1292
+ def __init__(
1293
+ self, duration: float, reply: Hello, connection_id: _Address, awaited: bool = False
1294
+ ) -> None:
1295
+ super(ServerHeartbeatSucceededEvent, self).__init__(connection_id)
1296
+ self.__duration = duration
1297
+ self.__reply = reply
1298
+ self.__awaited = awaited
1299
+
1300
+ @property
1301
+ def duration(self) -> float:
1302
+ """The duration of this heartbeat in microseconds."""
1303
+ return self.__duration
1304
+
1305
+ @property
1306
+ def reply(self) -> Hello:
1307
+ """An instance of :class:`~pymongo.hello.Hello`."""
1308
+ return self.__reply
1309
+
1310
+ @property
1311
+ def awaited(self) -> bool:
1312
+ """Whether the heartbeat was awaited.
1313
+
1314
+ If true, then :meth:`duration` reflects the sum of the round trip time
1315
+ to the server and the time that the server waited before sending a
1316
+ response.
1317
+ """
1318
+ return self.__awaited
1319
+
1320
+ def __repr__(self):
1321
+ return "<%s %s duration: %s, awaited: %s, reply: %s>" % (
1322
+ self.__class__.__name__,
1323
+ self.connection_id,
1324
+ self.duration,
1325
+ self.awaited,
1326
+ self.reply,
1327
+ )
1328
+
1329
+
1330
+ class ServerHeartbeatFailedEvent(_ServerHeartbeatEvent):
1331
+ """Fired when the server heartbeat fails, either with an "ok: 0"
1332
+ or a socket exception.
1333
+
1334
+ .. versionadded:: 3.3
1335
+ """
1336
+
1337
+ __slots__ = ("__duration", "__reply", "__awaited")
1338
+
1339
+ def __init__(
1340
+ self, duration: float, reply: Exception, connection_id: _Address, awaited: bool = False
1341
+ ) -> None:
1342
+ super(ServerHeartbeatFailedEvent, self).__init__(connection_id)
1343
+ self.__duration = duration
1344
+ self.__reply = reply
1345
+ self.__awaited = awaited
1346
+
1347
+ @property
1348
+ def duration(self) -> float:
1349
+ """The duration of this heartbeat in microseconds."""
1350
+ return self.__duration
1351
+
1352
+ @property
1353
+ def reply(self) -> Exception:
1354
+ """A subclass of :exc:`Exception`."""
1355
+ return self.__reply
1356
+
1357
+ @property
1358
+ def awaited(self) -> bool:
1359
+ """Whether the heartbeat was awaited.
1360
+
1361
+ If true, then :meth:`duration` reflects the sum of the round trip time
1362
+ to the server and the time that the server waited before sending a
1363
+ response.
1364
+ """
1365
+ return self.__awaited
1366
+
1367
+ def __repr__(self):
1368
+ return "<%s %s duration: %s, awaited: %s, reply: %r>" % (
1369
+ self.__class__.__name__,
1370
+ self.connection_id,
1371
+ self.duration,
1372
+ self.awaited,
1373
+ self.reply,
1374
+ )
1375
+
1376
+
1377
+ class _EventListeners(object):
1378
+ """Configure event listeners for a client instance.
1379
+
1380
+ Any event listeners registered globally are included by default.
1381
+
1382
+ :Parameters:
1383
+ - `listeners`: A list of event listeners.
1384
+ """
1385
+
1386
+ def __init__(self, listeners):
1387
+ self.__command_listeners = _LISTENERS.command_listeners[:]
1388
+ self.__server_listeners = _LISTENERS.server_listeners[:]
1389
+ lst = _LISTENERS.server_heartbeat_listeners
1390
+ self.__server_heartbeat_listeners = lst[:]
1391
+ self.__topology_listeners = _LISTENERS.topology_listeners[:]
1392
+ self.__cmap_listeners = _LISTENERS.cmap_listeners[:]
1393
+ if listeners is not None:
1394
+ for lst in listeners:
1395
+ if isinstance(lst, CommandListener):
1396
+ self.__command_listeners.append(lst)
1397
+ if isinstance(lst, ServerListener):
1398
+ self.__server_listeners.append(lst)
1399
+ if isinstance(lst, ServerHeartbeatListener):
1400
+ self.__server_heartbeat_listeners.append(lst)
1401
+ if isinstance(lst, TopologyListener):
1402
+ self.__topology_listeners.append(lst)
1403
+ if isinstance(lst, ConnectionPoolListener):
1404
+ self.__cmap_listeners.append(lst)
1405
+ self.__enabled_for_commands = bool(self.__command_listeners)
1406
+ self.__enabled_for_server = bool(self.__server_listeners)
1407
+ self.__enabled_for_server_heartbeat = bool(self.__server_heartbeat_listeners)
1408
+ self.__enabled_for_topology = bool(self.__topology_listeners)
1409
+ self.__enabled_for_cmap = bool(self.__cmap_listeners)
1410
+
1411
+ @property
1412
+ def enabled_for_commands(self):
1413
+ """Are any CommandListener instances registered?"""
1414
+ return self.__enabled_for_commands
1415
+
1416
+ @property
1417
+ def enabled_for_server(self):
1418
+ """Are any ServerListener instances registered?"""
1419
+ return self.__enabled_for_server
1420
+
1421
+ @property
1422
+ def enabled_for_server_heartbeat(self):
1423
+ """Are any ServerHeartbeatListener instances registered?"""
1424
+ return self.__enabled_for_server_heartbeat
1425
+
1426
+ @property
1427
+ def enabled_for_topology(self):
1428
+ """Are any TopologyListener instances registered?"""
1429
+ return self.__enabled_for_topology
1430
+
1431
+ @property
1432
+ def enabled_for_cmap(self):
1433
+ """Are any ConnectionPoolListener instances registered?"""
1434
+ return self.__enabled_for_cmap
1435
+
1436
+ def event_listeners(self):
1437
+ """List of registered event listeners."""
1438
+ return (
1439
+ self.__command_listeners
1440
+ + self.__server_heartbeat_listeners
1441
+ + self.__server_listeners
1442
+ + self.__topology_listeners
1443
+ + self.__cmap_listeners
1444
+ )
1445
+
1446
+ def publish_command_start(
1447
+ self, command, database_name, request_id, connection_id, op_id=None, service_id=None
1448
+ ):
1449
+ """Publish a CommandStartedEvent to all command listeners.
1450
+
1451
+ :Parameters:
1452
+ - `command`: The command document.
1453
+ - `database_name`: The name of the database this command was run
1454
+ against.
1455
+ - `request_id`: The request id for this operation.
1456
+ - `connection_id`: The address (host, port) of the server this
1457
+ command was sent to.
1458
+ - `op_id`: The (optional) operation id for this operation.
1459
+ - `service_id`: The service_id this command was sent to, or ``None``.
1460
+ """
1461
+ if op_id is None:
1462
+ op_id = request_id
1463
+ event = CommandStartedEvent(
1464
+ command, database_name, request_id, connection_id, op_id, service_id=service_id
1465
+ )
1466
+ for subscriber in self.__command_listeners:
1467
+ try:
1468
+ subscriber.started(event)
1469
+ except Exception:
1470
+ _handle_exception()
1471
+
1472
+ def publish_command_success(
1473
+ self,
1474
+ duration,
1475
+ reply,
1476
+ command_name,
1477
+ request_id,
1478
+ connection_id,
1479
+ op_id=None,
1480
+ service_id=None,
1481
+ speculative_hello=False,
1482
+ ):
1483
+ """Publish a CommandSucceededEvent to all command listeners.
1484
+
1485
+ :Parameters:
1486
+ - `duration`: The command duration as a datetime.timedelta.
1487
+ - `reply`: The server reply document.
1488
+ - `command_name`: The command name.
1489
+ - `request_id`: The request id for this operation.
1490
+ - `connection_id`: The address (host, port) of the server this
1491
+ command was sent to.
1492
+ - `op_id`: The (optional) operation id for this operation.
1493
+ - `service_id`: The service_id this command was sent to, or ``None``.
1494
+ - `speculative_hello`: Was the command sent with speculative auth?
1495
+ """
1496
+ if op_id is None:
1497
+ op_id = request_id
1498
+ if speculative_hello:
1499
+ # Redact entire response when the command started contained
1500
+ # speculativeAuthenticate.
1501
+ reply = {}
1502
+ event = CommandSucceededEvent(
1503
+ duration, reply, command_name, request_id, connection_id, op_id, service_id
1504
+ )
1505
+ for subscriber in self.__command_listeners:
1506
+ try:
1507
+ subscriber.succeeded(event)
1508
+ except Exception:
1509
+ _handle_exception()
1510
+
1511
+ def publish_command_failure(
1512
+ self,
1513
+ duration,
1514
+ failure,
1515
+ command_name,
1516
+ request_id,
1517
+ connection_id,
1518
+ op_id=None,
1519
+ service_id=None,
1520
+ ):
1521
+ """Publish a CommandFailedEvent to all command listeners.
1522
+
1523
+ :Parameters:
1524
+ - `duration`: The command duration as a datetime.timedelta.
1525
+ - `failure`: The server reply document or failure description
1526
+ document.
1527
+ - `command_name`: The command name.
1528
+ - `request_id`: The request id for this operation.
1529
+ - `connection_id`: The address (host, port) of the server this
1530
+ command was sent to.
1531
+ - `op_id`: The (optional) operation id for this operation.
1532
+ - `service_id`: The service_id this command was sent to, or ``None``.
1533
+ """
1534
+ if op_id is None:
1535
+ op_id = request_id
1536
+ event = CommandFailedEvent(
1537
+ duration, failure, command_name, request_id, connection_id, op_id, service_id=service_id
1538
+ )
1539
+ for subscriber in self.__command_listeners:
1540
+ try:
1541
+ subscriber.failed(event)
1542
+ except Exception:
1543
+ _handle_exception()
1544
+
1545
+ def publish_server_heartbeat_started(self, connection_id):
1546
+ """Publish a ServerHeartbeatStartedEvent to all server heartbeat
1547
+ listeners.
1548
+
1549
+ :Parameters:
1550
+ - `connection_id`: The address (host, port) pair of the connection.
1551
+ """
1552
+ event = ServerHeartbeatStartedEvent(connection_id)
1553
+ for subscriber in self.__server_heartbeat_listeners:
1554
+ try:
1555
+ subscriber.started(event)
1556
+ except Exception:
1557
+ _handle_exception()
1558
+
1559
+ def publish_server_heartbeat_succeeded(self, connection_id, duration, reply, awaited):
1560
+ """Publish a ServerHeartbeatSucceededEvent to all server heartbeat
1561
+ listeners.
1562
+
1563
+ :Parameters:
1564
+ - `connection_id`: The address (host, port) pair of the connection.
1565
+ - `duration`: The execution time of the event in the highest possible
1566
+ resolution for the platform.
1567
+ - `reply`: The command reply.
1568
+ - `awaited`: True if the response was awaited.
1569
+ """
1570
+ event = ServerHeartbeatSucceededEvent(duration, reply, connection_id, awaited)
1571
+ for subscriber in self.__server_heartbeat_listeners:
1572
+ try:
1573
+ subscriber.succeeded(event)
1574
+ except Exception:
1575
+ _handle_exception()
1576
+
1577
+ def publish_server_heartbeat_failed(self, connection_id, duration, reply, awaited):
1578
+ """Publish a ServerHeartbeatFailedEvent to all server heartbeat
1579
+ listeners.
1580
+
1581
+ :Parameters:
1582
+ - `connection_id`: The address (host, port) pair of the connection.
1583
+ - `duration`: The execution time of the event in the highest possible
1584
+ resolution for the platform.
1585
+ - `reply`: The command reply.
1586
+ - `awaited`: True if the response was awaited.
1587
+ """
1588
+ event = ServerHeartbeatFailedEvent(duration, reply, connection_id, awaited)
1589
+ for subscriber in self.__server_heartbeat_listeners:
1590
+ try:
1591
+ subscriber.failed(event)
1592
+ except Exception:
1593
+ _handle_exception()
1594
+
1595
+ def publish_server_opened(self, server_address, topology_id):
1596
+ """Publish a ServerOpeningEvent to all server listeners.
1597
+
1598
+ :Parameters:
1599
+ - `server_address`: The address (host, port) pair of the server.
1600
+ - `topology_id`: A unique identifier for the topology this server
1601
+ is a part of.
1602
+ """
1603
+ event = ServerOpeningEvent(server_address, topology_id)
1604
+ for subscriber in self.__server_listeners:
1605
+ try:
1606
+ subscriber.opened(event)
1607
+ except Exception:
1608
+ _handle_exception()
1609
+
1610
+ def publish_server_closed(self, server_address, topology_id):
1611
+ """Publish a ServerClosedEvent to all server listeners.
1612
+
1613
+ :Parameters:
1614
+ - `server_address`: The address (host, port) pair of the server.
1615
+ - `topology_id`: A unique identifier for the topology this server
1616
+ is a part of.
1617
+ """
1618
+ event = ServerClosedEvent(server_address, topology_id)
1619
+ for subscriber in self.__server_listeners:
1620
+ try:
1621
+ subscriber.closed(event)
1622
+ except Exception:
1623
+ _handle_exception()
1624
+
1625
+ def publish_server_description_changed(
1626
+ self, previous_description, new_description, server_address, topology_id
1627
+ ):
1628
+ """Publish a ServerDescriptionChangedEvent to all server listeners.
1629
+
1630
+ :Parameters:
1631
+ - `previous_description`: The previous server description.
1632
+ - `server_address`: The address (host, port) pair of the server.
1633
+ - `new_description`: The new server description.
1634
+ - `topology_id`: A unique identifier for the topology this server
1635
+ is a part of.
1636
+ """
1637
+ event = ServerDescriptionChangedEvent(
1638
+ previous_description, new_description, server_address, topology_id
1639
+ )
1640
+ for subscriber in self.__server_listeners:
1641
+ try:
1642
+ subscriber.description_changed(event)
1643
+ except Exception:
1644
+ _handle_exception()
1645
+
1646
+ def publish_topology_opened(self, topology_id):
1647
+ """Publish a TopologyOpenedEvent to all topology listeners.
1648
+
1649
+ :Parameters:
1650
+ - `topology_id`: A unique identifier for the topology this server
1651
+ is a part of.
1652
+ """
1653
+ event = TopologyOpenedEvent(topology_id)
1654
+ for subscriber in self.__topology_listeners:
1655
+ try:
1656
+ subscriber.opened(event)
1657
+ except Exception:
1658
+ _handle_exception()
1659
+
1660
+ def publish_topology_closed(self, topology_id):
1661
+ """Publish a TopologyClosedEvent to all topology listeners.
1662
+
1663
+ :Parameters:
1664
+ - `topology_id`: A unique identifier for the topology this server
1665
+ is a part of.
1666
+ """
1667
+ event = TopologyClosedEvent(topology_id)
1668
+ for subscriber in self.__topology_listeners:
1669
+ try:
1670
+ subscriber.closed(event)
1671
+ except Exception:
1672
+ _handle_exception()
1673
+
1674
+ def publish_topology_description_changed(
1675
+ self, previous_description, new_description, topology_id
1676
+ ):
1677
+ """Publish a TopologyDescriptionChangedEvent to all topology listeners.
1678
+
1679
+ :Parameters:
1680
+ - `previous_description`: The previous topology description.
1681
+ - `new_description`: The new topology description.
1682
+ - `topology_id`: A unique identifier for the topology this server
1683
+ is a part of.
1684
+ """
1685
+ event = TopologyDescriptionChangedEvent(previous_description, new_description, topology_id)
1686
+ for subscriber in self.__topology_listeners:
1687
+ try:
1688
+ subscriber.description_changed(event)
1689
+ except Exception:
1690
+ _handle_exception()
1691
+
1692
+ def publish_pool_created(self, address, options):
1693
+ """Publish a :class:`PoolCreatedEvent` to all pool listeners."""
1694
+ event = PoolCreatedEvent(address, options)
1695
+ for subscriber in self.__cmap_listeners:
1696
+ try:
1697
+ subscriber.pool_created(event)
1698
+ except Exception:
1699
+ _handle_exception()
1700
+
1701
+ def publish_pool_ready(self, address):
1702
+ """Publish a :class:`PoolReadyEvent` to all pool listeners."""
1703
+ event = PoolReadyEvent(address)
1704
+ for subscriber in self.__cmap_listeners:
1705
+ try:
1706
+ subscriber.pool_ready(event)
1707
+ except Exception:
1708
+ _handle_exception()
1709
+
1710
+ def publish_pool_cleared(self, address, service_id):
1711
+ """Publish a :class:`PoolClearedEvent` to all pool listeners."""
1712
+ event = PoolClearedEvent(address, service_id)
1713
+ for subscriber in self.__cmap_listeners:
1714
+ try:
1715
+ subscriber.pool_cleared(event)
1716
+ except Exception:
1717
+ _handle_exception()
1718
+
1719
+ def publish_pool_closed(self, address):
1720
+ """Publish a :class:`PoolClosedEvent` to all pool listeners."""
1721
+ event = PoolClosedEvent(address)
1722
+ for subscriber in self.__cmap_listeners:
1723
+ try:
1724
+ subscriber.pool_closed(event)
1725
+ except Exception:
1726
+ _handle_exception()
1727
+
1728
+ def publish_connection_created(self, address, connection_id):
1729
+ """Publish a :class:`ConnectionCreatedEvent` to all connection
1730
+ listeners.
1731
+ """
1732
+ event = ConnectionCreatedEvent(address, connection_id)
1733
+ for subscriber in self.__cmap_listeners:
1734
+ try:
1735
+ subscriber.connection_created(event)
1736
+ except Exception:
1737
+ _handle_exception()
1738
+
1739
+ def publish_connection_ready(self, address, connection_id):
1740
+ """Publish a :class:`ConnectionReadyEvent` to all connection listeners."""
1741
+ event = ConnectionReadyEvent(address, connection_id)
1742
+ for subscriber in self.__cmap_listeners:
1743
+ try:
1744
+ subscriber.connection_ready(event)
1745
+ except Exception:
1746
+ _handle_exception()
1747
+
1748
+ def publish_connection_closed(self, address, connection_id, reason):
1749
+ """Publish a :class:`ConnectionClosedEvent` to all connection
1750
+ listeners.
1751
+ """
1752
+ event = ConnectionClosedEvent(address, connection_id, reason)
1753
+ for subscriber in self.__cmap_listeners:
1754
+ try:
1755
+ subscriber.connection_closed(event)
1756
+ except Exception:
1757
+ _handle_exception()
1758
+
1759
+ def publish_connection_check_out_started(self, address):
1760
+ """Publish a :class:`ConnectionCheckOutStartedEvent` to all connection
1761
+ listeners.
1762
+ """
1763
+ event = ConnectionCheckOutStartedEvent(address)
1764
+ for subscriber in self.__cmap_listeners:
1765
+ try:
1766
+ subscriber.connection_check_out_started(event)
1767
+ except Exception:
1768
+ _handle_exception()
1769
+
1770
+ def publish_connection_check_out_failed(self, address, reason):
1771
+ """Publish a :class:`ConnectionCheckOutFailedEvent` to all connection
1772
+ listeners.
1773
+ """
1774
+ event = ConnectionCheckOutFailedEvent(address, reason)
1775
+ for subscriber in self.__cmap_listeners:
1776
+ try:
1777
+ subscriber.connection_check_out_failed(event)
1778
+ except Exception:
1779
+ _handle_exception()
1780
+
1781
+ def publish_connection_checked_out(self, address, connection_id):
1782
+ """Publish a :class:`ConnectionCheckedOutEvent` to all connection
1783
+ listeners.
1784
+ """
1785
+ event = ConnectionCheckedOutEvent(address, connection_id)
1786
+ for subscriber in self.__cmap_listeners:
1787
+ try:
1788
+ subscriber.connection_checked_out(event)
1789
+ except Exception:
1790
+ _handle_exception()
1791
+
1792
+ def publish_connection_checked_in(self, address, connection_id):
1793
+ """Publish a :class:`ConnectionCheckedInEvent` to all connection
1794
+ listeners.
1795
+ """
1796
+ event = ConnectionCheckedInEvent(address, connection_id)
1797
+ for subscriber in self.__cmap_listeners:
1798
+ try:
1799
+ subscriber.connection_checked_in(event)
1800
+ except Exception:
1801
+ _handle_exception()