mongo 2.13.0.beta1 → 2.13.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -5
  4. data/Rakefile +15 -9
  5. data/lib/mongo.rb +4 -2
  6. data/lib/mongo/auth/aws/request.rb +4 -2
  7. data/lib/mongo/bulk_write.rb +1 -0
  8. data/lib/mongo/client.rb +143 -21
  9. data/lib/mongo/cluster.rb +53 -17
  10. data/lib/mongo/cluster/sdam_flow.rb +13 -10
  11. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
  12. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  13. data/lib/mongo/cluster/topology/single.rb +1 -1
  14. data/lib/mongo/collection.rb +17 -13
  15. data/lib/mongo/collection/view/readable.rb +3 -1
  16. data/lib/mongo/collection/view/writable.rb +41 -5
  17. data/lib/mongo/database.rb +31 -4
  18. data/lib/mongo/database/view.rb +19 -4
  19. data/lib/mongo/distinguishing_semaphore.rb +55 -0
  20. data/lib/mongo/error.rb +1 -0
  21. data/lib/mongo/error/invalid_session.rb +2 -1
  22. data/lib/mongo/error/operation_failure.rb +6 -0
  23. data/lib/mongo/error/sessions_not_supported.rb +35 -0
  24. data/lib/mongo/event/base.rb +6 -0
  25. data/lib/mongo/grid/file.rb +5 -0
  26. data/lib/mongo/grid/file/chunk.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +15 -13
  28. data/lib/mongo/grid/stream/write.rb +9 -3
  29. data/lib/mongo/monitoring.rb +38 -0
  30. data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
  31. data/lib/mongo/monitoring/event/command_failed.rb +11 -0
  32. data/lib/mongo/monitoring/event/command_started.rb +37 -2
  33. data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
  34. data/lib/mongo/monitoring/event/server_closed.rb +1 -1
  35. data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
  36. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
  37. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
  38. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
  39. data/lib/mongo/monitoring/event/server_opening.rb +1 -1
  40. data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
  41. data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
  42. data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
  43. data/lib/mongo/monitoring/publishable.rb +6 -3
  44. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
  45. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
  46. data/lib/mongo/protocol/message.rb +36 -8
  47. data/lib/mongo/protocol/msg.rb +14 -0
  48. data/lib/mongo/protocol/serializers.rb +5 -2
  49. data/lib/mongo/server.rb +10 -3
  50. data/lib/mongo/server/connection.rb +4 -4
  51. data/lib/mongo/server/connection_base.rb +3 -1
  52. data/lib/mongo/server/description.rb +5 -0
  53. data/lib/mongo/server/monitor.rb +76 -44
  54. data/lib/mongo/server/monitor/connection.rb +55 -7
  55. data/lib/mongo/server/pending_connection.rb +14 -4
  56. data/lib/mongo/server/push_monitor.rb +173 -0
  57. data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
  58. data/lib/mongo/server_selector.rb +0 -1
  59. data/lib/mongo/server_selector/base.rb +579 -1
  60. data/lib/mongo/server_selector/nearest.rb +1 -6
  61. data/lib/mongo/server_selector/primary.rb +1 -6
  62. data/lib/mongo/server_selector/primary_preferred.rb +7 -10
  63. data/lib/mongo/server_selector/secondary.rb +1 -6
  64. data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
  65. data/lib/mongo/session.rb +2 -0
  66. data/lib/mongo/socket.rb +20 -8
  67. data/lib/mongo/socket/ssl.rb +1 -1
  68. data/lib/mongo/socket/tcp.rb +1 -1
  69. data/lib/mongo/topology_version.rb +9 -0
  70. data/lib/mongo/utils.rb +62 -0
  71. data/lib/mongo/version.rb +1 -1
  72. data/spec/README.aws-auth.md +2 -2
  73. data/spec/integration/awaited_ismaster_spec.rb +28 -0
  74. data/spec/integration/change_stream_examples_spec.rb +6 -2
  75. data/spec/integration/check_clean_slate_spec.rb +16 -0
  76. data/spec/integration/client_construction_spec.rb +1 -0
  77. data/spec/integration/connect_single_rs_name_spec.rb +5 -2
  78. data/spec/integration/connection_spec.rb +7 -4
  79. data/spec/integration/crud_spec.rb +4 -4
  80. data/spec/integration/docs_examples_spec.rb +6 -0
  81. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  82. data/spec/integration/heartbeat_events_spec.rb +4 -23
  83. data/spec/integration/read_concern_spec.rb +1 -1
  84. data/spec/integration/retryable_errors_spec.rb +1 -1
  85. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -2
  86. data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
  87. data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
  88. data/spec/integration/sdam_error_handling_spec.rb +37 -15
  89. data/spec/integration/sdam_events_spec.rb +77 -6
  90. data/spec/integration/sdam_prose_spec.rb +64 -0
  91. data/spec/integration/server_monitor_spec.rb +25 -1
  92. data/spec/integration/size_limit_spec.rb +7 -3
  93. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
  94. data/spec/integration/ssl_uri_options_spec.rb +2 -2
  95. data/spec/integration/zlib_compression_spec.rb +25 -0
  96. data/spec/lite_spec_helper.rb +12 -5
  97. data/spec/mongo/auth/aws/request_spec.rb +76 -0
  98. data/spec/mongo/auth/scram_spec.rb +1 -1
  99. data/spec/mongo/client_construction_spec.rb +207 -0
  100. data/spec/mongo/client_spec.rb +38 -3
  101. data/spec/mongo/cluster/topology/replica_set_spec.rb +52 -9
  102. data/spec/mongo/cluster/topology/single_spec.rb +4 -2
  103. data/spec/mongo/cluster_spec.rb +34 -35
  104. data/spec/mongo/collection/view/change_stream_resume_spec.rb +6 -6
  105. data/spec/mongo/collection_spec.rb +500 -0
  106. data/spec/mongo/database_spec.rb +245 -8
  107. data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
  108. data/spec/mongo/error/operation_failure_spec.rb +40 -0
  109. data/spec/mongo/index/view_spec.rb +2 -2
  110. data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
  111. data/spec/mongo/protocol/msg_spec.rb +10 -0
  112. data/spec/mongo/semaphore_spec.rb +51 -0
  113. data/spec/mongo/server/connection_auth_spec.rb +2 -2
  114. data/spec/mongo/server_selector/nearest_spec.rb +23 -23
  115. data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
  116. data/spec/mongo/server_selector/primary_spec.rb +9 -9
  117. data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
  118. data/spec/mongo/server_selector/secondary_spec.rb +18 -18
  119. data/spec/mongo/server_selector_spec.rb +4 -4
  120. data/spec/mongo/session_spec.rb +35 -0
  121. data/spec/runners/change_streams/test.rb +2 -2
  122. data/spec/runners/cmap.rb +1 -1
  123. data/spec/runners/command_monitoring.rb +3 -34
  124. data/spec/runners/crud/context.rb +9 -5
  125. data/spec/runners/crud/operation.rb +59 -27
  126. data/spec/runners/crud/spec.rb +0 -8
  127. data/spec/runners/crud/test.rb +1 -1
  128. data/spec/runners/sdam.rb +2 -2
  129. data/spec/runners/server_selection.rb +242 -28
  130. data/spec/runners/transactions.rb +12 -12
  131. data/spec/runners/transactions/operation.rb +151 -25
  132. data/spec/runners/transactions/test.rb +60 -16
  133. data/spec/spec_tests/command_monitoring_spec.rb +22 -12
  134. data/spec/spec_tests/crud_spec.rb +1 -1
  135. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -8
  136. data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
  137. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
  138. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
  139. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
  140. data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
  141. data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
  142. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
  143. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
  144. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
  145. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
  146. data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
  147. data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
  148. data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
  149. data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
  150. data/spec/spec_tests/max_staleness_spec.rb +4 -142
  151. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  152. data/spec/spec_tests/sdam_integration_spec.rb +13 -0
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
  154. data/spec/spec_tests/server_selection_spec.rb +4 -116
  155. data/spec/stress/cleanup_spec.rb +17 -2
  156. data/spec/stress/connection_pool_stress_spec.rb +10 -8
  157. data/spec/support/child_process_helper.rb +78 -0
  158. data/spec/support/client_registry.rb +1 -0
  159. data/spec/support/cluster_config.rb +4 -0
  160. data/spec/support/event_subscriber.rb +123 -33
  161. data/spec/support/keyword_struct.rb +26 -0
  162. data/spec/support/shared/server_selector.rb +13 -1
  163. data/spec/support/spec_config.rb +38 -13
  164. data/spec/support/spec_organizer.rb +129 -0
  165. data/spec/support/spec_setup.rb +1 -1
  166. data/spec/support/utils.rb +46 -0
  167. metadata +992 -942
  168. metadata.gz.sig +0 -0
  169. data/lib/mongo/server_selector/selectable.rb +0 -560
  170. data/spec/runners/sdam_monitoring.rb +0 -89
