mongo 2.13.0.beta1 → 2.13.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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