oneapm_rpm 1.1.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 +7 -0
- data/.gitignore +30 -0
- data/.rubocop.yml +725 -0
- data/Gemfile +3 -0
- data/Guardfile +7 -0
- data/LICENSE +1 -0
- data/README.md +3 -0
- data/config/cert/cacert.pem +1177 -0
- data/config/database.yml +5 -0
- data/lib/initializers/goliath.rb +11 -0
- data/lib/initializers/other.rb +1 -0
- data/lib/initializers/rails.rb +15 -0
- data/lib/one_apm/agent.rb +253 -0
- data/lib/one_apm/agent/agent.rb +283 -0
- data/lib/one_apm/agent/agent/connect.rb +175 -0
- data/lib/one_apm/agent/agent/container_data_manager.rb +218 -0
- data/lib/one_apm/agent/agent/forkable_dispatcher_functions.rb +96 -0
- data/lib/one_apm/agent/agent/helpers.rb +45 -0
- data/lib/one_apm/agent/agent/start.rb +226 -0
- data/lib/one_apm/agent/agent/start_worker_thread.rb +148 -0
- data/lib/one_apm/agent/busy_calculator.rb +115 -0
- data/lib/one_apm/agent/cross_app/cross_app_monitor.rb +181 -0
- data/lib/one_apm/agent/cross_app/cross_app_tracing.rb +336 -0
- data/lib/one_apm/agent/database.rb +308 -0
- data/lib/one_apm/agent/database/active_record_helper.rb +80 -0
- data/lib/one_apm/agent/database/obfuscation_helpers.rb +76 -0
- data/lib/one_apm/agent/database/obfuscator.rb +78 -0
- data/lib/one_apm/agent/database/postgres_explain_obfuscator.rb +45 -0
- data/lib/one_apm/agent/datastores.rb +175 -0
- data/lib/one_apm/agent/datastores/metric_helper.rb +83 -0
- data/lib/one_apm/agent/datastores/mongo.rb +27 -0
- data/lib/one_apm/agent/datastores/mongo/metric_translator.rb +189 -0
- data/lib/one_apm/agent/datastores/mongo/obfuscator.rb +37 -0
- data/lib/one_apm/agent/datastores/mongo/statement_formatter.rb +51 -0
- data/lib/one_apm/agent/event/event_listener.rb +40 -0
- data/lib/one_apm/agent/event/event_loop.rb +191 -0
- data/lib/one_apm/agent/event/worker_loop.rb +97 -0
- data/lib/one_apm/agent/harvester.rb +48 -0
- data/lib/one_apm/agent/inbound_request_monitor.rb +30 -0
- data/lib/one_apm/agent/javascript_instrumentor.rb +186 -0
- data/lib/one_apm/agent/pipe/pipe_channel_manager.rb +275 -0
- data/lib/one_apm/agent/pipe/pipe_service.rb +81 -0
- data/lib/one_apm/agent/sampler.rb +55 -0
- data/lib/one_apm/agent/sampler_collection.rb +65 -0
- data/lib/one_apm/agent/samplers/cpu_sampler.rb +49 -0
- data/lib/one_apm/agent/samplers/delayed_job_sampler.rb +109 -0
- data/lib/one_apm/agent/samplers/memory_sampler.rb +144 -0
- data/lib/one_apm/agent/samplers/object_sampler.rb +22 -0
- data/lib/one_apm/agent/samplers/vm_sampler.rb +124 -0
- data/lib/one_apm/agent/synthetics_monitor.rb +48 -0
- data/lib/one_apm/agent/threading/agent_thread.rb +74 -0
- data/lib/one_apm/agent/threading/backtrace_node.rb +133 -0
- data/lib/one_apm/agent/threading/backtrace_service.rb +259 -0
- data/lib/one_apm/agent/threading/thread_profile.rb +155 -0
- data/lib/one_apm/collector/collector/helper.rb +139 -0
- data/lib/one_apm/collector/collector/http_connection.rb +254 -0
- data/lib/one_apm/collector/collector/server_methods.rb +71 -0
- data/lib/one_apm/collector/collector_service.rb +123 -0
- data/lib/one_apm/collector/commands/agent_command.rb +17 -0
- data/lib/one_apm/collector/commands/thread_profiler_session.rb +108 -0
- data/lib/one_apm/collector/commands/xray_session.rb +53 -0
- data/lib/one_apm/collector/commands/xray_session_collection.rb +156 -0
- data/lib/one_apm/collector/containers/agent_command_router.rb +153 -0
- data/lib/one_apm/collector/containers/custom_event_aggregator.rb +94 -0
- data/lib/one_apm/collector/containers/error_collector.rb +349 -0
- data/lib/one_apm/collector/containers/sql_sampler.rb +331 -0
- data/lib/one_apm/collector/containers/stats_engine.rb +34 -0
- data/lib/one_apm/collector/containers/transaction_event_aggregator.rb +249 -0
- data/lib/one_apm/collector/containers/transaction_sampler.rb +352 -0
- data/lib/one_apm/collector/containers/utilization_data.rb +36 -0
- data/lib/one_apm/collector/stats_engine/gc_profiler.rb +106 -0
- data/lib/one_apm/collector/stats_engine/metric_stats.rb +243 -0
- data/lib/one_apm/collector/stats_engine/stats_hash.rb +105 -0
- data/lib/one_apm/configuration.rb +429 -0
- data/lib/one_apm/configuration/autostart.rb +41 -0
- data/lib/one_apm/configuration/default_source.rb +1026 -0
- data/lib/one_apm/configuration/environment_source.rb +113 -0
- data/lib/one_apm/configuration/high_security_source.rb +56 -0
- data/lib/one_apm/configuration/manual_source.rb +13 -0
- data/lib/one_apm/configuration/server_source.rb +60 -0
- data/lib/one_apm/configuration/yaml_source.rb +134 -0
- data/lib/one_apm/errors/agent_errors.rb +26 -0
- data/lib/one_apm/errors/internal_agent_error.rb +16 -0
- data/lib/one_apm/errors/noticed_error.rb +79 -0
- data/lib/one_apm/frameworks/external.rb +15 -0
- data/lib/one_apm/frameworks/rails.rb +103 -0
- data/lib/one_apm/frameworks/rails3.rb +37 -0
- data/lib/one_apm/frameworks/rails4.rb +21 -0
- data/lib/one_apm/frameworks/ruby.rb +21 -0
- data/lib/one_apm/frameworks/sinatra.rb +12 -0
- data/lib/one_apm/inst/3rd/active_merchant.rb +35 -0
- data/lib/one_apm/inst/3rd/acts_as_solr.rb +70 -0
- data/lib/one_apm/inst/3rd/authlogic.rb +23 -0
- data/lib/one_apm/inst/3rd/sunspot.rb +31 -0
- data/lib/one_apm/inst/background_job/active_job.rb +88 -0
- data/lib/one_apm/inst/background_job/delayed_job.rb +52 -0
- data/lib/one_apm/inst/background_job/delayed_job_injection.rb +8 -0
- data/lib/one_apm/inst/background_job/resque.rb +107 -0
- data/lib/one_apm/inst/background_job/sidekiq.rb +64 -0
- data/lib/one_apm/inst/dispatcher/passenger.rb +25 -0
- data/lib/one_apm/inst/dispatcher/rainbows.rb +23 -0
- data/lib/one_apm/inst/framework/grape.rb +94 -0
- data/lib/one_apm/inst/framework/padrino.rb +30 -0
- data/lib/one_apm/inst/framework/sinatra.rb +185 -0
- data/lib/one_apm/inst/framework/sinatra/ignorer.rb +50 -0
- data/lib/one_apm/inst/framework/sinatra/transaction_namer.rb +54 -0
- data/lib/one_apm/inst/http_clients/curb.rb +189 -0
- data/lib/one_apm/inst/http_clients/excon.rb +70 -0
- data/lib/one_apm/inst/http_clients/excon/connection.rb +31 -0
- data/lib/one_apm/inst/http_clients/excon/middleware.rb +55 -0
- data/lib/one_apm/inst/http_clients/httpclient.rb +44 -0
- data/lib/one_apm/inst/http_clients/net.rb +34 -0
- data/lib/one_apm/inst/http_clients/typhoeus.rb +76 -0
- data/lib/one_apm/inst/nosql/memcache.rb +134 -0
- data/lib/one_apm/inst/nosql/mongo.rb +126 -0
- data/lib/one_apm/inst/nosql/mongo_moped.rb +85 -0
- data/lib/one_apm/inst/nosql/redis.rb +83 -0
- data/lib/one_apm/inst/orm/active_record.rb +99 -0
- data/lib/one_apm/inst/orm/active_record_4.rb +28 -0
- data/lib/one_apm/inst/orm/data_mapper.rb +180 -0
- data/lib/one_apm/inst/orm/sequel.rb +47 -0
- data/lib/one_apm/inst/rack.rb +38 -0
- data/lib/one_apm/inst/rack/rack.rb +44 -0
- data/lib/one_apm/inst/rack/rack_builder.rb +51 -0
- data/lib/one_apm/inst/rails/action_controller.rb +118 -0
- data/lib/one_apm/inst/rails/action_web_service.rb +44 -0
- data/lib/one_apm/inst/rails/errors.rb +43 -0
- data/lib/one_apm/inst/rails3/action_controller.rb +172 -0
- data/lib/one_apm/inst/rails3/errors.rb +43 -0
- data/lib/one_apm/inst/rails4/action_controller.rb +27 -0
- data/lib/one_apm/inst/rails4/action_controller_subscriber.rb +121 -0
- data/lib/one_apm/inst/rails4/action_view.rb +23 -0
- data/lib/one_apm/inst/rails4/action_view_subscriber.rb +93 -0
- data/lib/one_apm/inst/rails4/active_record_subscriber.rb +96 -0
- data/lib/one_apm/inst/rails4/errors.rb +42 -0
- data/lib/one_apm/inst/rails_middleware.rb +40 -0
- data/lib/one_apm/inst/support/evented_subscriber.rb +98 -0
- data/lib/one_apm/inst/support/ignore_actions.rb +39 -0
- data/lib/one_apm/inst/support/queue_time.rb +76 -0
- data/lib/one_apm/inst/transaction_base.rb +405 -0
- data/lib/one_apm/logger/agent_logger.rb +206 -0
- data/lib/one_apm/logger/audit_logger.rb +78 -0
- data/lib/one_apm/logger/memory_logger.rb +50 -0
- data/lib/one_apm/logger/null_logger.rb +19 -0
- data/lib/one_apm/metrics/metric_data.rb +72 -0
- data/lib/one_apm/metrics/metric_spec.rb +82 -0
- data/lib/one_apm/metrics/stats.rb +173 -0
- data/lib/one_apm/probe.rb +16 -0
- data/lib/one_apm/probe/framework_loader.rb +53 -0
- data/lib/one_apm/probe/instance_methods.rb +105 -0
- data/lib/one_apm/probe/instrumentation.rb +60 -0
- data/lib/one_apm/rack/browser_monitoring.rb +144 -0
- data/lib/one_apm/rack/middleware_base.rb +27 -0
- data/lib/one_apm/rack/middleware_hooks.rb +17 -0
- data/lib/one_apm/rack/middleware_tracing.rb +81 -0
- data/lib/one_apm/rack/middleware_wrapper.rb +86 -0
- data/lib/one_apm/support/chained_call.rb +15 -0
- data/lib/one_apm/support/coerce.rb +81 -0
- data/lib/one_apm/support/collection_helper.rb +79 -0
- data/lib/one_apm/support/dotted_hash.rb +45 -0
- data/lib/one_apm/support/encoders.rb +34 -0
- data/lib/one_apm/support/environment_report.rb +127 -0
- data/lib/one_apm/support/event_buffer.rb +82 -0
- data/lib/one_apm/support/event_buffer/sampled_buffer.rb +45 -0
- data/lib/one_apm/support/event_buffer/sized_buffer.rb +21 -0
- data/lib/one_apm/support/event_buffer/synthetics_event_buffer.rb +40 -0
- data/lib/one_apm/support/helper.rb +49 -0
- data/lib/one_apm/support/hostname.rb +13 -0
- data/lib/one_apm/support/http_clients/curb_wrappers.rb +65 -0
- data/lib/one_apm/support/http_clients/excon_wrappers.rb +63 -0
- data/lib/one_apm/support/http_clients/httpclient_wrappers.rb +61 -0
- data/lib/one_apm/support/http_clients/net_http_wrappers.rb +48 -0
- data/lib/one_apm/support/http_clients/typhoeus_wrappers.rb +73 -0
- data/lib/one_apm/support/http_clients/uri_util.rb +39 -0
- data/lib/one_apm/support/json_marshaller.rb +68 -0
- data/lib/one_apm/support/json_wrapper.rb +130 -0
- data/lib/one_apm/support/language_support.rb +142 -0
- data/lib/one_apm/support/library_detection.rb +119 -0
- data/lib/one_apm/support/local_environment.rb +196 -0
- data/lib/one_apm/support/marshaller.rb +62 -0
- data/lib/one_apm/support/method_tracer.rb +334 -0
- data/lib/one_apm/support/method_tracer/helpers.rb +92 -0
- data/lib/one_apm/support/method_tracer/traced_method_stack.rb +103 -0
- data/lib/one_apm/support/obfuscator.rb +47 -0
- data/lib/one_apm/support/okjson.rb +601 -0
- data/lib/one_apm/support/parameter_filtering.rb +35 -0
- data/lib/one_apm/support/rules_engine.rb +56 -0
- data/lib/one_apm/support/rules_engine/replacement_rule.rb +80 -0
- data/lib/one_apm/support/rules_engine/segment_terms_rule.rb +46 -0
- data/lib/one_apm/support/server.rb +11 -0
- data/lib/one_apm/support/supported_versions.rb +257 -0
- data/lib/one_apm/support/system_info.rb +211 -0
- data/lib/one_apm/support/timer_lib.rb +29 -0
- data/lib/one_apm/support/version_number.rb +51 -0
- data/lib/one_apm/support/vm.rb +30 -0
- data/lib/one_apm/support/vm/jruby_vm.rb +38 -0
- data/lib/one_apm/support/vm/monotonic_gc_profiler.rb +43 -0
- data/lib/one_apm/support/vm/mri_vm.rb +85 -0
- data/lib/one_apm/support/vm/rubinius_vm.rb +129 -0
- data/lib/one_apm/support/vm/snapshot.rb +18 -0
- data/lib/one_apm/transaction.rb +336 -0
- data/lib/one_apm/transaction/class_methods.rb +132 -0
- data/lib/one_apm/transaction/instance_helpers.rb +82 -0
- data/lib/one_apm/transaction/metric_constants.rb +42 -0
- data/lib/one_apm/transaction/sample_buffer/force_persist_sample_buffer.rb +21 -0
- data/lib/one_apm/transaction/sample_buffer/slowest_sample_buffer.rb +21 -0
- data/lib/one_apm/transaction/sample_buffer/synthetics_sample_buffer.rb +21 -0
- data/lib/one_apm/transaction/sample_buffer/transaction_sample_buffer.rb +101 -0
- data/lib/one_apm/transaction/sample_buffer/xray_sample_buffer.rb +60 -0
- data/lib/one_apm/transaction/segment.rb +193 -0
- data/lib/one_apm/transaction/segment_summary.rb +51 -0
- data/lib/one_apm/transaction/thread_local_access.rb +73 -0
- data/lib/one_apm/transaction/transaction_analysis.rb +78 -0
- data/lib/one_apm/transaction/transaction_apdex.rb +20 -0
- data/lib/one_apm/transaction/transaction_cpu.rb +22 -0
- data/lib/one_apm/transaction/transaction_finish_append.rb +67 -0
- data/lib/one_apm/transaction/transaction_ignore.rb +33 -0
- data/lib/one_apm/transaction/transaction_jruby_functions.rb +40 -0
- data/lib/one_apm/transaction/transaction_metrics.rb +53 -0
- data/lib/one_apm/transaction/transaction_name.rb +90 -0
- data/lib/one_apm/transaction/transaction_namer.rb +49 -0
- data/lib/one_apm/transaction/transaction_sample.rb +204 -0
- data/lib/one_apm/transaction/transaction_sample_builder.rb +168 -0
- data/lib/one_apm/transaction/transaction_state.rb +149 -0
- data/lib/one_apm/transaction/transaction_summary.rb +28 -0
- data/lib/one_apm/transaction/transaction_synthetics.rb +40 -0
- data/lib/one_apm/transaction/transaction_timings.rb +54 -0
- data/lib/one_apm/version.rb +13 -0
- data/lib/oneapm_rpm.rb +16 -0
- data/lib/sequel/extensions/oneapm_instrumentation.rb +84 -0
- data/lib/sequel/plugins/oneapm_instrumentation.rb +66 -0
- data/oneapm.yml +135 -0
- data/oneapm_rpm.gemspec +58 -0
- metadata +474 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/database/obfuscation_helpers'
|
4
|
+
|
5
|
+
module OneApm
|
6
|
+
module Agent
|
7
|
+
module Database
|
8
|
+
class Obfuscator
|
9
|
+
include Singleton
|
10
|
+
include ObfuscationHelpers
|
11
|
+
|
12
|
+
attr_reader :obfuscator
|
13
|
+
|
14
|
+
QUERY_TOO_LARGE_MESSAGE = "Query too large (over 16k characters) to safely obfuscate"
|
15
|
+
FAILED_TO_OBFUSCATE_MESSAGE = "Failed to obfuscate SQL query - quote characters remained after obfuscation"
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
reset
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
@obfuscator = method(:default_sql_obfuscator)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Sets the sql obfuscator used to clean up sql when sending it
|
26
|
+
# to the server. Possible types are:
|
27
|
+
#
|
28
|
+
# :before => sets the block to run before the existing
|
29
|
+
# obfuscators
|
30
|
+
#
|
31
|
+
# :after => sets the block to run after the existing
|
32
|
+
# obfuscator(s)
|
33
|
+
#
|
34
|
+
# :replace => removes the current obfuscator and replaces it
|
35
|
+
# with the provided block
|
36
|
+
def set_sql_obfuscator(type, &block)
|
37
|
+
if type == :before
|
38
|
+
@obfuscator = OneApm::ChainedCall.new(block, @obfuscator)
|
39
|
+
elsif type == :after
|
40
|
+
@obfuscator = OneApm::ChainedCall.new(@obfuscator, block)
|
41
|
+
elsif type == :replace
|
42
|
+
@obfuscator = block
|
43
|
+
else
|
44
|
+
fail "unknown sql_obfuscator type #{type}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_sql_obfuscator(sql)
|
49
|
+
if sql[-3,3] == '...'
|
50
|
+
return QUERY_TOO_LARGE_MESSAGE
|
51
|
+
end
|
52
|
+
|
53
|
+
stmt = sql.kind_of?(Statement) ? sql : Statement.new(sql)
|
54
|
+
obfuscate_double_quotes = stmt.adapter.to_s !~ /postgres|sqlite/
|
55
|
+
|
56
|
+
obfuscated = obfuscate_numeric_literals(stmt)
|
57
|
+
|
58
|
+
if obfuscate_double_quotes
|
59
|
+
obfuscated = obfuscate_quoted_literals(obfuscated)
|
60
|
+
obfuscated = remove_comments(obfuscated)
|
61
|
+
if contains_quotes?(obfuscated)
|
62
|
+
obfuscated = FAILED_TO_OBFUSCATE_MESSAGE
|
63
|
+
end
|
64
|
+
else
|
65
|
+
obfuscated = obfuscate_single_quote_literals(obfuscated)
|
66
|
+
obfuscated = remove_comments(obfuscated)
|
67
|
+
if contains_single_quotes?(obfuscated)
|
68
|
+
obfuscated = FAILED_TO_OBFUSCATE_MESSAGE
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
obfuscated.to_s # return back to a regular String
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/database'
|
4
|
+
require 'one_apm/agent/database/obfuscation_helpers'
|
5
|
+
|
6
|
+
module OneApm
|
7
|
+
module Agent
|
8
|
+
module Database
|
9
|
+
module PostgresExplainObfuscator
|
10
|
+
extend self
|
11
|
+
|
12
|
+
# Note that this regex can't be shared with the ones in the
|
13
|
+
# Database::Obfuscator class because here we don't look for
|
14
|
+
# backslash-escaped strings (and those regexes are backwards).
|
15
|
+
QUOTED_STRINGS_REGEX = /'(?:[^']|'')*'|"(?:[^"]|"")*"/
|
16
|
+
LABEL_LINE_REGEX = /^([^:\n]*:\s+).*$/.freeze
|
17
|
+
|
18
|
+
def obfuscate(explain)
|
19
|
+
# First, we replace all single-quoted strings.
|
20
|
+
# This is necessary in order to deal with multi-line string constants
|
21
|
+
# embedded in the explain output.
|
22
|
+
#
|
23
|
+
# Note that we look for both single or double quotes but do not
|
24
|
+
# replace double quotes in order to avoid accidentally latching onto a
|
25
|
+
# single quote character embedded within a quoted identifier (such as
|
26
|
+
# a table name).
|
27
|
+
#
|
28
|
+
# Note also that we make no special provisions for backslash-escaped
|
29
|
+
# single quotes (\') because these are canonicalized to two single
|
30
|
+
# quotes ('') in the explain output.
|
31
|
+
explain.gsub!(QUOTED_STRINGS_REGEX) do |match|
|
32
|
+
match.start_with?('"') ? match : '?'
|
33
|
+
end
|
34
|
+
|
35
|
+
# Now, mask anything after the first colon (:).
|
36
|
+
# All parts of the query that can appear in the explain output are
|
37
|
+
# prefixed with "<label>: ", so we want to preserve the label, but
|
38
|
+
# remove the rest of the line.
|
39
|
+
explain.gsub!(LABEL_LINE_REGEX, '\1?')
|
40
|
+
explain
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/datastores/metric_helper'
|
4
|
+
|
5
|
+
module OneApm
|
6
|
+
module Agent
|
7
|
+
module Datastores
|
8
|
+
|
9
|
+
# Add Datastore tracing to a method. This properly generates the metrics
|
10
|
+
# for OneApm's Datastore features. It does not capture the actual
|
11
|
+
# query content into Transaction Traces. Use wrap if you want to provide
|
12
|
+
# that functionality.
|
13
|
+
#
|
14
|
+
# @param [Class] clazz the class to instrument
|
15
|
+
#
|
16
|
+
# @param [String, Symbol] method_name the name of instance method to
|
17
|
+
# instrument
|
18
|
+
#
|
19
|
+
# @param [String] product name of your datastore for use in metric naming, e.g. "Redis"
|
20
|
+
#
|
21
|
+
# @param [optional,String] operation the name of operation if different
|
22
|
+
# than the instrumented method name
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
#
|
26
|
+
def self.trace(clazz, method_name, product, operation = method_name)
|
27
|
+
clazz.class_eval do
|
28
|
+
method_name_without_oneapm = "#{method_name}_without_oneapm"
|
29
|
+
|
30
|
+
if OneApm::Helper.instance_methods_include?(clazz, method_name) &&
|
31
|
+
!OneApm::Helper.instance_methods_include?(clazz, method_name_without_oneapm)
|
32
|
+
|
33
|
+
visibility = OneApm::Helper.instance_method_visibility(clazz, method_name)
|
34
|
+
|
35
|
+
alias_method method_name_without_oneapm, method_name
|
36
|
+
|
37
|
+
define_method(method_name) do |*args, &blk|
|
38
|
+
metrics = MetricHelper.metrics_for(product, operation)
|
39
|
+
OneApm::Support::MethodTracer.trace_execution_scoped(metrics) do
|
40
|
+
send(method_name_without_oneapm, *args, &blk)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
send visibility, method_name
|
45
|
+
send visibility, method_name_without_oneapm
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Wrap a call to a datastore and record OneApm Datastore metrics. This
|
51
|
+
# method can be used when a collection (i.e. table or model name) is
|
52
|
+
# known at runtime to be included in the metric naming. It is intended
|
53
|
+
# for situations that the simpler OneApm::Agent::Datastores.trace can't
|
54
|
+
# properly handle.
|
55
|
+
#
|
56
|
+
# To use this, wrap the datastore operation in the block passed to wrap.
|
57
|
+
#
|
58
|
+
# OneApm::Agent::Datastores.wrap("FauxDB", "find", "items") do
|
59
|
+
# FauxDB.find(query)
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# @param [String] product the datastore name for use in metric naming,
|
63
|
+
# e.g. "FauxDB"
|
64
|
+
#
|
65
|
+
# @param [String,Symbol] operation the name of operation (e.g. "select"),
|
66
|
+
# often named after the method that's being instrumented.
|
67
|
+
#
|
68
|
+
# @param [optional, String] collection the collection name for use in
|
69
|
+
# statement-level metrics (i.e. table or model name)
|
70
|
+
#
|
71
|
+
# @param [Proc,#call] callback proc or other callable to invoke after
|
72
|
+
# running the datastore block. Receives three arguments: result of the
|
73
|
+
# yield, the most specific (scoped) metric name, and elapsed time of the
|
74
|
+
# call. An example use is attaching SQL to Transaction Traces at the end
|
75
|
+
# of a wrapped datastore call.
|
76
|
+
#
|
77
|
+
# callback = Proc.new do |result, metrics, elapsed|
|
78
|
+
# OneApm::Agent::Datastores.notice_sql(query, metrics, elapsed)
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# OneApm::Agent::Datastores.wrap("FauxDB", "find", "items", callback) do
|
82
|
+
# FauxDB.find(query)
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING SQL!**
|
86
|
+
# OneApm's Transaction Tracing and Slow SQL features will
|
87
|
+
# attempt to apply obfuscation to the passed queries, but it is possible
|
88
|
+
# for a query format to be unsupported and result in exposing user
|
89
|
+
# information embedded within captured queries.
|
90
|
+
#
|
91
|
+
# @api public
|
92
|
+
#
|
93
|
+
def self.wrap(product, operation, collection = nil, callback = nil)
|
94
|
+
return yield unless operation
|
95
|
+
|
96
|
+
metrics = MetricHelper.metrics_for(product, operation, collection)
|
97
|
+
scoped_metric = metrics.first
|
98
|
+
OneApm::Support::MethodTracer.trace_execution_scoped(metrics) do
|
99
|
+
t0 = Time.now
|
100
|
+
begin
|
101
|
+
result = yield
|
102
|
+
ensure
|
103
|
+
if callback
|
104
|
+
elapsed_time = (Time.now - t0).to_f
|
105
|
+
callback.call(result, scoped_metric, elapsed_time)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Wrapper for simplifying attaching SQL queries during a transaction.
|
112
|
+
#
|
113
|
+
# If you are recording non-SQL data, please use the notice_statement
|
114
|
+
# method instead.
|
115
|
+
#
|
116
|
+
# OneApm::Agent::Datastores.notice_sql(query, metrics, elapsed)
|
117
|
+
#
|
118
|
+
# @param [String] query the SQL text to be captured. Note that depending
|
119
|
+
# on user settings, this string will be run through obfuscation, but
|
120
|
+
# some dialects of SQL (or non-SQL queries) are not guaranteed to be
|
121
|
+
# properly obfuscated by these routines!
|
122
|
+
#
|
123
|
+
# @param [String] scoped_metric The most specific metric relating to this
|
124
|
+
# query. Typically the result of
|
125
|
+
# OneApm::Agent::Datastores::MetricHelper#metrics_for
|
126
|
+
#
|
127
|
+
# @param [Float] elapsed the elapsed time during query execution
|
128
|
+
#
|
129
|
+
# **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING SQL!**
|
130
|
+
# OneApm's Transaction Tracing and Slow SQL features will
|
131
|
+
# attempt to apply obfuscation to the passed queries, but it is possible
|
132
|
+
# for a query format to be unsupported and result in exposing user
|
133
|
+
# information embedded within captured queries.
|
134
|
+
#
|
135
|
+
def self.notice_sql(query, scoped_metric, elapsed)
|
136
|
+
agent = OneApm::Agent.instance
|
137
|
+
agent.transaction_sampler.notice_sql(query, nil, elapsed)
|
138
|
+
agent.sql_sampler.notice_sql(query, scoped_metric, nil, elapsed)
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
|
142
|
+
# Wrapper for simplifying attaching non-SQL data statements to a
|
143
|
+
# transaction. For instance, Mongo or CQL queries, Memcached or Redis
|
144
|
+
# keys would all be appropriate data to attach as statements.
|
145
|
+
#
|
146
|
+
# Data passed to this method is NOT obfuscated by OneApm, so please
|
147
|
+
# ensure that user information is obfuscated if the agent setting
|
148
|
+
# `transaction_tracer.record_sql` is set to `obfuscated`
|
149
|
+
#
|
150
|
+
# OneApm::Agent::Datastores.notice_statement("key", elapsed)
|
151
|
+
#
|
152
|
+
# @param [String] statement text of the statement to capture.
|
153
|
+
#
|
154
|
+
# @param [Float] elapsed the elapsed time during query execution
|
155
|
+
#
|
156
|
+
# **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING STATEMENTS!**
|
157
|
+
# This method will properly ignore statements when the user has turned
|
158
|
+
# off capturing queries, but it is not able to obfuscate arbitrary data!
|
159
|
+
# To prevent exposing user information embedded in captured queries,
|
160
|
+
# please ensure all data passed to this method is safe to transmit to
|
161
|
+
# OneApm.
|
162
|
+
#
|
163
|
+
def self.notice_statement(statement, elapsed)
|
164
|
+
# Settings may change eventually, but for now we follow the same
|
165
|
+
# capture rules as SQL for non-SQL statements.
|
166
|
+
return unless OneApm::Agent::Database.should_record_sql?
|
167
|
+
|
168
|
+
agent = OneApm::Agent.instance
|
169
|
+
agent.transaction_sampler.notice_nosql_statement(statement, elapsed)
|
170
|
+
nil
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Agent
|
5
|
+
module Datastores
|
6
|
+
module MetricHelper
|
7
|
+
ROLLUP_METRIC = "Datastore/all".freeze
|
8
|
+
WEB_ROLLUP_METRIC = "Datastore/allWeb".freeze
|
9
|
+
OTHER_ROLLUP_METRIC = "Datastore/allOther".freeze
|
10
|
+
DEFAULT_PRODUCT_NAME = "ActiveRecord".freeze
|
11
|
+
OTHER = "Other".freeze
|
12
|
+
|
13
|
+
ALL = "all".freeze
|
14
|
+
ALL_WEB = "allWeb".freeze
|
15
|
+
ALL_OTHER = "allOther".freeze
|
16
|
+
|
17
|
+
def self.statement_metric_for(product, collection, operation)
|
18
|
+
"Datastore/statement/#{product}/#{collection}/#{operation}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.operation_metric_for(product, operation)
|
22
|
+
"Datastore/operation/#{product}/#{operation}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.product_suffixed_rollup(product, suffix)
|
26
|
+
"Datastore/#{product}/#{suffix}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.product_rollup(product)
|
30
|
+
"Datastore/#{product}/all"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.suffixed_rollup(suffix)
|
34
|
+
"Datastore/#{suffix}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.all_suffix
|
38
|
+
if OneApm::Transaction.recording_web_transaction?
|
39
|
+
ALL_WEB
|
40
|
+
else
|
41
|
+
ALL_OTHER
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.metrics_for(product, operation, collection = nil)
|
46
|
+
if overrides = overridden_operation_and_collection
|
47
|
+
operation, collection = overrides
|
48
|
+
end
|
49
|
+
|
50
|
+
suffix = all_suffix
|
51
|
+
|
52
|
+
# Order of these metrics matters--the first metric in the list will
|
53
|
+
# be treated as the scoped metric in a bunch of different cases.
|
54
|
+
metrics = [
|
55
|
+
operation_metric_for(product, operation),
|
56
|
+
product_suffixed_rollup(product, suffix),
|
57
|
+
product_rollup(product),
|
58
|
+
suffixed_rollup(suffix),
|
59
|
+
ROLLUP_METRIC
|
60
|
+
]
|
61
|
+
|
62
|
+
metrics.unshift statement_metric_for(product, collection, operation) if collection
|
63
|
+
|
64
|
+
metrics
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.metrics_from_sql(product, sql)
|
68
|
+
operation = OneApm::Agent::Database.parse_operation_from_query(sql) || OTHER
|
69
|
+
metrics_for(product, operation)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Allow Transaction#with_database_metric_name to override our
|
73
|
+
# collection and operation
|
74
|
+
def self.overridden_operation_and_collection #THREAD_LOCAL_ACCESS
|
75
|
+
state = OneApm::TransactionState.tl_get
|
76
|
+
txn = state.current_transaction
|
77
|
+
txn ? txn.instrumentation_state[:datastore_override] : nil
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Agent
|
5
|
+
module Datastores
|
6
|
+
module Mongo
|
7
|
+
def self.is_supported_version?
|
8
|
+
# No version constant in < 2.0 versions of Mongo :(
|
9
|
+
defined?(::Mongo) &&
|
10
|
+
defined?(::Mongo::MongoClient) &&
|
11
|
+
!is_version2?
|
12
|
+
end
|
13
|
+
|
14
|
+
# At present we explicitly don't support version 2.x of the driver yet
|
15
|
+
def self.is_version2?
|
16
|
+
defined?(::Mongo::VERSION) &&
|
17
|
+
OneApm::VersionNumber.new(::Mongo::VERSION) > OneApm::VersionNumber.new("2.0.0")
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.is_version_1_10_or_later?
|
21
|
+
# Again, no VERSION constant in 1.x, so we have to rely on constant checks
|
22
|
+
defined?(::Mongo::CollectionOperationWriter)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/datastores/mongo/obfuscator'
|
4
|
+
require 'one_apm/agent/datastores/metric_helper'
|
5
|
+
|
6
|
+
module OneApm
|
7
|
+
module Agent
|
8
|
+
module Datastores
|
9
|
+
module Mongo
|
10
|
+
module MetricTranslator
|
11
|
+
def self.metrics_for(name, payload)
|
12
|
+
payload ||= {}
|
13
|
+
|
14
|
+
if collection_in_selector?(payload)
|
15
|
+
command_key = command_key_from_selector(payload)
|
16
|
+
name = get_name_from_selector(command_key, payload)
|
17
|
+
collection = get_collection_from_selector(command_key, payload)
|
18
|
+
else
|
19
|
+
collection = payload[:collection]
|
20
|
+
end
|
21
|
+
|
22
|
+
# The 1.10.0 version of the mongo driver renamed 'remove' to
|
23
|
+
# 'delete', but for metric consistency with previous versions we
|
24
|
+
# want to keep it as 'remove'.
|
25
|
+
name = 'remove' if name.to_s == 'delete'
|
26
|
+
|
27
|
+
if self.find_one?(name, payload)
|
28
|
+
name = 'findOne'
|
29
|
+
elsif self.find_and_remove?(name, payload)
|
30
|
+
name = 'findAndRemove'
|
31
|
+
elsif self.find_and_modify?(name, payload)
|
32
|
+
name = 'findAndModify'
|
33
|
+
elsif self.create_indexes?(name, payload)
|
34
|
+
name = 'createIndexes'
|
35
|
+
elsif self.create_index?(name, payload)
|
36
|
+
name = 'createIndex'
|
37
|
+
collection = self.collection_name_from_index(payload)
|
38
|
+
elsif self.drop_indexes?(name, payload)
|
39
|
+
name = 'dropIndexes'
|
40
|
+
elsif self.drop_index?(name, payload)
|
41
|
+
name = 'dropIndex'
|
42
|
+
elsif self.re_index?(name, payload)
|
43
|
+
name = 'reIndex'
|
44
|
+
elsif self.group?(name, payload)
|
45
|
+
name = 'group'
|
46
|
+
collection = collection_name_from_group_selector(payload)
|
47
|
+
elsif self.rename_collection?(name, payload)
|
48
|
+
name = 'renameCollection'
|
49
|
+
collection = collection_name_from_rename_selector(payload)
|
50
|
+
end
|
51
|
+
|
52
|
+
build_metrics(name, collection)
|
53
|
+
rescue => e
|
54
|
+
OneApm::Agent.logger.debug("Failure during Mongo metric generation", e)
|
55
|
+
[]
|
56
|
+
end
|
57
|
+
|
58
|
+
MONGO_PRODUCT_NAME = "MongoDB".freeze
|
59
|
+
|
60
|
+
def self.build_metrics(name, collection)
|
61
|
+
OneApm::Agent::Datastores::MetricHelper.metrics_for(MONGO_PRODUCT_NAME,
|
62
|
+
name,
|
63
|
+
collection)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.collection_in_selector?(payload)
|
67
|
+
payload[:collection] == '$cmd' && payload[:selector]
|
68
|
+
end
|
69
|
+
|
70
|
+
NAMES_IN_SELECTOR = [
|
71
|
+
:findandmodify,
|
72
|
+
|
73
|
+
"aggregate",
|
74
|
+
"count",
|
75
|
+
"group",
|
76
|
+
"mapreduce",
|
77
|
+
|
78
|
+
:distinct,
|
79
|
+
|
80
|
+
:createIndexes,
|
81
|
+
:deleteIndexes,
|
82
|
+
:reIndex,
|
83
|
+
|
84
|
+
:collstats,
|
85
|
+
:renameCollection,
|
86
|
+
:drop,
|
87
|
+
]
|
88
|
+
|
89
|
+
def self.command_key_from_selector(payload)
|
90
|
+
selector = payload[:selector]
|
91
|
+
NAMES_IN_SELECTOR.find do |check_name|
|
92
|
+
selector.key?(check_name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.get_name_from_selector(command_key, payload)
|
97
|
+
if command_key
|
98
|
+
command_key.to_sym
|
99
|
+
else
|
100
|
+
OneApm::Agent.increment_metric("Supportability/Mongo/UnknownCollection")
|
101
|
+
payload[:selector].first.first unless command_key
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
CMD_COLLECTION = "$cmd".freeze
|
106
|
+
|
107
|
+
def self.get_collection_from_selector(command_key, payload)
|
108
|
+
if command_key
|
109
|
+
payload[:selector][command_key]
|
110
|
+
else
|
111
|
+
OneApm::Agent.increment_metric("Supportability/Mongo/UnknownCollection")
|
112
|
+
CMD_COLLECTION
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.find_one?(name, payload)
|
117
|
+
name == :find && payload[:limit] == -1
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.find_and_modify?(name, payload)
|
121
|
+
name == :findandmodify
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.find_and_remove?(name, payload)
|
125
|
+
name == :findandmodify && payload[:selector] && payload[:selector][:remove]
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.create_indexes?(name, paylod)
|
129
|
+
name == :createIndexes
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.create_index?(name, payload)
|
133
|
+
name == :insert && payload[:collection] == "system.indexes"
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.drop_indexes?(name, payload)
|
137
|
+
name == :deleteIndexes && payload[:selector] && payload[:selector][:index] == "*"
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.drop_index?(name, payload)
|
141
|
+
name == :deleteIndexes
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.re_index?(name, payload)
|
145
|
+
name == :reIndex && payload[:selector] && payload[:selector][:reIndex]
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.group?(name, payload)
|
149
|
+
name == :group
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.rename_collection?(name, payload)
|
153
|
+
name == :renameCollection
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.collection_name_from_index(payload)
|
157
|
+
if payload[:documents]
|
158
|
+
if payload[:documents].is_a?(Array)
|
159
|
+
# mongo gem versions pre 1.10.0
|
160
|
+
document = payload[:documents].first
|
161
|
+
else
|
162
|
+
# mongo gem versions 1.10.0 and later
|
163
|
+
document = payload[:documents]
|
164
|
+
end
|
165
|
+
|
166
|
+
if document && document[:ns]
|
167
|
+
return document[:ns].split('.').last
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
'system.indexes'
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.collection_name_from_group_selector(payload)
|
175
|
+
payload[:selector]["group"]["ns"]
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.collection_name_from_rename_selector(payload)
|
179
|
+
parts = payload[:selector][:renameCollection].split('.')
|
180
|
+
parts.shift
|
181
|
+
parts.join('.')
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|