@@ -210,6 +210,7 @@ require 'mongo/error/need_primary_server'
210
210
  require 'mongo/error/no_server_available'
211
211
  require 'mongo/error/no_srv_records'
212
212
  require 'mongo/error/session_ended'
213
+ require 'mongo/error/sessions_not_supported'
213
214
  require 'mongo/error/pool_closed_error'
214
215
  require 'mongo/error/raise_original_error'
215
216
  require 'mongo/error/socket_error'
@@ -15,7 +15,8 @@
15
15
  module Mongo
16
16
  class Error
17
17
 
18
- # This exception is raised when a session is attempted to be used and it is invalid.
18
+ # This exception is raised when a session is attempted to be used and it
19
+ # is invalid.
19
20
  #
20
21
  # @since 2.5.0
21
22
  class InvalidSession < Error
@@ -166,6 +166,12 @@ module Mongo
166
166
  # @since 2.6.0
167
167
  def change_stream_resumable?
168
168
  if @result && @result.is_a?(Mongo::Operation::GetMore::Result)
169
+ # CursorNotFound exceptions are always resumable because the server
170
+ # is not aware of the cursor id, and thus cannot determine if
171
+ # the cursor is a change stream and cannot add the
172
+ # ResumableChangeStreamError label.
173
+ return true if code == 43
174
+
169
175
  # Connection description is not populated for unacknowledged writes.
