mongo 2.22.0 → 2.23.0
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.
- checksums.yaml +4 -4
- data/lib/mongo/client.rb +40 -4
- data/lib/mongo/cluster.rb +4 -1
- data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
- data/lib/mongo/collection/view/aggregation.rb +5 -2
- data/lib/mongo/collection/view/iterable.rb +16 -14
- data/lib/mongo/collection/view/readable.rb +64 -55
- data/lib/mongo/collection/view/writable.rb +52 -46
- data/lib/mongo/collection/view.rb +2 -0
- data/lib/mongo/collection.rb +56 -46
- data/lib/mongo/config.rb +4 -0
- data/lib/mongo/crypt/auto_decryption_context.rb +9 -0
- data/lib/mongo/crypt/binding.rb +1 -1
- data/lib/mongo/crypt/context.rb +10 -0
- data/lib/mongo/crypt/explicit_decryption_context.rb +9 -0
- data/lib/mongo/database/view.rb +25 -20
- data/lib/mongo/database.rb +17 -10
- data/lib/mongo/deprecations.rb +98 -0
- data/lib/mongo/index/view.rb +28 -19
- data/lib/mongo/operation/create.rb +4 -0
- data/lib/mongo/operation/insert/op_msg.rb +5 -2
- data/lib/mongo/operation/shared/executable.rb +11 -4
- data/lib/mongo/operation/shared/specifiable.rb +5 -1
- data/lib/mongo/search_index/view.rb +29 -9
- data/lib/mongo/server/app_metadata/platform.rb +17 -4
- data/lib/mongo/server/connection.rb +18 -0
- data/lib/mongo/server/description/features.rb +37 -8
- data/lib/mongo/server.rb +2 -1
- data/lib/mongo/session.rb +55 -19
- data/lib/mongo/srv/monitor.rb +5 -1
- data/lib/mongo/srv/result.rb +14 -4
- data/lib/mongo/tracing/open_telemetry/command_tracer.rb +320 -0
- data/lib/mongo/tracing/open_telemetry/operation_tracer.rb +227 -0
- data/lib/mongo/tracing/open_telemetry/tracer.rb +236 -0
- data/lib/mongo/tracing/open_telemetry.rb +27 -0
- data/lib/mongo/tracing.rb +42 -0
- data/lib/mongo/uri/srv_protocol.rb +11 -6
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +3 -0
- metadata +8 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025-present MongoDB Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the 'License');
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an 'AS IS' BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Mongo
|
|
18
|
+
module Tracing
|
|
19
|
+
module OpenTelemetry
|
|
20
|
+
# OperationTracer is responsible for tracing MongoDB driver operations using OpenTelemetry.
|
|
21
|
+
#
|
|
22
|
+
# @api private
|
|
23
|
+
class OperationTracer
|
|
24
|
+
extend Forwardable
|
|
25
|
+
|
|
26
|
+
def_delegators :@parent_tracer,
|
|
27
|
+
:cursor_context_map,
|
|
28
|
+
:parent_context_for,
|
|
29
|
+
:transaction_context_map,
|
|
30
|
+
:transaction_map_key
|
|
31
|
+
|
|
32
|
+
# Initializes a new OperationTracer.
|
|
33
|
+
#
|
|
34
|
+
# @param otel_tracer [ OpenTelemetry::Trace::Tracer ] the OpenTelemetry tracer.
|
|
35
|
+
# @param parent_tracer [ Mongo::Tracing::OpenTelemetry::Tracer ] the parent tracer
|
|
36
|
+
# for accessing shared context maps.
|
|
37
|
+
def initialize(otel_tracer, parent_tracer)
|
|
38
|
+
@otel_tracer = otel_tracer
|
|
39
|
+
@parent_tracer = parent_tracer
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Trace a MongoDB operation.
|
|
43
|
+
#
|
|
44
|
+
# Creates an OpenTelemetry span for the operation, capturing attributes such as
|
|
45
|
+
# database name, collection name, operation name, and cursor ID. The span is finished
|
|
46
|
+
# automatically when the operation completes or fails.
|
|
47
|
+
#
|
|
48
|
+
# @param operation [ Mongo::Operation ] the MongoDB operation to trace.
|
|
49
|
+
# @param operation_context [ Mongo::Operation::Context ] the context of the operation.
|
|
50
|
+
# @param op_name [ String | nil ] an optional name for the operation. If nil, the
|
|
51
|
+
# operation class name is used.
|
|
52
|
+
#
|
|
53
|
+
# @yield the block representing the operation to be traced.
|
|
54
|
+
#
|
|
55
|
+
# @return [ Object ] the result of the operation.
|
|
56
|
+
#
|
|
57
|
+
# rubocop:disable Lint/RescueException
|
|
58
|
+
def trace_operation(operation, operation_context, op_name: nil, &block)
|
|
59
|
+
span = create_operation_span(operation, operation_context, op_name)
|
|
60
|
+
execute_with_span(span, operation, &block)
|
|
61
|
+
rescue Exception => e
|
|
62
|
+
handle_span_exception(span, e)
|
|
63
|
+
raise e
|
|
64
|
+
ensure
|
|
65
|
+
span&.finish
|
|
66
|
+
end
|
|
67
|
+
# rubocop:enable Lint/RescueException
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# Creates an OpenTelemetry span for the operation.
|
|
72
|
+
#
|
|
73
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
74
|
+
# @param operation_context [ Mongo::Operation::Context ] the operation context.
|
|
75
|
+
# @param op_name [ String | nil ] optional operation name.
|
|
76
|
+
#
|
|
77
|
+
# @return [ OpenTelemetry::Trace::Span ] the created span.
|
|
78
|
+
def create_operation_span(operation, operation_context, op_name)
|
|
79
|
+
parent_context = parent_context_for(operation_context, operation.cursor_id)
|
|
80
|
+
@otel_tracer.start_span(
|
|
81
|
+
operation_span_name(operation, op_name),
|
|
82
|
+
attributes: span_attributes(operation, op_name),
|
|
83
|
+
with_parent: parent_context,
|
|
84
|
+
kind: :client
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Executes the operation block within the span context.
|
|
89
|
+
#
|
|
90
|
+
# @param span [ OpenTelemetry::Trace::Span ] the span.
|
|
91
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
92
|
+
#
|
|
93
|
+
# @yield the block to execute.
|
|
94
|
+
#
|
|
95
|
+
# @return [ Object ] the result of the block.
|
|
96
|
+
def execute_with_span(span, operation)
|
|
97
|
+
::OpenTelemetry::Trace.with_span(span) do |s, c|
|
|
98
|
+
yield.tap do |result|
|
|
99
|
+
process_cursor_context(result, operation.cursor_id, c, s)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Handles exception for the span.
|
|
105
|
+
#
|
|
106
|
+
# @param span [ OpenTelemetry::Trace::Span ] the span.
|
|
107
|
+
# @param exception [ Exception ] the exception.
|
|
108
|
+
def handle_span_exception(span, exception)
|
|
109
|
+
return unless span
|
|
110
|
+
|
|
111
|
+
span.record_exception(exception)
|
|
112
|
+
span.status = ::OpenTelemetry::Trace::Status.error(
|
|
113
|
+
"Unhandled exception of type: #{exception.class}"
|
|
114
|
+
)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Returns the operation name from the provided name or operation class.
|
|
118
|
+
#
|
|
119
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
120
|
+
# @param op_name [ String | nil ] optional operation name.
|
|
121
|
+
#
|
|
122
|
+
# @return [ String ] the operation name in lowercase.
|
|
123
|
+
def operation_name(operation, op_name = nil)
|
|
124
|
+
op_name || operation.class.name.split('::').last.downcase
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Builds span attributes for the operation.
|
|
128
|
+
#
|
|
129
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
130
|
+
# @param op_name [ String | nil ] optional operation name.
|
|
131
|
+
#
|
|
132
|
+
# @return [ Hash ] OpenTelemetry span attributes following MongoDB semantic conventions.
|
|
133
|
+
def span_attributes(operation, op_name)
|
|
134
|
+
{
|
|
135
|
+
'db.system' => 'mongodb',
|
|
136
|
+
'db.namespace' => operation.db_name.to_s,
|
|
137
|
+
'db.collection.name' => collection_name(operation),
|
|
138
|
+
'db.operation.name' => operation_name(operation, op_name),
|
|
139
|
+
'db.operation.summary' => operation_span_name(operation, op_name),
|
|
140
|
+
'db.mongodb.cursor_id' => operation.cursor_id,
|
|
141
|
+
}.compact
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Processes cursor context after operation execution.
|
|
145
|
+
#
|
|
146
|
+
# Updates the cursor context map based on the result. Removes closed cursors
|
|
147
|
+
# and stores context for newly created cursors.
|
|
148
|
+
#
|
|
149
|
+
# @param result [ Object ] the operation result.
|
|
150
|
+
# @param cursor_id [ Integer | nil ] the cursor ID before the operation.
|
|
151
|
+
# @param context [ OpenTelemetry::Context ] the OpenTelemetry context.
|
|
152
|
+
# @param span [ OpenTelemetry::Trace::Span ] the current span.
|
|
153
|
+
def process_cursor_context(result, cursor_id, context, span)
|
|
154
|
+
return unless result.is_a?(Cursor)
|
|
155
|
+
|
|
156
|
+
if result.id.zero?
|
|
157
|
+
# If the cursor is closed, remove it from the context map.
|
|
158
|
+
cursor_context_map.delete(cursor_id)
|
|
159
|
+
elsif result.id && cursor_id.nil?
|
|
160
|
+
# New cursor created, store its context.
|
|
161
|
+
cursor_context_map[result.id] = context
|
|
162
|
+
span.set_attribute('db.mongodb.cursor_id', result.id)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Extracts the collection name from the operation.
|
|
167
|
+
#
|
|
168
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
169
|
+
#
|
|
170
|
+
# @return [ String | nil ] the collection name, or nil if not applicable.
|
|
171
|
+
def collection_name(operation)
|
|
172
|
+
return operation.coll_name.to_s if operation.respond_to?(:coll_name) && operation.coll_name
|
|
173
|
+
|
|
174
|
+
extract_collection_from_spec(operation)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Extracts collection name from operation spec based on operation type.
|
|
178
|
+
#
|
|
179
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
180
|
+
#
|
|
181
|
+
# @return [ String | nil ] the collection name, or nil if not found.
|
|
182
|
+
def extract_collection_from_spec(operation)
|
|
183
|
+
collection_key = collection_key_for_operation(operation)
|
|
184
|
+
return nil unless collection_key
|
|
185
|
+
|
|
186
|
+
value = if collection_key == :first_value
|
|
187
|
+
operation.spec[:selector].values.first
|
|
188
|
+
else
|
|
189
|
+
operation.spec[:selector][collection_key]
|
|
190
|
+
end
|
|
191
|
+
value&.to_s
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Returns the collection key for a given operation type.
|
|
195
|
+
#
|
|
196
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
197
|
+
#
|
|
198
|
+
# @return [ Symbol | nil ] the collection key symbol or nil.
|
|
199
|
+
def collection_key_for_operation(operation)
|
|
200
|
+
case operation
|
|
201
|
+
when Operation::Aggregate then :aggregate
|
|
202
|
+
when Operation::Count then :count
|
|
203
|
+
when Operation::Create then :create
|
|
204
|
+
when Operation::Distinct then :distinct
|
|
205
|
+
when Operation::Drop then :drop
|
|
206
|
+
when Operation::WriteCommand then :first_value
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Generates the span name for the operation.
|
|
211
|
+
#
|
|
212
|
+
# @param operation [ Mongo::Operation ] the operation.
|
|
213
|
+
# @param op_name [ String | nil ] optional operation name.
|
|
214
|
+
#
|
|
215
|
+
# @return [ String ] span name in format "operation_name db.collection" or "operation_name db".
|
|
216
|
+
def operation_span_name(operation, op_name = nil)
|
|
217
|
+
coll_name = collection_name(operation)
|
|
218
|
+
if coll_name && !coll_name.empty?
|
|
219
|
+
"#{operation_name(operation, op_name)} #{operation.db_name}.#{coll_name}"
|
|
220
|
+
else
|
|
221
|
+
"#{operation_name(operation, op_name)} #{operation.db_name}"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025-present MongoDB Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the 'License');
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an 'AS IS' BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Mongo
|
|
18
|
+
module Tracing
|
|
19
|
+
module OpenTelemetry
|
|
20
|
+
# OpenTelemetry tracer for MongoDB operations and commands.
|
|
21
|
+
# @api private
|
|
22
|
+
class Tracer
|
|
23
|
+
# @return [ OpenTelemetry::Trace::Tracer ] the OpenTelemetry tracer implementation
|
|
24
|
+
# used to create spans for MongoDB operations and commands.
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
attr_reader :otel_tracer
|
|
28
|
+
|
|
29
|
+
# Initializes a new OpenTelemetry tracer.
|
|
30
|
+
#
|
|
31
|
+
# @param enabled [ Boolean | nil ] whether OpenTelemetry is enabled or not.
|
|
32
|
+
# Defaults to nil, which means it will check the environment variable
|
|
33
|
+
# OTEL_RUBY_INSTRUMENTATION_MONGODB_ENABLED (values: true/1/yes). If the
|
|
34
|
+
# environment variable is not set, OpenTelemetry will be disabled by default.
|
|
35
|
+
# @param query_text_max_length [ Integer | nil ] maximum length for captured query text.
|
|
36
|
+
# Defaults to nil, which means it will check the environment variable
|
|
37
|
+
# OTEL_RUBY_INSTRUMENTATION_MONGODB_QUERY_TEXT_MAX_LENGTH. If the environment variable is not set,
|
|
38
|
+
# the query text will not be captured.
|
|
39
|
+
# @param otel_tracer [ OpenTelemetry::Trace::Tracer | nil ] the OpenTelemetry tracer
|
|
40
|
+
# implementation to use. Defaults to nil, which means it will use the default tracer
|
|
41
|
+
# from OpenTelemetry's tracer provider.
|
|
42
|
+
def initialize(enabled: nil, query_text_max_length: nil, otel_tracer: nil)
|
|
43
|
+
@enabled = if enabled.nil?
|
|
44
|
+
%w[true 1 yes].include?(ENV['OTEL_RUBY_INSTRUMENTATION_MONGODB_ENABLED']&.downcase)
|
|
45
|
+
else
|
|
46
|
+
enabled
|
|
47
|
+
end
|
|
48
|
+
check_opentelemetry_loaded
|
|
49
|
+
@query_text_max_length = if query_text_max_length.nil?
|
|
50
|
+
ENV['OTEL_RUBY_INSTRUMENTATION_MONGODB_QUERY_TEXT_MAX_LENGTH'].to_i
|
|
51
|
+
else
|
|
52
|
+
query_text_max_length
|
|
53
|
+
end
|
|
54
|
+
@otel_tracer = otel_tracer || initialize_tracer
|
|
55
|
+
@operation_tracer = OperationTracer.new(@otel_tracer, self)
|
|
56
|
+
@command_tracer = CommandTracer.new(@otel_tracer, self, query_text_max_length: @query_text_max_length)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Whether OpenTelemetry is enabled or not.
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean] true if OpenTelemetry is enabled, false otherwise.
|
|
62
|
+
def enabled?
|
|
63
|
+
@enabled
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Trace a MongoDB operation.
|
|
67
|
+
#
|
|
68
|
+
# @param operation [Mongo::Operation] The MongoDB operation to trace.
|
|
69
|
+
# @param operation_context [Mongo::Operation::Context] The context of the operation.
|
|
70
|
+
# @param op_name [String, nil] An optional name for the operation.
|
|
71
|
+
# @yield The block representing the operation to be traced.
|
|
72
|
+
# @return [Object] The result of the operation.
|
|
73
|
+
def trace_operation(operation, operation_context, op_name: nil, &block)
|
|
74
|
+
return yield unless enabled?
|
|
75
|
+
|
|
76
|
+
@operation_tracer.trace_operation(operation, operation_context, op_name: op_name, &block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Trace a MongoDB command.
|
|
80
|
+
#
|
|
81
|
+
# @param message [Mongo::Protocol::Message] The MongoDB command message to trace.
|
|
82
|
+
# @param operation_context [Mongo::Operation::Context] The context of the operation.
|
|
83
|
+
# @param connection [Mongo::Server::Connection] The connection used to send the command
|
|
84
|
+
# @yield The block representing the command to be traced.
|
|
85
|
+
# @return [Object] The result of the command.
|
|
86
|
+
def trace_command(message, operation_context, connection, &block)
|
|
87
|
+
return yield unless enabled?
|
|
88
|
+
|
|
89
|
+
@command_tracer.trace_command(message, operation_context, connection, &block)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Start a transaction span and activate its context.
|
|
93
|
+
#
|
|
94
|
+
# @param session [Mongo::Session] The session starting the transaction.
|
|
95
|
+
def start_transaction_span(session)
|
|
96
|
+
return unless enabled?
|
|
97
|
+
|
|
98
|
+
key = transaction_map_key(session)
|
|
99
|
+
return unless key
|
|
100
|
+
|
|
101
|
+
# Create the transaction span with minimal attributes
|
|
102
|
+
span = @otel_tracer.start_span(
|
|
103
|
+
'transaction',
|
|
104
|
+
attributes: { 'db.system' => 'mongodb' },
|
|
105
|
+
kind: :client
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Create a context containing this span
|
|
109
|
+
context = ::OpenTelemetry::Trace.context_with_span(span)
|
|
110
|
+
|
|
111
|
+
# Activate the context and store the token for later detachment
|
|
112
|
+
token = ::OpenTelemetry::Context.attach(context)
|
|
113
|
+
|
|
114
|
+
# Store span, token, and context for later retrieval
|
|
115
|
+
transaction_span_map[key] = span
|
|
116
|
+
transaction_token_map[key] = token
|
|
117
|
+
transaction_context_map[key] = context
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Finish a transaction span and deactivate its context.
|
|
121
|
+
#
|
|
122
|
+
# @param session [Mongo::Session] The session finishing the transaction.
|
|
123
|
+
def finish_transaction_span(session)
|
|
124
|
+
return unless enabled?
|
|
125
|
+
|
|
126
|
+
key = transaction_map_key(session)
|
|
127
|
+
return unless key
|
|
128
|
+
|
|
129
|
+
span = transaction_span_map.delete(key)
|
|
130
|
+
token = transaction_token_map.delete(key)
|
|
131
|
+
transaction_context_map.delete(key)
|
|
132
|
+
|
|
133
|
+
return unless span && token
|
|
134
|
+
|
|
135
|
+
begin
|
|
136
|
+
span.finish
|
|
137
|
+
ensure
|
|
138
|
+
::OpenTelemetry::Context.detach(token)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Returns the cursor context map for tracking cursor-related OpenTelemetry contexts.
|
|
143
|
+
#
|
|
144
|
+
# @return [ Hash ] map of cursor IDs to OpenTelemetry contexts.
|
|
145
|
+
def cursor_context_map
|
|
146
|
+
@cursor_context_map ||= {}
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Generates a unique key for cursor tracking in the context map.
|
|
150
|
+
#
|
|
151
|
+
# @param session [ Mongo::Session ] the session associated with the cursor.
|
|
152
|
+
# @param cursor_id [ Integer ] the cursor ID.
|
|
153
|
+
#
|
|
154
|
+
# @return [ String | nil ] unique key combining session ID and cursor ID, or nil if either is nil.
|
|
155
|
+
def cursor_map_key(session, cursor_id)
|
|
156
|
+
return if cursor_id.nil? || session.nil?
|
|
157
|
+
|
|
158
|
+
"#{session.session_id['id'].to_uuid}-#{cursor_id}"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Determines the parent OpenTelemetry context for an operation.
|
|
162
|
+
#
|
|
163
|
+
# Returns the transaction context if the operation is part of a transaction,
|
|
164
|
+
# otherwise returns nil. Cursor-based context nesting is not currently implemented.
|
|
165
|
+
#
|
|
166
|
+
# @param operation_context [ Mongo::Operation::Context ] the operation context.
|
|
167
|
+
# @param cursor_id [ Integer ] the cursor ID, if applicable.
|
|
168
|
+
#
|
|
169
|
+
# @return [ OpenTelemetry::Context | nil ] parent context or nil.
|
|
170
|
+
def parent_context_for(operation_context, cursor_id)
|
|
171
|
+
if (key = transaction_map_key(operation_context.session))
|
|
172
|
+
transaction_context_map[key]
|
|
173
|
+
elsif (_key = cursor_map_key(operation_context.session, cursor_id))
|
|
174
|
+
# We return nil here unless we decide how to nest cursor operations.
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Returns the transaction context map for tracking active transaction contexts.
|
|
180
|
+
#
|
|
181
|
+
# @return [ Hash ] map of transaction keys to OpenTelemetry contexts.
|
|
182
|
+
def transaction_context_map
|
|
183
|
+
@transaction_context_map ||= {}
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Returns the transaction span map for tracking active transaction spans.
|
|
187
|
+
#
|
|
188
|
+
# @return [ Hash ] map of transaction keys to OpenTelemetry spans.
|
|
189
|
+
def transaction_span_map
|
|
190
|
+
@transaction_span_map ||= {}
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Returns the transaction token map for tracking context attachment tokens.
|
|
194
|
+
#
|
|
195
|
+
# @return [ Hash ] map of transaction keys to OpenTelemetry context tokens.
|
|
196
|
+
def transaction_token_map
|
|
197
|
+
@transaction_token_map ||= {}
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Generates a unique key for transaction tracking.
|
|
201
|
+
#
|
|
202
|
+
# Returns nil for implicit sessions or sessions not in a transaction.
|
|
203
|
+
#
|
|
204
|
+
# @param session [ Mongo::Session ] the session.
|
|
205
|
+
#
|
|
206
|
+
# @return [ String | nil ] unique key combining session ID and transaction number, or nil.
|
|
207
|
+
def transaction_map_key(session)
|
|
208
|
+
return if session.nil? || session.implicit? || !session.in_transaction?
|
|
209
|
+
|
|
210
|
+
"#{session.session_id['id'].to_uuid}-#{session.txn_num}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
private
|
|
214
|
+
|
|
215
|
+
def check_opentelemetry_loaded
|
|
216
|
+
return unless @enabled
|
|
217
|
+
return if defined?(::OpenTelemetry)
|
|
218
|
+
|
|
219
|
+
Logger.logger.warn('OpenTelemetry tracing for MongoDB is enabled, ' \
|
|
220
|
+
'but the OpenTelemetry library is not loaded. ' \
|
|
221
|
+
'Disabling tracing.')
|
|
222
|
+
@enabled = false
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def initialize_tracer
|
|
226
|
+
return unless enabled?
|
|
227
|
+
|
|
228
|
+
::OpenTelemetry.tracer_provider.tracer(
|
|
229
|
+
'mongo-ruby-driver',
|
|
230
|
+
Mongo::VERSION
|
|
231
|
+
)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025-present MongoDB Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the 'License');
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an 'AS IS' BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Mongo
|
|
18
|
+
module Tracing
|
|
19
|
+
# This module contains OpenTelemetry tracing functionality for MongoDB operations.
|
|
20
|
+
module OpenTelemetry
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require 'mongo/tracing/open_telemetry/command_tracer'
|
|
26
|
+
require 'mongo/tracing/open_telemetry/operation_tracer'
|
|
27
|
+
require 'mongo/tracing/open_telemetry/tracer'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025-present MongoDB Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the 'License');
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an 'AS IS' BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Mongo
|
|
18
|
+
# Provides OpenTelemetry tracing capabilities for MongoDB operations.
|
|
19
|
+
module Tracing
|
|
20
|
+
# Creates a new OpenTelemetry tracer for instrumenting MongoDB operations.
|
|
21
|
+
#
|
|
22
|
+
# @param enabled [Boolean, nil] Whether tracing is enabled. Default to nil, which
|
|
23
|
+
# means it will check the environment variable OTEL_RUBY_INSTRUMENTATION_MONGODB_ENABLED.
|
|
24
|
+
# See +Mongo::Tracing::OpenTelemetry::Tracer+ for details.
|
|
25
|
+
# @param query_text_max_length [Integer, nil] Maximum length for captured query text. Default to nil,
|
|
26
|
+
# which means it will check the environment variable OTEL_RUBY_INSTRUMENTATION_MONGODB_QUERY_TEXT_MAX_LENGTH.
|
|
27
|
+
# See +Mongo::Tracing::OpenTelemetry::Tracer+ for details.
|
|
28
|
+
# @param otel_tracer [OpenTelemetry::Trace::Tracer, nil] Custom OpenTelemetry tracer instance.
|
|
29
|
+
#
|
|
30
|
+
# @return [Mongo::Tracing::OpenTelemetry::Tracer] Configured tracer instance.
|
|
31
|
+
def create_tracer(enabled: nil, query_text_max_length: nil, otel_tracer: nil)
|
|
32
|
+
OpenTelemetry::Tracer.new(
|
|
33
|
+
enabled: enabled,
|
|
34
|
+
query_text_max_length: query_text_max_length,
|
|
35
|
+
otel_tracer: otel_tracer
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
module_function :create_tracer
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
require 'mongo/tracing/open_telemetry'
|
|
@@ -122,11 +122,13 @@ module Mongo
|
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
# Gets the SRV resolver.
|
|
125
|
+
# If domain verification fails or no SRV records are found,
|
|
126
|
+
# an error must not be raised per the spec; instead, a warning is logged.
|
|
125
127
|
#
|
|
126
128
|
# @return [ Mongo::Srv::Resolver ]
|
|
127
129
|
def resolver
|
|
128
130
|
@resolver ||= Srv::Resolver.new(
|
|
129
|
-
raise_on_invalid:
|
|
131
|
+
raise_on_invalid: false,
|
|
130
132
|
resolv_options: options[:resolv_options],
|
|
131
133
|
timeout: options[:connect_timeout],
|
|
132
134
|
)
|
|
@@ -149,7 +151,11 @@ module Mongo
|
|
|
149
151
|
|
|
150
152
|
log_debug "attempting to resolve #{hostname}"
|
|
151
153
|
|
|
152
|
-
@srv_result = resolver.get_records(
|
|
154
|
+
@srv_result = resolver.get_records(
|
|
155
|
+
hostname,
|
|
156
|
+
uri_options[:srv_service_name] || options[:srv_service_name],
|
|
157
|
+
uri_options[:srv_max_hosts] || options[:srv_max_hosts]
|
|
158
|
+
)
|
|
153
159
|
if srv_result.empty?
|
|
154
160
|
raise Error::NoSRVRecords.new(NO_SRV_RECORDS % hostname)
|
|
155
161
|
end
|
|
@@ -168,8 +174,7 @@ module Mongo
|
|
|
168
174
|
# The hostname cannot include a port.
|
|
169
175
|
#
|
|
170
176
|
# The hostname must not begin with a dot, end with a dot, or have
|
|
171
|
-
# consecutive dots. The hostname must have a minimum of
|
|
172
|
-
# components (foo.bar.tld).
|
|
177
|
+
# consecutive dots. The hostname must have a minimum of 1 component
|
|
173
178
|
#
|
|
174
179
|
# Raises Error::InvalidURI if validation fails.
|
|
175
180
|
def validate_srv_hostname(hostname)
|
|
@@ -185,8 +190,8 @@ module Mongo
|
|
|
185
190
|
if parts.any?(&:empty?)
|
|
186
191
|
raise_invalid_error!("Hostname cannot have consecutive dots: #{hostname}")
|
|
187
192
|
end
|
|
188
|
-
if parts.length <
|
|
189
|
-
raise_invalid_error!("Hostname
|
|
193
|
+
if parts.length < 1
|
|
194
|
+
raise_invalid_error!("Hostname cannot be empty: #{hostname}")
|
|
190
195
|
end
|
|
191
196
|
end
|
|
192
197
|
|
data/lib/mongo/version.rb
CHANGED
data/lib/mongo.rb
CHANGED
|
@@ -42,6 +42,7 @@ require 'mongo/condition_variable'
|
|
|
42
42
|
require 'mongo/csot_timeout_holder'
|
|
43
43
|
require 'mongo/options'
|
|
44
44
|
require 'mongo/loggable'
|
|
45
|
+
require 'mongo/deprecations'
|
|
45
46
|
require 'mongo/cluster_time'
|
|
46
47
|
require 'mongo/topology_version'
|
|
47
48
|
require 'mongo/monitoring'
|
|
@@ -74,6 +75,7 @@ require 'mongo/session'
|
|
|
74
75
|
require 'mongo/socket'
|
|
75
76
|
require 'mongo/srv'
|
|
76
77
|
require 'mongo/timeout'
|
|
78
|
+
require 'mongo/tracing'
|
|
77
79
|
require 'mongo/uri'
|
|
78
80
|
require 'mongo/version'
|
|
79
81
|
require 'mongo/write_concern'
|
|
@@ -100,6 +102,7 @@ module Mongo
|
|
|
100
102
|
delegate_option Config, :broken_view_aggregate
|
|
101
103
|
delegate_option Config, :broken_view_options
|
|
102
104
|
delegate_option Config, :validate_update_replace
|
|
105
|
+
delegate_option Config, :csfle_convert_to_ruby_types
|
|
103
106
|
end
|
|
104
107
|
|
|
105
108
|
# Clears the driver's OCSP response cache.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mongo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The MongoDB Ruby Team
|
|
@@ -193,6 +193,7 @@ files:
|
|
|
193
193
|
- lib/mongo/database.rb
|
|
194
194
|
- lib/mongo/database/view.rb
|
|
195
195
|
- lib/mongo/dbref.rb
|
|
196
|
+
- lib/mongo/deprecations.rb
|
|
196
197
|
- lib/mongo/distinguishing_semaphore.rb
|
|
197
198
|
- lib/mongo/error.rb
|
|
198
199
|
- lib/mongo/error/auth_error.rb
|
|
@@ -520,6 +521,11 @@ files:
|
|
|
520
521
|
- lib/mongo/srv/result.rb
|
|
521
522
|
- lib/mongo/timeout.rb
|
|
522
523
|
- lib/mongo/topology_version.rb
|
|
524
|
+
- lib/mongo/tracing.rb
|
|
525
|
+
- lib/mongo/tracing/open_telemetry.rb
|
|
526
|
+
- lib/mongo/tracing/open_telemetry/command_tracer.rb
|
|
527
|
+
- lib/mongo/tracing/open_telemetry/operation_tracer.rb
|
|
528
|
+
- lib/mongo/tracing/open_telemetry/tracer.rb
|
|
523
529
|
- lib/mongo/uri.rb
|
|
524
530
|
- lib/mongo/uri/options_mapper.rb
|
|
525
531
|
- lib/mongo/uri/srv_protocol.rb
|
|
@@ -553,7 +559,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
553
559
|
- !ruby/object:Gem::Version
|
|
554
560
|
version: '0'
|
|
555
561
|
requirements: []
|
|
556
|
-
rubygems_version:
|
|
562
|
+
rubygems_version: 4.0.5
|
|
557
563
|
specification_version: 4
|
|
558
564
|
summary: Ruby driver for MongoDB
|
|
559
565
|
test_files: []
|