lib/one_apm/inst/nosql/mongo2.rb in oneapm_rpm-1.2.9 vs lib/one_apm/inst/nosql/mongo2.rb in oneapm_rpm-1.3.0.rc1
- old
+ new
@@ -1,87 +1,116 @@
# encoding: utf-8
-LibraryDetection.defer do
- named :mongo2
+module OneApm
+ module Agent
+ module Instrumentation
+ class MongoCommandSubscriber
- depends_on do
- require 'one_apm/agent/datastore/mongo'
- defined?(::Mongo) && OneApm::Agent::Datastore::Mongo.is_version2? && !OneApm::Manager.config[:disable_mongo]
- end
+ MONGODB = 'MongoDB'.freeze
+ STARTED = 'STARTED'.freeze
+ SUCCEEDED = 'SUCCEEDED'.freeze
+ FAILED = 'FAILED'.freeze
- executes do
- OneApm::Manager.logger.info 'Installing Mongo 2 instrumentation'
- install_mongo_instrumentation
- end
+ def started(event)
+ begin
+ return unless OneApm::Manager.tl_is_execution_traced?
+ operations[event.operation_id] = event
+ rescue Exception => e
+ log_operations_error(STARTED, e)
+ end
+ end
- def install_mongo_instrumentation
- require 'one_apm/agent/datastore/mongo/metric_translator'
- require 'one_apm/agent/datastore/mongo/statement_formatter'
- hook_instrument_method_for_collection
- hook_instrument_method_for_view
- end
+ def succeeded(event)
+ operator SUCCEEDED, event
+ end
- def hook_instrument_method_for_collection
- methods = [:create,:drop, :find, :indexes, :insert_one, :insert_many, :bulk_write, :parallel_scan]
- instrument_methods_with_oneapm(::Mongo::Collection, methods)
- end
+ def failed(event)
+ operator FAILED, event
+ end
+ private
- def hook_instrument_method_for_view
- methods = [:count, :distinct, :map_reduce,:find_one_and_delete, :find_one_and_replace, :find_one_and_update,
- :delete_many, :delete_one, :replace_one, :update_many, :update_one]
- instrument_methods_with_oneapm(::Mongo::Collection::View, methods)
- end
+ def operations
+ @operations ||= {}
+ end
+ def mertircs(event)
+ OneApm::Agent::Datastore::MetricHelper.metrics_for(
+ MONGODB, event.command_name, event.command.values.first
+ )
+ end
- def instrument_methods_with_oneapm klass, methods
- klass.class_eval do
- include OneApm::Support::MethodTracer
+ def operator(operator_type, event)
+ begin
+ state = OneApm::TransactionState.tl_get
+ return unless state.is_execution_traced?
+ stared_event = operations.delete(event.operation_id)
+ one_apm_generate_metrics(stared_event, event.duration)
+ one_apm_notice_statement(stared_event, operator_type, event.duration)
+ one_apm_notice_sql(state, stared_event, operator_type, event.duration)
+ rescue => e
+ log_operations_error(operator_type, e)
+ end
+ end
- def payload_for_oneapm
- collection = self.name rescue self.collection.name
- @payload_for_oneapm ||= { :collection => collection, :database => self.database.name }
- end
-
- def one_apm_notice_statement(t0, name)
- statement = OneApm::Agent::Datastore::Mongo::StatementFormatter.format(payload_for_oneapm, name)
- if statement
- OneApm::Manager.agent.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
+ def one_apm_generate_metrics(event, duration)
+ base, *other_metrics = mertircs(event)
+ OneApm::Manager.agent.stats_engine.tl_record_scoped_and_unscoped_metrics(
+ base, other_metrics, duration
+ )
end
- rescue => e
- OneApm::Manager.logger.debug("Exception during Mongo statement gathering", e)
- end
- def one_apm_generate_metrics(operation)
- OneApm::Agent::Datastore::Mongo::MetricTranslator.metrics_for(operation, payload_for_oneapm)
- end
- end
+ def one_apm_notice_sql(state, event, status, duration)
+ stack = state.traced_method_stack
+ base, *other_metrics = mertircs(event)
- methods.each do |method_name|
- next unless klass.method_defined?(method_name)
+ started_time = Time.now.to_f
+ frame = stack.push_frame(state, :mongo_tracer, started_time)
- klass.class_eval do
+ builder = state.transaction_sample_builder
+ format_sql = OneApm::Agent::Datastore::Mongo::CommandFormatter.format_sql(event, status)
+ OneApm::Manager.agent.transaction_sampler.send(:notice_extra_data, builder, format_sql, duration, :sql)
- method_name_without_oneapm = :"#{method_name}_without_oneapm"
- method_name_with_oneapm = :"#{method_name}_with_oneapm"
+ stack.pop_frame(state, frame, base, started_time + duration)
+ end
- define_method method_name_with_oneapm do |*args, &block|
- metrics = one_apm_generate_metrics(method_name)
-
- trace_execution_scoped(metrics) do
- t0 = Time.now
- result = OneApm::Manager.disable_all_tracing do
- send method_name_without_oneapm, *args, &block
- end
- one_apm_notice_statement(t0, method_name)
- result
+ def one_apm_notice_statement(event, status, duration)
+ statement = OneApm::Agent::Datastore::Mongo::CommandFormatter.format(event, status)
+ if statement
+ OneApm::Manager.agent.transaction_sampler.notice_nosql_statement(statement, duration)
end
-
+ rescue => e
+ OneApm::Manager.logger.debug("Exception during Mongo statement gathering", e)
end
- alias_method method_name_without_oneapm, method_name.to_sym
- alias_method method_name.to_sym, method_name_with_oneapm
+
+ def log_operations_error(event_type, error)
+ OneApm::Manager.logger.error("Error during MongoDB #{event_type} event:")
+ OneApm::Manager.logger.log_exception(:error, error)
+ end
+
end
end
-
end
-
end
+
+LibraryDetection.defer do
+ named :mongo2
+
+ depends_on do
+ require 'one_apm/agent/datastore/mongo'
+ defined?(::Mongo) && OneApm::Agent::Datastore::Mongo.is_support_version2? && !OneApm::Manager.config[:disable_mongo]
+ end
+
+ executes do
+ OneApm::Manager.logger.info 'Installing Mongo 2 instrumentation'
+ install_mongo_command_subscriber
+ end
+
+ def install_mongo_command_subscriber
+ require 'one_apm/agent/datastore/metric_helper'
+ require 'one_apm/agent/datastore/mongo/command_formatter'
+ ::Mongo::Monitoring::Global.subscribe(
+ ::Mongo::Monitoring::COMMAND,
+ OneApm::Agent::Instrumentation::MongoCommandSubscriber.new
+ )
+ end
+end
\ No newline at end of file