170
176
  if connection_description.max_wire_version >= 9
171
177
  label?('ResumableChangeStreamError')
@@ -0,0 +1,35 @@
1
+ # Copyright (C) 2020 MongoDB Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You 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 implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Error
17
+
18
+ # This exception is raised when a session is attempted to be used and the
19
+ # deployment does not support sessions.
20
+ #
21
+ # @note The subclassing of InvalidSession only exists for backwards
22
+ # compatibility and will be removed in driver version 3.0.
23
+ class SessionsNotSupported < InvalidSession
24
+
25
+ # Create the new exception.
26
+ #
27
+ # @param [ String ] message The error message.
28
+ #
29
+ # @api private
30
+ def initialize(message)
31
+ super(message)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -31,6 +31,12 @@ module Mongo
31
31
  def summary
32
32
  "#<#{self.class}>"
33
33
  end
34
+
35
+ private
36
+
37
+ def short_class_name
38
+ self.class.name.sub(/^Mongo::Monitoring::Event::/, '')
39
+ end
34
40
  end
35
41
  end
36
42
  end
@@ -104,6 +104,11 @@ module Mongo
104
104
  # chunk objects and assemble the data. If we have an IO object, then
105
105
  # it's the original file data and we must split it into chunks and set
106
106
  # the original data itself.
107
+ #
108
+ # @param [ IO, String, Array<BSON::Document> ] value The file object,
109
+ # file contents or chunk documents.
110
+ #
111
+ # @return [ Array<Grid::File::Chunk> ] Array of chunks.
107
112
  def initialize_chunks!(value)
108
113
  if value.is_a?(Array)
109
114
  @chunks = value.map{ |doc| Chunk.new(doc) }
@@ -151,6 +151,7 @@ module Mongo
151
151
  # @return [ String ] The assembled data.
152
152
  #
153
153
  # @since 2.0.0
154
+ # @api private
154
155
  def assemble(chunks)
155
156
  chunks.reduce(''){ |data, chunk| data << chunk.data.data }
156
157
  end
@@ -167,6 +168,7 @@ module Mongo
167
168
  # @return [ Array<Chunk> ] The chunks of the data.
168
169
  #
169
170
  # @since 2.0.0
171
+ # @api private
170
172
  def split(io, file_info, offset = 0)
171
173
  io = StringIO.new(io) if io.is_a?(String)
172
174
  parts = Enumerator.new { |y| y << io.read(file_info.chunk_size) until io.eof? }
@@ -179,7 +179,7 @@ module Mongo
179
179
  #
180
180
  # @since 2.0.0
181
181
  def prefix
182
- @options[:fs_name] || @options[:bucket_name]|| DEFAULT_ROOT
182
+ @options[:fs_name] || @options[:bucket_name] || DEFAULT_ROOT
183
183
  end
184
184
 
185
185
  # Remove a single file from the GridFS.
@@ -232,7 +232,8 @@ module Mongo
232
232
  #
233
233
  # @since 2.1.0
234
234
  def open_download_stream(id, options = nil)
