Class: Mongo::Tracing::OpenTelemetry::CommandTracer Private
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Instance Chain:
|
|
| Inherits: | Object |
| Defined in: | lib/mongo/tracing/open_telemetry/command_tracer.rb |
Overview
CommandTracer is responsible for tracing MongoDB server commands using ::Mongo::Tracing::OpenTelemetry.
Constant Summary
-
ELLIPSIS =
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 324
Ellipsis for truncated query text.
'...' -
EXCLUDED_KEYS =
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 321
Keys to exclude from query text capture.
%w[lsid $db $clusterTime signature].freeze
-
HELLO_COMMANDS =
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 31
Commands for which a span MUST NOT be created. The OpenTelemetry spec requires drivers to skip command spans for sensitive commands listed in the Command Logging and
::Mongo::Monitoringspec. We additionally skip hello / legacy hello in all forms — these are handshake/heartbeat traffic and would only add noise to traces.%w[hello ismaster isMaster].freeze
::Mongo::Monitoring::Event::Secure - Included
Class Method Summary
-
.new(otel_tracer, parent_tracer, query_text_max_length: 0) ⇒ CommandTracer
constructor
Internal use only
Initializes a new
CommandTracer.
Instance Attribute Summary
-
#query_text? ⇒ Boolean
readonly
private
Internal use only
Checks if query text capture is enabled.
Instance Method Summary
-
#start_span(message, operation_context, connection)
Internal use only
Starts a span for a MongoDB command.
-
#trace_command(message, _operation_context, connection) { ... } ⇒ Object
Internal use only
Trace a MongoDB command.
-
#base_attributes(message) ⇒ Hash
private
Internal use only
Returns base database and command attributes.
-
#collection_name(message) ⇒ String | nil
private
Internal use only
Extracts the collection name from the command message.
-
#command_name(message) ⇒ String
private
Internal use only
Extracts the command name from the message.
-
#connection_attributes(connection) ⇒ Hash
private
Internal use only
Returns connection-related attributes.
-
#create_command_span(message, connection) ⇒ OpenTelemetry::Trace::Span
private
Internal use only
Creates a span for a command.
-
#cursor_id(message) ⇒ Integer | nil
private
Internal use only
Extracts the cursor ID from getMore commands.
-
#database(message) ⇒ String
private
Internal use only
Extracts the database name from the message.
-
#handle_command_exception(span, exception)
private
Internal use only
Handles exceptions that occur during command execution.
-
#lsid(message) ⇒ BSON::Binary | nil
private
Internal use only
Extracts the logical session ID from the command.
-
#maybe_trace_error(result, span)
private
Internal use only
Records error status code if the command failed.
-
#process_command_result(result, cursor_id, context, span)
private
Internal use only
Processes the command result and updates span attributes.
-
#process_cursor_context(result, _cursor_id, _context, span)
private
Internal use only
Processes cursor context from the command result.
-
#query_summary(message) ⇒ String
private
Internal use only
Generates a summary string for the query.
-
#query_text(message) ⇒ String | nil
readonly
private
Internal use only
Extracts and formats the query text from the command.
-
#session_attributes(message) ⇒ Hash
private
Internal use only
Returns session and transaction attributes.
-
#skip_tracing?(message) ⇒ Boolean
private
Internal use only
Determines whether the command must not be traced.
-
#span_attributes(message, connection) ⇒ Hash
private
Internal use only
Builds span attributes for the command.
-
#txn_number(message) ⇒ Integer | nil
private
Internal use only
Extracts the transaction number from the command.
::Mongo::Monitoring::Event::Secure - Included
| #compression_allowed? | Is compression allowed for a given command message. |
| #redacted | Redact secure information from the document if: |
| #sensitive? | Check whether the command is sensitive in terms of command monitoring spec. |
Instance Attribute Details
#query_text? ⇒ Boolean (readonly, private)
Checks if query text capture is enabled.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 281
def query_text? @query_text_max_length.positive? end
Instance Method Details
#base_attributes(message) ⇒ Hash (private)
Returns base database and command attributes.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 163
def base_attributes() { 'db.system.name' => 'mongodb', 'db.namespace' => database(), 'db.collection.name' => collection_name(), 'db.command.name' => command_name(), 'db.query.summary' => query_summary(), 'db.query.text' => query_text() } end
#collection_name(message) ⇒ String | nil (private)
Extracts the collection name from the command message.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 247
def collection_name() case command_name() when 'getMore' .documents.first['collection'].to_s when 'listCollections', 'listDatabases', 'commitTransaction', 'abortTransaction' nil else value = .documents.first.values.first # Return nil if the value is not a string (e.g., for admin commands that have numeric values) value.is_a?(String) ? value : nil end end
#command_name(message) ⇒ String (private)
Extracts the command name from the message.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 265
def command_name() .documents.first.keys.first.to_s end
#connection_attributes(connection) ⇒ Hash (private)
Returns connection-related attributes.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 179
def connection_attributes(connection) { 'server.port' => connection.address.port, 'server.address' => connection.address.host, 'network.transport' => connection.transport.to_s, 'db.mongodb.server_connection_id' => connection.server.description.server_connection_id, 'db.mongodb.driver_connection_id' => connection.id } end
#create_command_span(message, connection) ⇒ OpenTelemetry::Trace::Span (private)
Creates a span for a command.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 112
def create_command_span(, connection) @otel_tracer.start_span( command_name(), attributes: span_attributes(, connection), kind: :client ) end
#cursor_id(message) ⇒ Integer | nil (private)
Extracts the cursor ID from getMore commands.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 290
def cursor_id() return unless command_name() == 'getMore' .documents.first['getMore'].value end
#database(message) ⇒ String (private)
Extracts the database name from the message.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 274
def database() .documents.first['$db'].to_s end
#handle_command_exception(span, exception) (private)
Handles exceptions that occur during command execution.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 135
def handle_command_exception(span, exception) return unless span if exception.is_a?(Mongo::Error::OperationFailure) span.set_attribute('db.response.status_code', exception.code.to_s) end span.record_exception(exception) span.status = ::OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{exception.class}") end
#lsid(message) ⇒ BSON::Binary | nil (private)
Extracts the logical session ID from the command.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 301
def lsid() lsid_doc = .documents.first['lsid'] return unless lsid_doc lsid_doc['id'].to_uuid end
#maybe_trace_error(result, span) (private)
Records error status code if the command failed.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 218
def maybe_trace_error(result, span) return if result.successful? span.set_attribute('db.response.status_code', result.error.code.to_s) begin result.validate! rescue Mongo::Error::OperationFailure => e span.record_exception(e) end end
#process_command_result(result, cursor_id, context, span) (private)
Processes the command result and updates span attributes.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 126
def process_command_result(result, cursor_id, context, span) process_cursor_context(result, cursor_id, context, span) maybe_trace_error(result, span) end
#process_cursor_context(result, _cursor_id, _context, span) (private)
Processes cursor context from the command result.
#query_summary(message) ⇒ String (private)
Generates a summary string for the query.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 234
def query_summary() if (coll_name = collection_name()) "#{command_name()} #{database()}.#{coll_name}" else "#{command_name()} #{database()}" end end
#query_text(message) ⇒ String | nil (readonly, private)
Extracts and formats the query text from the command.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 331
def query_text() return unless query_text? text = .payload['command'] .reject { |key, _| EXCLUDED_KEYS.include?(key) } .to_json if text.length > @query_text_max_length "#{text[0...@query_text_max_length]}#{ELLIPSIS}" else text end end
#session_attributes(message) ⇒ Hash (private)
Returns session and transaction attributes.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 194
def session_attributes() { 'db.mongodb.cursor_id' => cursor_id(), 'db.mongodb.lsid' => lsid(), 'db.mongodb.txn_number' => txn_number() } end
#skip_tracing?(message) ⇒ Boolean (private)
Determines whether the command must not be traced. Sensitive auth
commands carry credentials in their payloads (SCRAM proofs, cleartext
passwords, etc.) and the ::Mongo::Tracing::OpenTelemetry spec requires drivers to skip
command spans for them. Hello / legacy hello are also skipped to keep
handshake traffic out of traces.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 99
def skip_tracing?() name = command_name() return true if HELLO_COMMANDS.include?(name) sensitive?(command_name: name, document: .documents.first) end
#span_attributes(message, connection) ⇒ Hash (private)
Builds span attributes for the command.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 151
def span_attributes(, connection) base_attributes() .merge(connection_attributes(connection)) .merge(session_attributes()) .compact end
#start_span(message, operation_context, connection)
Starts a span for a MongoDB command.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 51
def start_span(, operation_context, connection); end
#trace_command(message, _operation_context, connection) { ... } ⇒ Object
Trace a MongoDB command.
Creates an ::Mongo::Tracing::OpenTelemetry span for the command, capturing attributes such as
command name, database name, collection name, server address, connection IDs,
and optionally query text. The span is automatically nested under the current
operation span and is finished when the command completes or fails.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 68
def trace_command(, _operation_context, connection) return yield if skip_tracing?() # Commands should always be nested under their operation span, not directly under # the transaction span. Don't pass with_parent to use automatic parent resolution # from the currently active span (the operation span). span = create_command_span(, connection) ::OpenTelemetry::Trace.with_span(span) do |s, c| yield.tap do |result| process_command_result(result, cursor_id(), c, s) end end rescue Exception => e handle_command_exception(span, e) raise e ensure span&.finish end
#txn_number(message) ⇒ Integer | nil (private)
Extracts the transaction number from the command.
# File 'lib/mongo/tracing/open_telemetry/command_tracer.rb', line 313
def txn_number() txn_num = .documents.first['txnNumber'] return unless txn_num txn_num.value end