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,153 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/collector/commands/agent_command'
|
4
|
+
require 'one_apm/collector/commands/xray_session_collection'
|
5
|
+
require 'one_apm/collector/commands/thread_profiler_session'
|
6
|
+
require 'one_apm/agent/threading/backtrace_service'
|
7
|
+
|
8
|
+
module OneApm
|
9
|
+
module Collector
|
10
|
+
class AgentCommandRouter
|
11
|
+
attr_reader :handlers
|
12
|
+
|
13
|
+
attr_accessor :thread_profiler_session,
|
14
|
+
:backtrace_service,
|
15
|
+
:xray_session_collection
|
16
|
+
|
17
|
+
def initialize(event_listener=nil)
|
18
|
+
@handlers = Hash.new { |*| Proc.new { |cmd| self.unrecognized_agent_command(cmd) } }
|
19
|
+
|
20
|
+
@backtrace_service = OneApm::Agent::Threading::BacktraceService.new(event_listener)
|
21
|
+
|
22
|
+
@thread_profiler_session = OneApm::Collector::Commands::ThreadProfilerSession.new(@backtrace_service)
|
23
|
+
@xray_session_collection = OneApm::Collector::Commands::XraySessionCollection.new(@backtrace_service, event_listener)
|
24
|
+
|
25
|
+
@handlers['restart'] = Proc.new { OneApm::Agent.restart }
|
26
|
+
@handlers['start_profiler'] = Proc.new { |cmd| thread_profiler_session.handle_start_command(cmd) }
|
27
|
+
@handlers['stop_profiler'] = Proc.new { |cmd| thread_profiler_session.handle_stop_command(cmd) }
|
28
|
+
@handlers['active_xray_sessions'] = Proc.new { |cmd| xray_session_collection.handle_active_xray_sessions(cmd) }
|
29
|
+
|
30
|
+
if event_listener
|
31
|
+
event_listener.subscribe(:before_shutdown, &method(:on_before_shutdown))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def one_apm_service
|
36
|
+
OneApm::Agent.instance.service
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_for_and_handle_agent_commands
|
40
|
+
commands = get_agent_commands
|
41
|
+
|
42
|
+
stop_xray_sessions unless active_xray_command?(commands)
|
43
|
+
|
44
|
+
results = invoke_commands(commands)
|
45
|
+
one_apm_service.agent_command_results(results) unless results.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop_xray_sessions
|
49
|
+
self.xray_session_collection.stop_all_sessions
|
50
|
+
end
|
51
|
+
|
52
|
+
def active_xray_command?(commands)
|
53
|
+
commands.any? {|command| command.name == 'active_xray_sessions'}
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_before_shutdown(*args)
|
57
|
+
if self.thread_profiler_session.running?
|
58
|
+
self.thread_profiler_session.stop(true)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def harvest!
|
63
|
+
profiles = []
|
64
|
+
profiles += harvest_from_xray_session_collection
|
65
|
+
profiles += harvest_from_thread_profiler_session
|
66
|
+
log_profiles(profiles)
|
67
|
+
profiles
|
68
|
+
end
|
69
|
+
|
70
|
+
# We don't currently support merging thread profiles that failed to send
|
71
|
+
# back into the AgentCommandRouter, so we just no-op this method.
|
72
|
+
# Same with reset! - we don't support asynchronous cancellation of a
|
73
|
+
# running thread profile or X-Ray session currently.
|
74
|
+
def merge!(*args); end
|
75
|
+
def reset!; end
|
76
|
+
|
77
|
+
def harvest_from_xray_session_collection
|
78
|
+
self.xray_session_collection.harvest_thread_profiles
|
79
|
+
end
|
80
|
+
|
81
|
+
def harvest_from_thread_profiler_session
|
82
|
+
if self.thread_profiler_session.ready_to_harvest?
|
83
|
+
self.thread_profiler_session.stop(true)
|
84
|
+
[self.thread_profiler_session.harvest]
|
85
|
+
else
|
86
|
+
[]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def log_profiles(profiles)
|
91
|
+
if profiles.empty?
|
92
|
+
::OneApm::Agent.logger.debug "No thread profiles with data found to send."
|
93
|
+
else
|
94
|
+
profile_descriptions = profiles.map { |p| p.to_log_description }
|
95
|
+
::OneApm::Agent.logger.debug "Sending thread profiles [#{profile_descriptions.join(", ")}]"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_agent_commands
|
100
|
+
commands = one_apm_service.get_agent_commands
|
101
|
+
OneApm::Agent.logger.info "Received get_agent_commands = #{commands.inspect}" if commands.any?
|
102
|
+
commands.map {|collector_command| OneApm::Collector::Commands::AgentCommand.new(collector_command)}
|
103
|
+
end
|
104
|
+
|
105
|
+
def invoke_commands(agent_commands)
|
106
|
+
results = {}
|
107
|
+
|
108
|
+
agent_commands.each do |agent_command|
|
109
|
+
results[agent_command.id.to_s] = invoke_command(agent_command)
|
110
|
+
end
|
111
|
+
|
112
|
+
results
|
113
|
+
end
|
114
|
+
|
115
|
+
class AgentCommandError < StandardError
|
116
|
+
end
|
117
|
+
|
118
|
+
def invoke_command(agent_command)
|
119
|
+
begin
|
120
|
+
call_handler_for(agent_command)
|
121
|
+
return success
|
122
|
+
rescue AgentCommandError => e
|
123
|
+
OneApm::Agent.logger.debug(e)
|
124
|
+
error(e)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
SUCCESS_RESULT = {}.freeze
|
129
|
+
ERROR_KEY = "error"
|
130
|
+
|
131
|
+
def success
|
132
|
+
SUCCESS_RESULT
|
133
|
+
end
|
134
|
+
|
135
|
+
def error(err)
|
136
|
+
{ ERROR_KEY => err.message }
|
137
|
+
end
|
138
|
+
|
139
|
+
def call_handler_for(agent_command)
|
140
|
+
handler = select_handler(agent_command)
|
141
|
+
handler.call(agent_command)
|
142
|
+
end
|
143
|
+
|
144
|
+
def select_handler(agent_command)
|
145
|
+
@handlers[agent_command.name]
|
146
|
+
end
|
147
|
+
|
148
|
+
def unrecognized_agent_command(agent_command)
|
149
|
+
OneApm::Agent.logger.debug("Unrecognized agent command #{agent_command.inspect}")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/support/event_buffer/sized_buffer'
|
4
|
+
|
5
|
+
module OneApm
|
6
|
+
module Collector
|
7
|
+
class CustomEventAggregator
|
8
|
+
include OneApm::Coerce
|
9
|
+
|
10
|
+
TYPE = 'type'.freeze
|
11
|
+
TIMESTAMP = 'timestamp'.freeze
|
12
|
+
EVENT_PARAMS_CTX = 'recording custom event'.freeze
|
13
|
+
EVENT_TYPE_REGEX = /^[a-zA-Z0-9:_ ]+$/.freeze
|
14
|
+
|
15
|
+
DEFAULT_CAPACITY_KEY = :'custom_insights_events.max_samples_stored'
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@lock = Mutex.new
|
19
|
+
@buffer = OneApm::Agent::SampledBuffer.new(OneApm::Agent.config[DEFAULT_CAPACITY_KEY])
|
20
|
+
@type_strings = Hash.new { |hash, key| hash[key] = key.to_s.freeze }
|
21
|
+
register_config_callbacks
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_config_callbacks
|
25
|
+
OneApm::Agent.config.register_callback(DEFAULT_CAPACITY_KEY) do |max_samples|
|
26
|
+
OneApm::Agent.logger.debug "CustomEventAggregator max_samples set to #{max_samples}"
|
27
|
+
@lock.synchronize do
|
28
|
+
@buffer.capacity = max_samples
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def record(type, attributes)
|
34
|
+
type = @type_strings[type]
|
35
|
+
unless type =~ EVENT_TYPE_REGEX
|
36
|
+
note_dropped_event(type)
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
40
|
+
event = [
|
41
|
+
{ TYPE => type, TIMESTAMP => Time.now.to_i },
|
42
|
+
event_params(attributes, EVENT_PARAMS_CTX)
|
43
|
+
]
|
44
|
+
|
45
|
+
stored = @lock.synchronize do
|
46
|
+
@buffer.append(event)
|
47
|
+
end
|
48
|
+
stored
|
49
|
+
end
|
50
|
+
|
51
|
+
def harvest!
|
52
|
+
results = []
|
53
|
+
drop_count = 0
|
54
|
+
@lock.synchronize do
|
55
|
+
results.concat(@buffer.to_a)
|
56
|
+
drop_count += @buffer.num_dropped
|
57
|
+
@buffer.reset!
|
58
|
+
end
|
59
|
+
note_dropped_events(results.size, drop_count)
|
60
|
+
results
|
61
|
+
end
|
62
|
+
|
63
|
+
def note_dropped_events(captured_count, dropped_count)
|
64
|
+
total_count = captured_count + dropped_count
|
65
|
+
if dropped_count > 0
|
66
|
+
OneApm::Agent.logger.warn("Dropped #{dropped_count} custom events out of #{total_count}.")
|
67
|
+
end
|
68
|
+
engine = OneApm::Agent.instance.stats_engine
|
69
|
+
engine.tl_record_supportability_metric_count("Events/Customer/Seen" , total_count)
|
70
|
+
engine.tl_record_supportability_metric_count("Events/Customer/Sent" , captured_count)
|
71
|
+
engine.tl_record_supportability_metric_count("Events/Customer/Dropped", dropped_count)
|
72
|
+
end
|
73
|
+
|
74
|
+
def merge!(events)
|
75
|
+
@lock.synchronize do
|
76
|
+
events.each do |event|
|
77
|
+
@buffer.append(event)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def reset!
|
83
|
+
@lock.synchronize { @buffer.reset! }
|
84
|
+
end
|
85
|
+
|
86
|
+
def note_dropped_event(type)
|
87
|
+
::OneApm::Agent.logger.log_once(:warn, "dropping_event_of_type:#{type}",
|
88
|
+
"Invalid event type name '#{type}', not recording.")
|
89
|
+
@buffer.note_dropped
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,349 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Collector
|
5
|
+
class ErrorCollector
|
6
|
+
include OneApm::CollectionHelper
|
7
|
+
|
8
|
+
# Defined the methods that need to be stubbed out when the agent is disabled
|
9
|
+
module Shim
|
10
|
+
def notice_error(*args); end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Maximum possible length of the queue - defaults to 20, may be
|
14
|
+
# made configurable in the future. This is a tradeoff between
|
15
|
+
# memory and data retention
|
16
|
+
MAX_ERROR_QUEUE_LENGTH = 20 unless defined? MAX_ERROR_QUEUE_LENGTH
|
17
|
+
|
18
|
+
attr_accessor :errors
|
19
|
+
|
20
|
+
# Returns a new error collector
|
21
|
+
def initialize
|
22
|
+
@errors = []
|
23
|
+
|
24
|
+
# lookup of exception class names to ignore. Hash for fast access
|
25
|
+
@ignore = {}
|
26
|
+
|
27
|
+
initialize_ignored_errors(Agent.config[:'error_collector.ignore_errors'])
|
28
|
+
@lock = Mutex.new
|
29
|
+
|
30
|
+
Agent.config.register_callback(:'error_collector.enabled') do |config_enabled|
|
31
|
+
::OneApm::Agent.logger.debug "Errors will #{config_enabled ? '' : 'not '}be sent to the OneApm service."
|
32
|
+
end
|
33
|
+
Agent.config.register_callback(:'error_collector.ignore_errors') do |ignore_errors|
|
34
|
+
initialize_ignored_errors(ignore_errors)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize_ignored_errors(ignore_errors)
|
39
|
+
@ignore.clear
|
40
|
+
ignore_errors = ignore_errors.split(",") if ignore_errors.is_a? String
|
41
|
+
ignore_errors.each { |error| error.strip! }
|
42
|
+
ignore(ignore_errors)
|
43
|
+
end
|
44
|
+
|
45
|
+
def enabled?
|
46
|
+
Agent.config[:'error_collector.enabled']
|
47
|
+
end
|
48
|
+
|
49
|
+
def disabled?
|
50
|
+
!enabled?
|
51
|
+
end
|
52
|
+
|
53
|
+
# We store the passed block in both an ivar on the class, and implicitly
|
54
|
+
# within the body of the ignore_filter_proc method intentionally here.
|
55
|
+
# The define_method trick is needed to get around the fact that users may
|
56
|
+
# call 'return' from within their filter blocks, which would otherwise
|
57
|
+
# result in a LocalJumpError.
|
58
|
+
#
|
59
|
+
# The raw block is also stored in an instance variable so that we can
|
60
|
+
# return it later in its original form.
|
61
|
+
#
|
62
|
+
# This is all done at the class level in order to avoid the case where
|
63
|
+
# the user sets up an ignore filter on one instance of the ErrorCollector,
|
64
|
+
# and then that instance subsequently gets discarded during agent startup.
|
65
|
+
# (For example, if the agent is initially disabled, and then gets enabled
|
66
|
+
# via a call to start later on.)
|
67
|
+
#
|
68
|
+
def self.ignore_error_filter=(block)
|
69
|
+
@ignore_filter = block
|
70
|
+
if block
|
71
|
+
define_method(:ignore_filter_proc, &block)
|
72
|
+
elsif method_defined?(:ignore_filter_proc)
|
73
|
+
undef :ignore_filter_proc
|
74
|
+
end
|
75
|
+
@ignore_filter
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.ignore_error_filter
|
79
|
+
@ignore_filter
|
80
|
+
end
|
81
|
+
|
82
|
+
# errors is an array of Exception Class Names
|
83
|
+
def ignore(errors)
|
84
|
+
errors.each do |error|
|
85
|
+
@ignore[error] = true
|
86
|
+
::OneApm::Agent.logger.debug("Ignoring errors of type '#{error}'")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# This module was extracted from the notice_error method - it is
|
91
|
+
# internally tested and can be refactored without major issues.
|
92
|
+
module NoticeError
|
93
|
+
# Checks the provided error against the error filter, if there
|
94
|
+
# is an error filter
|
95
|
+
def filtered_by_error_filter?(error)
|
96
|
+
respond_to?(:ignore_filter_proc) && !ignore_filter_proc(error)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Checks the array of error names and the error filter against
|
100
|
+
# the provided error
|
101
|
+
def filtered_error?(error)
|
102
|
+
@ignore[error.class.name] || filtered_by_error_filter?(error)
|
103
|
+
end
|
104
|
+
|
105
|
+
# an error is ignored if it is nil or if it is filtered
|
106
|
+
def error_is_ignored?(error)
|
107
|
+
error && filtered_error?(error)
|
108
|
+
rescue => e
|
109
|
+
OneApm::Agent.logger.error("Error '#{error}' will NOT be ignored. Exception '#{e}' while determining whether to ignore or not.", e)
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
def seen?(txn, exception)
|
114
|
+
error_ids = txn.nil? ? [] : txn.noticed_error_ids
|
115
|
+
error_ids.include?(exception.object_id)
|
116
|
+
end
|
117
|
+
|
118
|
+
def tag_as_seen(state, exception)
|
119
|
+
txn = state.current_transaction
|
120
|
+
txn.noticed_error_ids << exception.object_id if txn
|
121
|
+
end
|
122
|
+
|
123
|
+
def blamed_metric_name(txn, options)
|
124
|
+
if options[:metric] && options[:metric] != OneApm::Transaction::UNKNOWN_METRIC
|
125
|
+
"Errors/#{options[:metric]}"
|
126
|
+
else
|
127
|
+
"Errors/#{txn.best_name}" if txn
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def aggregated_metric_names(txn)
|
132
|
+
metric_names = ["Errors/all"]
|
133
|
+
return metric_names unless txn
|
134
|
+
|
135
|
+
if txn.recording_web_transaction?
|
136
|
+
metric_names << "Errors/allWeb"
|
137
|
+
else
|
138
|
+
metric_names << "Errors/allOther"
|
139
|
+
end
|
140
|
+
|
141
|
+
metric_names
|
142
|
+
end
|
143
|
+
|
144
|
+
# Increments a statistic that tracks total error rate
|
145
|
+
def increment_error_count!(state, exception, options={})
|
146
|
+
txn = state.current_transaction
|
147
|
+
|
148
|
+
metric_names = aggregated_metric_names(txn)
|
149
|
+
blamed_metric = blamed_metric_name(txn, options)
|
150
|
+
metric_names << blamed_metric if blamed_metric
|
151
|
+
|
152
|
+
stats_engine = OneApm::Agent.instance.stats_engine
|
153
|
+
stats_engine.record_unscoped_metrics(state, metric_names) do |stats|
|
154
|
+
stats.increment_count
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def skip_notice_error?(state, exception)
|
159
|
+
disabled? ||
|
160
|
+
error_is_ignored?(exception) ||
|
161
|
+
exception.nil? ||
|
162
|
+
seen?(state.current_transaction, exception)
|
163
|
+
end
|
164
|
+
|
165
|
+
# acts just like Hash#fetch, but deletes the key from the hash
|
166
|
+
def fetch_from_options(options, key, default=nil)
|
167
|
+
options.delete(key) || default
|
168
|
+
end
|
169
|
+
|
170
|
+
# returns some basic option defaults pulled from the provided
|
171
|
+
# options hash
|
172
|
+
def uri_ref_and_root(options)
|
173
|
+
{
|
174
|
+
:request_uri => fetch_from_options(options, :uri, ''),
|
175
|
+
:request_referer => fetch_from_options(options, :referer, ''),
|
176
|
+
:rails_root => OneApm::Probe.instance.root
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
# If anything else is left over, we treat it like a custom param
|
181
|
+
def custom_params_from_opts(options)
|
182
|
+
# If anything else is left over, treat it like a custom param:
|
183
|
+
if Agent.config[:'error_collector.capture_attributes']
|
184
|
+
fetch_from_options(options, :custom_params, {}).merge(options)
|
185
|
+
else
|
186
|
+
{}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# takes the request parameters out of the options hash, and
|
191
|
+
# returns them if we are capturing parameters, otherwise
|
192
|
+
# returns nil
|
193
|
+
def request_params_from_opts(options)
|
194
|
+
value = options.delete(:request_params)
|
195
|
+
if Agent.config[:capture_params]
|
196
|
+
value
|
197
|
+
else
|
198
|
+
nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# normalizes the request and custom parameters before attaching
|
203
|
+
# them to the error. See OneApm::CollectionHelper#normalize_params
|
204
|
+
def normalized_request_and_custom_params(options)
|
205
|
+
{
|
206
|
+
:request_params => normalize_params(request_params_from_opts(options)),
|
207
|
+
:custom_params => normalize_params(custom_params_from_opts(options))
|
208
|
+
}
|
209
|
+
end
|
210
|
+
|
211
|
+
# Merges together many of the options into something that can
|
212
|
+
# actually be attached to the error
|
213
|
+
def error_params_from_options(options)
|
214
|
+
uri_ref_and_root(options).merge(normalized_request_and_custom_params(options))
|
215
|
+
end
|
216
|
+
|
217
|
+
# calls a method on an object, if it responds to it - used for
|
218
|
+
# detection and soft fail-safe. Returns nil if the method does
|
219
|
+
# not exist
|
220
|
+
def sense_method(object, method)
|
221
|
+
object.send(method) if object.respond_to?(method)
|
222
|
+
end
|
223
|
+
|
224
|
+
# extracts a stack trace from the exception for debugging purposes
|
225
|
+
def extract_stack_trace(exception)
|
226
|
+
actual_exception = sense_method(exception, 'original_exception') || exception
|
227
|
+
if bt = sense_method(actual_exception, 'backtrace')
|
228
|
+
bt.reject! { |t| t.include?('one_apm') }
|
229
|
+
bt
|
230
|
+
else
|
231
|
+
'<no stack trace>'
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# extracts a bunch of information from the exception to include
|
236
|
+
# in the noticed error - some may or may not be available, but
|
237
|
+
# we try to include all of it
|
238
|
+
def exception_info(exception)
|
239
|
+
{
|
240
|
+
:file_name => sense_method(exception, 'file_name'),
|
241
|
+
:line_number => sense_method(exception, 'line_number'),
|
242
|
+
:stack_trace => extract_stack_trace(exception)
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
# checks the size of the error queue to make sure we are under
|
247
|
+
# the maximum limit, and logs a warning if we are over the limit.
|
248
|
+
def over_queue_limit?(message)
|
249
|
+
over_limit = (@errors.reject{|err| err.is_internal}.length >= MAX_ERROR_QUEUE_LENGTH)
|
250
|
+
::OneApm::Agent.logger.warn("The error reporting queue has reached #{MAX_ERROR_QUEUE_LENGTH}. The error detail for this and subsequent errors will not be transmitted to OneApm until the queued errors have been sent: #{message}") if over_limit
|
251
|
+
over_limit
|
252
|
+
end
|
253
|
+
|
254
|
+
# Synchronizes adding an error to the error queue, and checks if
|
255
|
+
# the error queue is too long - if so, we drop the error on the
|
256
|
+
# floor after logging a warning.
|
257
|
+
def add_to_error_queue(noticed_error)
|
258
|
+
@lock.synchronize do
|
259
|
+
if !over_queue_limit?(noticed_error.message) && !@errors.include?(noticed_error)
|
260
|
+
@errors << noticed_error
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
include NoticeError
|
267
|
+
|
268
|
+
|
269
|
+
# Notice the error with the given available options:
|
270
|
+
#
|
271
|
+
# * <tt>:uri</tt> => The request path, minus any request params or query string.
|
272
|
+
# * <tt>:referer</tt> => The URI of the referer
|
273
|
+
# * <tt>:metric</tt> => The metric name associated with the transaction
|
274
|
+
# * <tt>:request_params</tt> => Request parameters, already filtered if necessary
|
275
|
+
# * <tt>:custom_params</tt> => Custom parameters
|
276
|
+
#
|
277
|
+
# If anything is left over, it's added to custom params
|
278
|
+
# If exception is nil, the error count is bumped and no traced error is recorded
|
279
|
+
def notice_error(exception, options={}) #THREAD_LOCAL_ACCESS
|
280
|
+
state = ::OneApm::TransactionState.tl_get
|
281
|
+
|
282
|
+
return if skip_notice_error?(state, exception)
|
283
|
+
tag_as_seen(state, exception)
|
284
|
+
|
285
|
+
increment_error_count!(state, exception, options)
|
286
|
+
OneApm::Agent.instance.events.notify(:notice_error, exception, options)
|
287
|
+
|
288
|
+
action_path = fetch_from_options(options, :metric, "")
|
289
|
+
exception_options = error_params_from_options(options).merge(exception_info(exception))
|
290
|
+
add_to_error_queue(OneApm::NoticedError.new(action_path, exception_options, exception))
|
291
|
+
|
292
|
+
exception
|
293
|
+
rescue => e
|
294
|
+
::OneApm::Agent.logger.warn("Failure when capturing error '#{exception}':", e)
|
295
|
+
end
|
296
|
+
|
297
|
+
# *Use sparingly for difficult to track bugs.*
|
298
|
+
#
|
299
|
+
# Track internal agent errors for communication back to OneApm.
|
300
|
+
# To use, make a specific subclass of OneApm::Agent::InternalAgentError,
|
301
|
+
# then pass an instance of it to this method when your problem occurs.
|
302
|
+
#
|
303
|
+
# Limits are treated differently for these errors. We only gather one per
|
304
|
+
# class per harvest, disregarding (and not impacting) the app error queue
|
305
|
+
# limit.
|
306
|
+
def notice_agent_error(exception)
|
307
|
+
return unless exception.class < OneApm::Agent::InternalAgentError
|
308
|
+
|
309
|
+
# Log 'em all!
|
310
|
+
OneApm::Agent.logger.info(exception)
|
311
|
+
|
312
|
+
@lock.synchronize do
|
313
|
+
# Already seen this class once? Bail!
|
314
|
+
return if @errors.any? { |err| err.exception_class_name == exception.class.name }
|
315
|
+
|
316
|
+
trace = exception.backtrace || caller.dup
|
317
|
+
noticed_error = OneApm::NoticedError.new("OneApm/AgentError",
|
318
|
+
{:stack_trace => trace},
|
319
|
+
exception)
|
320
|
+
@errors << noticed_error
|
321
|
+
end
|
322
|
+
rescue => e
|
323
|
+
OneApm::Agent.logger.info("Unable to capture internal agent error due to an exception:", e)
|
324
|
+
end
|
325
|
+
|
326
|
+
def merge!(errors)
|
327
|
+
errors.each do |error|
|
328
|
+
add_to_error_queue(error)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
# Get the errors currently queued up. Unsent errors are left
|
333
|
+
# over from a previous unsuccessful attempt to send them to the server.
|
334
|
+
def harvest!
|
335
|
+
@lock.synchronize do
|
336
|
+
errors = @errors
|
337
|
+
@errors = []
|
338
|
+
errors
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def reset!
|
343
|
+
@lock.synchronize do
|
344
|
+
@errors = []
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|