235
- read_stream(id, options).tap do |stream|
235
+ options = Utils.shallow_symbolize_keys(options || {})
236
+ read_stream(id, **options).tap do |stream|
236
237
  if block_given?
237
238
  begin
238
239
  yield stream
@@ -350,15 +351,15 @@ module Mongo
350
351
  download_to_stream(open_download_stream_by_name(filename, opts).file_id, io)
351
352
  end
352
353
 
353
- # Opens an upload stream to GridFS to which the contents of a user file came be written.
354
+ # Opens an upload stream to GridFS to which the contents of a file or
355
+ # blob can be written.
354
356
  #
355
- # @example Open a stream to which the contents of a file came be written.
356
- # fs.open_upload_stream('a-file.txt')
357
- #
358
- # @param [ String ] filename The filename of the file to upload.
357
+ # @param [ String ] filename The name of the file in GridFS.
359
358
  # @param [ Hash ] opts The options for the write stream.
360
359
  #
361
- # @option opts [ Object ] :file_id An optional unique file id. An ObjectId is generated otherwise.
360
+ # @option opts [ Object ] :file_id An optional unique file id.
361
+ # A BSON::ObjectId is automatically generated if a file id is not
362
+ # provided.
362
363
  # @option opts [ Integer ] :chunk_size Override the default chunk size.
363
364
  # @option opts [ Hash ] :metadata User data for the 'metadata' field of the files
364
365
  # collection document.
@@ -377,7 +378,8 @@ module Mongo
377
378
  #
378
379
  # @since 2.1.0
379
380
  def open_upload_stream(filename, opts = {})
380
- write_stream(filename, opts).tap do |stream|
381
+ opts = Utils.shallow_symbolize_keys(opts)
382
+ write_stream(filename, **opts).tap do |stream|
381
383
  if block_given?
382
384
  begin
383
385
  yield stream
@@ -467,12 +469,12 @@ module Mongo
467
469
  #
468
470
  # @option opts [ BSON::Document ] :file_info_doc For internal
469
471
  # driver use only. A BSON document to use as file information.
470
- def read_stream(id, opts = nil)
471
- Stream.get(self, Stream::READ_MODE, { file_id: id }.update(options).update(opts || {}))
472
+ def read_stream(id, **opts)
473
+ Stream.get(self, Stream::READ_MODE, { file_id: id }.update(options).update(opts))
472
474
  end
473
475
 
474
- def write_stream(filename, opts)
475
- Stream.get(self, Stream::WRITE_MODE, { filename: filename }.merge!(options).merge!(opts))
476
+ def write_stream(filename, **opts)
477
+ Stream.get(self, Stream::WRITE_MODE, { filename: filename }.update(options).update(opts))
476
478
  end
477
479
 
478
480
  def chunks_name
@@ -82,12 +82,12 @@ module Mongo
82
82
  @open = true
83
83
  end
84
84
 
85
- # Write to the GridFS bucket from the source stream.
85
+ # Write to the GridFS bucket from the source stream or a string.
86
86
  #
87
87
  # @example Write to GridFS.
88
88
  # stream.write(io)
89
89
  #
90
- # @param [ IO ] io The source io stream to upload from.
90
+ # @param [ String | IO ] io The string or IO object to upload from.
91
91
  #
92
92
  # @return [ Stream::Write ] self The write stream itself.
93
93
  #
@@ -95,7 +95,13 @@ module Mongo
95
95
  def write(io)
96
96
  ensure_open!
97
97
  @indexes ||= ensure_indexes!
98
- @length += io.size
98
+ @length += if io.respond_to?(:bytesize)
99
+ # String objects
100
+ io.bytesize
101
+ else
102
+ # IO objects
103
+ io.size
104
+ end
99
105
  chunks = File::Chunk.split(io, file_info, @n)
100
106
  @n += chunks.size
101
107
  chunks_collection.insert_many(chunks) unless chunks.empty?
@@ -304,6 +304,44 @@ module Mongo
304
304
  subscribers_for(topic).each{ |subscriber| subscriber.failed(event) }
305
305
  end
306
306
 
307
+ # @api private
308
+ def publish_heartbeat(server, awaited: false)
309
+ if monitoring?
310
+ event = Event::ServerHeartbeatStarted.new(
311
+ server.address, awaited: awaited)
312
+ started(SERVER_HEARTBEAT, event)
313
+ end
314
+
315
+ # The duration we publish in heartbeat succeeded/failed events is
316
+ # the time spent on the entire heartbeat. This could include time
317
+ # to connect the socket (including TLS handshake), not just time
318
+ # spent on ismaster call itself.
319
+ # The spec at https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-monitoring.rst
320
+ # requires that the duration exposed here start from "sending the
321
+ # message" (ismaster). This requirement does not make sense if,
322
+ # for example, we were never able to connect to the server at all
323
+ # and thus ismaster was never sent.
324
+ start_time = Time.now
325
+
326
+ begin
327
+ result = yield
328
+ rescue => exc
329
+ if monitoring?
330
+ event = Event::ServerHeartbeatFailed.new(
331
+ server.address, Time.now-start_time, exc, awaited: awaited)
332
+ failed(SERVER_HEARTBEAT, event)
333
+ end
334
+ raise
335
+ else
336
+ if monitoring?
337
+ event = Event::ServerHeartbeatSucceeded.new(
338
+ server.address, Time.now-start_time, awaited: awaited)
339
+ succeeded(SERVER_HEARTBEAT, event)
340
+ end
341
+ result
342
+ end
343
+ end
344
+
307
345
  private
308
346
 
309
347
  def initialize_copy(original)
@@ -57,6 +57,7 @@ module Mongo
57
57
  _prefix = prefix(event,
58
58
  connection_generation: event.connection_generation,
59
59
  connection_id: event.connection_id,
60
+ server_connection_id: event.server_connection_id,
60
61
  )
61
62
  log_debug("#{_prefix} | STARTED | #{format_command(event.command)}")
62
63
  end
@@ -100,12 +101,19 @@ module Mongo
100
101
  end
101
102
  end
102
103
 
103
- def prefix(event, connection_generation: nil, connection_id: nil)
104
+ def prefix(event, connection_generation: nil, connection_id: nil,
105
+ server_connection_id: nil
106
+ )
104
107
  extra = [connection_generation, connection_id].compact.join(':')
105
108
  if extra == ''
106
109
  extra = nil
110
+ else
111
+ extra = "conn:#{extra}"
107
112
  end
108
- "[#{event.request_id}] #{event.address.to_s}#{extra && " ##{extra}"} | " +
113
+ if server_connection_id
114
+ extra += " sconn:#{server_connection_id}"
115
+ end
116
+ "#{event.address.to_s} req:#{event.request_id}#{extra && " #{extra}"} | " +
109
117
  "#{event.database_name}.#{event.command_name}"
110
118
  end
111
119
 
@@ -75,6 +75,17 @@ module Mongo
75
75
  @duration = duration
76
76
  end
77
77
 
78
+ # Returns a concise yet useful summary of the event.
79
+ #
80
+ # @return [ String ] String summary of the event.
81
+ #
82
+ # @note This method is experimental and subject to change.
83
+ #
84
+ # @api experimental
85
+ def summary
86
+ "#<#{short_class_name} address=#{address} #{database_name}.#{command_name}>"
87
+ end
88
+
78
89
  # Create the event from a wire protocol message payload.
79
90
  #
80
91
  # @example Create the event.
@@ -54,6 +54,9 @@ module Mongo
54
54
  # @api private
55
55
  attr_reader :connection_id
56
56
 
57
+ # @api private
58
+ attr_reader :server_connection_id
59
+
57
60
  # Create the new event.
58
61
  #
59
62
  # @example Create the event.
@@ -69,7 +72,7 @@ module Mongo
69
72
  # @api private
70
73
  def initialize(command_name, database_name, address, request_id,
71
74
  operation_id, command, socket_object_id: nil, connection_id: nil,
72
- connection_generation: nil
75
+ connection_generation: nil, server_connection_id: nil
73
76
  )
74
77
  @command_name = command_name.to_s
75
78
  @database_name = database_name
@@ -80,6 +83,36 @@ module Mongo
80
83
  @socket_object_id = socket_object_id
81
84
  @connection_id = connection_id
82
85
  @connection_generation = connection_generation
86
+ @server_connection_id = server_connection_id
87
+ end
88
+
89
+ # Returns a concise yet useful summary of the event.
90
+ #
91
+ # @return [ String ] String summary of the event.
92
+ #
93
+ # @note This method is experimental and subject to change.
94
+ #
95
+ # @api experimental
96
+ def summary
97
+ "#<#{short_class_name} address=#{address} #{database_name}.#{command_name} command=#{command_summary}>"
98
+ end
99
+
100
+ # Returns the command, formatted as a string, with automatically added
101
+ # keys elided ($clusterTime, lsid, signature).
102
+ #
103
+ # @return [ String ] The command summary.
104
+ private def command_summary
105
+ command = self.command
106
+ remove_keys = %w($clusterTime lsid signature)
107
+ if remove_keys.any? { |k| command.key?(k) }
108
+ command = Hash[command.reject { |k, v| remove_keys.include?(k) }]
109
+ suffix = ' ...'
110
+ else
111
+ suffix = ''
112
+ end
113
+ command.map do |k, v|
114
+ "#{k}=#{v.inspect}"
115
+ end.join(' ') + suffix
83
116
  end
84
117
 
85
118
  # Create the event from a wire protocol message payload.
@@ -96,7 +129,8 @@ module Mongo
96
129
  # @since 2.1.0
97
130
  # @api private
98
131
  def self.generate(address, operation_id, payload,
99
- socket_object_id: nil, connection_id: nil, connection_generation: nil
132
+ socket_object_id: nil, connection_id: nil, connection_generation: nil,
133
+ server_connection_id: nil
100
134
  )
101
135
  new(
102
136
  payload[:command_name],
@@ -113,6 +147,7 @@ module Mongo
113
147
  socket_object_id: socket_object_id,
114
148
  connection_id: connection_id,
115
149
  connection_generation: connection_generation,
150
+ server_connection_id: server_connection_id,
116
151
  )
117
152
  end
118
153
 
@@ -67,6 +67,17 @@ module Mongo
67
67
  @duration = duration
68
68
  end
69
69
 
70
+ # Returns a concise yet useful summary of the event.
71
+ #
72
+ # @return [ String ] String summary of the event.
73
+ #
74
+ # @note This method is experimental and subject to change.
75
+ #
76
+ # @api experimental
77
+ def summary
78
+ "#<#{short_class_name} address=#{address} #{database_name}.#{command_name}>"
79
+ end
80
+
70
81
  # Create the event from a wire protocol message payload.
71
82
  #
72
83
  # @example Create the event.
@@ -50,7 +50,7 @@ module Mongo
50
50
  # @since 2.7.0
51
51
  # @api experimental
52
52
  def summary
53
- "#<#{self.class.name.sub(/^Mongo::Monitoring::Event::/, '')}" +
53
+ "#<#{short_class_name}" +
54
54
  " address=#{address} topology=#{topology.summary}>"
55
55
  end
56
56
  end
@@ -35,6 +35,13 @@ module Mongo
35
35
  # description.
36
36
  attr_reader :new_description
37
37
 
38
+ # @return [ true | false ] Whether the heartbeat was awaited.
39
+ #
40
+ # @api experimental
41
+ def awaited?
42
+ @awaited
43
+ end
44
+
38
45
  # Create the event.
39
46
  #
40
47
  # @example Create the event.
@@ -44,13 +51,19 @@ module Mongo
44
51
  # @param [ Integer ] topology The topology.
45
52
  # @param [ Server::Description ] previous_description The previous description.
46
53
  # @param [ Server::Description ] new_description The new description.
54
+ # @param [ true | false ] awaited Whether the server description was
55
+ # a result of processing an awaited ismaster response.
47
56
  #
48
57
  # @since 2.4.0
49
- def initialize(address, topology, previous_description, new_description)
58
+ # @api private
59
+ def initialize(address, topology, previous_description, new_description,
60
+ awaited: false
61
+ )
50
62
  @address = address
51
63
  @topology = topology
52
64
  @previous_description = previous_description
53
65
  @new_description = new_description
66
+ @awaited = !!awaited
54
67
  end
55
68
 
56
69
  # Returns a concise yet useful summary of the event.
@@ -62,10 +75,20 @@ module Mongo
62
75
  # @since 2.7.0
63
76
  # @api experimental
64
77
  def summary
65
- "#<#{self.class.name.sub(/^Mongo::Monitoring::Event::/, '')}" +
66
- " address=#{address} topology=#{topology.summary}" +
78
+ "#<#{short_class_name}" +
79
+ " address=#{address}" +
67
80
  # TODO Add summaries to descriptions and use them here
68
- " prev=#{previous_description.inspect} new=#{new_description.inspect}>"
81
+ " prev=#{previous_description.server_type.upcase} new=#{new_description.server_type.upcase}#{awaited_indicator}>"
82
+ end
83
+
84
+ private
85
+
86
+ def awaited_indicator
87
+ if awaited?
88
+ ' [awaited]'
89
+ else
90
+ ''
91
+ end
69
92
  end
70
93
  end
71
94
  end