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,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/sampler'
|
4
|
+
|
5
|
+
module OneApm
|
6
|
+
module Agent
|
7
|
+
module Samplers
|
8
|
+
class ObjectSampler < OneApm::Agent::Sampler
|
9
|
+
named :object
|
10
|
+
|
11
|
+
def self.supported_on_this_platform?
|
12
|
+
OneApm::LanguageSupport.object_space_usable? && ObjectSpace.respond_to?(:live_objects)
|
13
|
+
end
|
14
|
+
|
15
|
+
def poll
|
16
|
+
live_objects = ObjectSpace.live_objects
|
17
|
+
OneApm::Agent.record_metric("GC/objects", live_objects)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/sampler'
|
4
|
+
require 'one_apm/support/vm'
|
5
|
+
|
6
|
+
module OneApm
|
7
|
+
module Agent
|
8
|
+
module Samplers
|
9
|
+
class VMSampler < Sampler
|
10
|
+
GC_RUNS_METRIC = 'RubyVM/GC/runs'.freeze
|
11
|
+
HEAP_LIVE_METRIC = 'RubyVM/GC/heap_live'.freeze
|
12
|
+
HEAP_FREE_METRIC = 'RubyVM/GC/heap_free'.freeze
|
13
|
+
THREAD_COUNT_METRIC = 'RubyVM/Threads/all'.freeze
|
14
|
+
OBJECT_ALLOCATIONS_METRIC = 'RubyVM/GC/total_allocated_object'.freeze
|
15
|
+
MAJOR_GC_METRIC = 'RubyVM/GC/major_gc_count'.freeze
|
16
|
+
MINOR_GC_METRIC = 'RubyVM/GC/minor_gc_count'.freeze
|
17
|
+
METHOD_INVALIDATIONS_METRIC = 'RubyVM/CacheInvalidations/method'.freeze
|
18
|
+
CONSTANT_INVALIDATIONS_METRIC = 'RubyVM/CacheInvalidations/constant'.freeze
|
19
|
+
|
20
|
+
attr_reader :transaction_count
|
21
|
+
|
22
|
+
named :vm
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@lock = Mutex.new
|
26
|
+
@transaction_count = 0
|
27
|
+
@last_snapshot = take_snapshot
|
28
|
+
end
|
29
|
+
|
30
|
+
def take_snapshot
|
31
|
+
OneApm::Support::VM.snapshot
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_events(event_listener)
|
35
|
+
event_listener.subscribe(:transaction_finished, &method(:on_transaction_finished))
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_transaction_finished(*_)
|
39
|
+
@lock.synchronize { @transaction_count += 1 }
|
40
|
+
end
|
41
|
+
|
42
|
+
def reset_transaction_count
|
43
|
+
@lock.synchronize do
|
44
|
+
old_count = @transaction_count
|
45
|
+
@transaction_count = 0
|
46
|
+
old_count
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def record_gc_runs_metric(snapshot, txn_count) #THREAD_LOCAL_ACCESS
|
51
|
+
if snapshot.gc_total_time || snapshot.gc_runs
|
52
|
+
if snapshot.gc_total_time
|
53
|
+
gc_time = snapshot.gc_total_time - @last_snapshot.gc_total_time.to_f
|
54
|
+
end
|
55
|
+
if snapshot.gc_runs
|
56
|
+
gc_runs = snapshot.gc_runs - @last_snapshot.gc_runs
|
57
|
+
end
|
58
|
+
wall_clock_time = snapshot.taken_at - @last_snapshot.taken_at
|
59
|
+
OneApm::Agent.instance.stats_engine.tl_record_unscoped_metrics(GC_RUNS_METRIC) do |stats|
|
60
|
+
stats.call_count += txn_count
|
61
|
+
stats.total_call_time += gc_runs if gc_runs
|
62
|
+
stats.total_exclusive_time += gc_time if gc_time
|
63
|
+
stats.max_call_time = (gc_time.nil? ? 0 : 1)
|
64
|
+
stats.sum_of_squares += wall_clock_time
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def record_delta(snapshot, key, metric, txn_count) #THREAD_LOCAL_ACCESS
|
70
|
+
value = snapshot.send(key)
|
71
|
+
if value
|
72
|
+
delta = value - @last_snapshot.send(key)
|
73
|
+
OneApm::Agent.instance.stats_engine.tl_record_unscoped_metrics(metric) do |stats|
|
74
|
+
stats.call_count += txn_count
|
75
|
+
stats.total_call_time += delta
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def record_gauge_metric(metric_name, value) #THREAD_LOCAL_ACCESS
|
81
|
+
OneApm::Agent.instance.stats_engine.tl_record_unscoped_metrics(metric_name) do |stats|
|
82
|
+
stats.call_count = value
|
83
|
+
stats.sum_of_squares = 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def record_heap_live_metric(snapshot)
|
88
|
+
if snapshot.heap_live
|
89
|
+
record_gauge_metric(HEAP_LIVE_METRIC, snapshot.heap_live)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def record_heap_free_metric(snapshot)
|
94
|
+
if snapshot.heap_free
|
95
|
+
record_gauge_metric(HEAP_FREE_METRIC, snapshot.heap_free)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def record_thread_count_metric(snapshot)
|
100
|
+
if snapshot.thread_count
|
101
|
+
record_gauge_metric(THREAD_COUNT_METRIC, snapshot.thread_count)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def poll
|
106
|
+
snap = take_snapshot
|
107
|
+
tcount = reset_transaction_count
|
108
|
+
|
109
|
+
record_gc_runs_metric(snap, tcount)
|
110
|
+
record_delta(snap, :total_allocated_object, OBJECT_ALLOCATIONS_METRIC, tcount)
|
111
|
+
record_delta(snap, :major_gc_count, MAJOR_GC_METRIC, tcount)
|
112
|
+
record_delta(snap, :minor_gc_count, MINOR_GC_METRIC, tcount)
|
113
|
+
record_delta(snap, :method_cache_invalidations, METHOD_INVALIDATIONS_METRIC, tcount)
|
114
|
+
record_delta(snap, :constant_cache_invalidations, CONSTANT_INVALIDATIONS_METRIC, tcount)
|
115
|
+
record_heap_live_metric(snap)
|
116
|
+
record_heap_free_metric(snap)
|
117
|
+
record_thread_count_metric(snap)
|
118
|
+
|
119
|
+
@last_snapshot = snap
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'one_apm/agent/inbound_request_monitor'
|
4
|
+
|
5
|
+
module OneApm
|
6
|
+
module Agent
|
7
|
+
class SyntheticsMonitor < InboundRequestMonitor
|
8
|
+
SYNTHETICS_HEADER_KEY = 'HTTP_X_ONEAPM_SYNTHETICS'.freeze
|
9
|
+
|
10
|
+
SUPPORTED_VERSION = 1
|
11
|
+
EXPECTED_PAYLOAD_LENGTH = 5
|
12
|
+
|
13
|
+
def on_finished_configuring(events)
|
14
|
+
events.subscribe(:before_call, &method(:on_before_call))
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_before_call(request) #THREAD_LOCAL_ACCESS
|
18
|
+
encoded_header = request[SYNTHETICS_HEADER_KEY]
|
19
|
+
return unless encoded_header
|
20
|
+
|
21
|
+
incoming_payload = deserialize_header(encoded_header, SYNTHETICS_HEADER_KEY)
|
22
|
+
|
23
|
+
return unless incoming_payload &&
|
24
|
+
is_valid_payload?(incoming_payload) &&
|
25
|
+
is_supported_version?(incoming_payload) &&
|
26
|
+
is_trusted?(incoming_payload)
|
27
|
+
|
28
|
+
state = OneApm::TransactionState.tl_get
|
29
|
+
txn = state.current_transaction
|
30
|
+
txn.raw_synthetics_header = encoded_header
|
31
|
+
txn.synthetics_payload = incoming_payload
|
32
|
+
end
|
33
|
+
|
34
|
+
def is_supported_version?(incoming_payload)
|
35
|
+
incoming_payload.first == SUPPORTED_VERSION
|
36
|
+
end
|
37
|
+
|
38
|
+
def is_trusted?(incoming_payload)
|
39
|
+
account_id = incoming_payload[1]
|
40
|
+
OneApm::Agent.config[:trusted_account_ids].include?(account_id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_valid_payload?(incoming_payload)
|
44
|
+
incoming_payload.length == EXPECTED_PAYLOAD_LENGTH
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Agent
|
5
|
+
module Threading
|
6
|
+
class AgentThread
|
7
|
+
|
8
|
+
def self.create(label, &blk)
|
9
|
+
::OneApm::Agent.logger.debug("Creating OneApm thread: #{label}")
|
10
|
+
wrapped_blk = Proc.new do
|
11
|
+
begin
|
12
|
+
blk.call
|
13
|
+
rescue => e
|
14
|
+
::OneApm::Agent.logger.error("Thread #{label} exited with error", e)
|
15
|
+
rescue Exception => e
|
16
|
+
::OneApm::Agent.logger.error("Thread #{label} exited with exception. Re-raising in case of interupt.", e)
|
17
|
+
raise
|
18
|
+
ensure
|
19
|
+
::OneApm::Agent.logger.debug("Exiting OneApm thread: #{label}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
thread = backing_thread_class.new(&wrapped_blk)
|
24
|
+
thread[:oneapm_label] = label
|
25
|
+
thread
|
26
|
+
end
|
27
|
+
|
28
|
+
# Simplifies testing if we don't directly use ::Thread.list, so keep
|
29
|
+
# the accessor for it here on AgentThread to use and stub.
|
30
|
+
def self.list
|
31
|
+
backing_thread_class.list
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.bucket_thread(thread, profile_agent_code) #THREAD_LOCAL_ACCESS
|
35
|
+
if thread.key?(:oneapm_label)
|
36
|
+
profile_agent_code ? :agent : :ignore
|
37
|
+
else
|
38
|
+
state = TransactionState.tl_state_for(thread)
|
39
|
+
if state.in_background_transaction?
|
40
|
+
:background
|
41
|
+
elsif state.in_web_transaction?
|
42
|
+
:request
|
43
|
+
else
|
44
|
+
:other
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.scrub_backtrace(thread, profile_agent_code)
|
50
|
+
begin
|
51
|
+
bt = thread.backtrace
|
52
|
+
rescue Exception => e
|
53
|
+
::OneApm::Agent.logger.debug("Failed to backtrace #{thread.inspect}: #{e.class.name}: #{e.to_s}")
|
54
|
+
end
|
55
|
+
return nil unless bt
|
56
|
+
bt.reject! { |t| t.include?('one_apm') } unless profile_agent_code
|
57
|
+
bt
|
58
|
+
end
|
59
|
+
|
60
|
+
# To allow tests to swap out Thread for a synchronous alternative,
|
61
|
+
# surface the backing class we'll use from the class level.
|
62
|
+
@backing_thread_class = ::Thread
|
63
|
+
|
64
|
+
def self.backing_thread_class
|
65
|
+
@backing_thread_class
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.backing_thread_class=(clazz)
|
69
|
+
@backing_thread_class = clazz
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Agent
|
5
|
+
module Threading
|
6
|
+
MAX_THREAD_PROFILE_DEPTH = 500
|
7
|
+
UNKNOWN_LINE_NUMBER = -1
|
8
|
+
|
9
|
+
class BacktraceBase
|
10
|
+
attr_reader :children
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@children = []
|
14
|
+
@depth = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_child_unless_present(child)
|
18
|
+
child.depth = @depth + 1
|
19
|
+
@children << child unless @children.include? child
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_child(child)
|
23
|
+
child.depth = @depth + 1
|
24
|
+
@children << child
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_child(raw_line)
|
28
|
+
@children.find { |child| child.raw_line == raw_line }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class BacktraceRoot < BacktraceBase
|
34
|
+
attr_reader :flattened
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
super
|
38
|
+
@flattened = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def ==(other)
|
42
|
+
true # all roots are at the same depth and have no raw_line
|
43
|
+
end
|
44
|
+
|
45
|
+
def as_array
|
46
|
+
@children.map { |c| c.as_array }.compact
|
47
|
+
end
|
48
|
+
|
49
|
+
def aggregate(backtrace)
|
50
|
+
current = self
|
51
|
+
|
52
|
+
depth = 0
|
53
|
+
backtrace.reverse_each do |frame|
|
54
|
+
break if depth >= MAX_THREAD_PROFILE_DEPTH
|
55
|
+
|
56
|
+
existing_node = current.find_child(frame)
|
57
|
+
if existing_node
|
58
|
+
node = existing_node
|
59
|
+
else
|
60
|
+
node = Threading::BacktraceNode.new(frame)
|
61
|
+
current.add_child(node)
|
62
|
+
@flattened << node
|
63
|
+
end
|
64
|
+
|
65
|
+
node.runnable_count += 1
|
66
|
+
current = node
|
67
|
+
depth += 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def dump_string
|
72
|
+
result = "#<BacktraceRoot:#{object_id}>"
|
73
|
+
child_results = @children.map { |c| c.dump_string(2) }.join("\n")
|
74
|
+
result << "\n" unless child_results.empty?
|
75
|
+
result << child_results
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
class BacktraceNode < BacktraceBase
|
81
|
+
attr_reader :file, :method, :line_no, :raw_line, :as_array
|
82
|
+
attr_accessor :runnable_count, :depth
|
83
|
+
|
84
|
+
def initialize(line)
|
85
|
+
super()
|
86
|
+
@raw_line = line
|
87
|
+
@children = []
|
88
|
+
@runnable_count = 0
|
89
|
+
end
|
90
|
+
|
91
|
+
def ==(other)
|
92
|
+
(
|
93
|
+
@raw_line == other.raw_line &&
|
94
|
+
@depth == other.depth &&
|
95
|
+
@runnable_count == other.runnable_count
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def mark_for_array_conversion
|
100
|
+
@as_array = []
|
101
|
+
end
|
102
|
+
|
103
|
+
include OneApm::Coerce
|
104
|
+
|
105
|
+
def complete_array_conversion
|
106
|
+
child_arrays = @children.map { |c| c.as_array }.compact
|
107
|
+
|
108
|
+
file, method, line = parse_backtrace_frame(@raw_line)
|
109
|
+
|
110
|
+
@as_array << [string(file), string(method), line ? int(line) : UNKNOWN_LINE_NUMBER]
|
111
|
+
@as_array << int(@runnable_count)
|
112
|
+
@as_array << 0
|
113
|
+
@as_array << child_arrays
|
114
|
+
end
|
115
|
+
|
116
|
+
def dump_string(indent=0)
|
117
|
+
@file, @method, @line_no = parse_backtrace_frame(@raw_line)
|
118
|
+
result = "#{" " * indent}#<BacktraceNode:#{object_id} [#{@runnable_count}] #{@file}:#{@line_no} in #{@method}>"
|
119
|
+
child_results = @children.map { |c| c.dump_string(indent+2) }.join("\n")
|
120
|
+
result << "\n" unless child_results.empty?
|
121
|
+
result << child_results
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns [filename, method, line number]
|
125
|
+
def parse_backtrace_frame(frame)
|
126
|
+
frame =~ /([^:]*)(\:(\d+))?\:in `(.*)'/
|
127
|
+
[$1, $4, $3] # sic
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Agent
|
5
|
+
module Threading
|
6
|
+
class BacktraceService
|
7
|
+
ALL_TRANSACTIONS = "**ALL**".freeze
|
8
|
+
|
9
|
+
def self.is_supported?
|
10
|
+
RUBY_VERSION >= "1.9.2"
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :worker_loop, :buffer,
|
14
|
+
:effective_polling_period,
|
15
|
+
:overhead_percent_threshold
|
16
|
+
attr_accessor :worker_thread, :profile_agent_code
|
17
|
+
|
18
|
+
def initialize(event_listener=nil)
|
19
|
+
@profiles = {}
|
20
|
+
@buffer = {}
|
21
|
+
|
22
|
+
# synchronizes access to @profiles and @buffer above
|
23
|
+
@lock = Mutex.new
|
24
|
+
|
25
|
+
@running = false
|
26
|
+
@profile_agent_code = false
|
27
|
+
@worker_loop = OneApm::Agent::WorkerLoop.new
|
28
|
+
|
29
|
+
# Memoize overhead % to avoid getting stale OR looked up every poll
|
30
|
+
@overhead_percent_threshold = OneApm::Agent.config[:'xray_session.max_profile_overhead']
|
31
|
+
OneApm::Agent.config.register_callback(:'xray_session.max_profile_overhead') do |new_value|
|
32
|
+
@overhead_percent_threshold = new_value
|
33
|
+
end
|
34
|
+
|
35
|
+
if event_listener
|
36
|
+
event_listener.subscribe(:transaction_finished, &method(:on_transaction_finished))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Public interface
|
41
|
+
|
42
|
+
def running?
|
43
|
+
@running
|
44
|
+
end
|
45
|
+
|
46
|
+
def subscribe(transaction_name, command_arguments={})
|
47
|
+
if !self.class.is_supported?
|
48
|
+
OneApm::Agent.logger.debug("Backtracing not supported, so not subscribing transaction '#{transaction_name}'")
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
OneApm::Agent.logger.debug("Backtrace Service subscribing transaction '#{transaction_name}'")
|
53
|
+
|
54
|
+
profile = ThreadProfile.new(command_arguments)
|
55
|
+
|
56
|
+
@lock.synchronize do
|
57
|
+
@profiles[transaction_name] = profile
|
58
|
+
update_values_from_profiles
|
59
|
+
end
|
60
|
+
|
61
|
+
start
|
62
|
+
profile
|
63
|
+
end
|
64
|
+
|
65
|
+
def unsubscribe(transaction_name)
|
66
|
+
return unless self.class.is_supported?
|
67
|
+
|
68
|
+
OneApm::Agent.logger.debug("Backtrace Service unsubscribing transaction '#{transaction_name}'")
|
69
|
+
@lock.synchronize do
|
70
|
+
@profiles.delete(transaction_name)
|
71
|
+
if @profiles.empty?
|
72
|
+
stop
|
73
|
+
else
|
74
|
+
update_values_from_profiles
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_values_from_profiles
|
80
|
+
self.effective_polling_period = find_effective_polling_period
|
81
|
+
self.profile_agent_code = should_profile_agent_code?
|
82
|
+
end
|
83
|
+
|
84
|
+
def subscribed?(transaction_name)
|
85
|
+
@lock.synchronize do
|
86
|
+
@profiles.has_key?(transaction_name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def harvest(transaction_name)
|
91
|
+
@lock.synchronize do
|
92
|
+
if @profiles[transaction_name]
|
93
|
+
profile = @profiles.delete(transaction_name)
|
94
|
+
profile.finished_at = Time.now
|
95
|
+
@profiles[transaction_name] = ThreadProfile.new(profile.command_arguments)
|
96
|
+
profile
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def on_transaction_finished(payload)
|
102
|
+
name = payload[:name]
|
103
|
+
start = payload[:start_timestamp]
|
104
|
+
duration = payload[:duration]
|
105
|
+
thread = payload[:thread] || Thread.current
|
106
|
+
@lock.synchronize do
|
107
|
+
backtraces = @buffer.delete(thread)
|
108
|
+
if backtraces && @profiles.has_key?(name)
|
109
|
+
aggregate_backtraces(backtraces, name, start, duration, thread)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Internals
|
115
|
+
|
116
|
+
# This method is expected to be called with @lock held.
|
117
|
+
def aggregate_backtraces(backtraces, name, start, duration, thread)
|
118
|
+
end_time = start + duration
|
119
|
+
backtraces.each do |(timestamp, backtrace)|
|
120
|
+
if timestamp >= start && timestamp < end_time
|
121
|
+
@profiles[name].aggregate(backtrace, :request, thread)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def start
|
127
|
+
return if @running || !self.class.is_supported?
|
128
|
+
|
129
|
+
@running = true
|
130
|
+
self.worker_thread = AgentThread.create('Backtrace Service') do
|
131
|
+
# Not passing period because we expect it's already been set.
|
132
|
+
self.worker_loop.run(&method(:poll))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# This method is expected to be called with @lock held
|
137
|
+
def stop
|
138
|
+
return unless @running
|
139
|
+
@running = false
|
140
|
+
self.worker_loop.stop
|
141
|
+
|
142
|
+
@buffer = {}
|
143
|
+
end
|
144
|
+
|
145
|
+
def effective_polling_period=(new_period)
|
146
|
+
@effective_polling_period = new_period
|
147
|
+
self.worker_loop.period = new_period
|
148
|
+
end
|
149
|
+
|
150
|
+
def poll
|
151
|
+
poll_start = Time.now
|
152
|
+
|
153
|
+
@lock.synchronize do
|
154
|
+
AgentThread.list.each do |thread|
|
155
|
+
sample_thread(thread)
|
156
|
+
end
|
157
|
+
@profiles.each_value { |p| p.increment_poll_count }
|
158
|
+
@buffer.delete_if { |thread, _| !thread.alive? }
|
159
|
+
end
|
160
|
+
|
161
|
+
end_time = Time.now
|
162
|
+
adjust_polling_time(end_time, poll_start)
|
163
|
+
record_supportability_metrics(end_time, poll_start)
|
164
|
+
end
|
165
|
+
|
166
|
+
# This method is expected to be called with @lock held.
|
167
|
+
attr_reader :profiles
|
168
|
+
|
169
|
+
# This method is expected to be called with @lock held.
|
170
|
+
def should_buffer?(bucket)
|
171
|
+
bucket == :request && @profiles.keys.any? { |k| k != ALL_TRANSACTIONS }
|
172
|
+
end
|
173
|
+
|
174
|
+
# This method is expected to be called with @lock held.
|
175
|
+
def need_backtrace?(bucket)
|
176
|
+
(
|
177
|
+
bucket != :ignore &&
|
178
|
+
(@profiles[ALL_TRANSACTIONS] || should_buffer?(bucket))
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
MAX_BUFFER_LENGTH = 500
|
183
|
+
|
184
|
+
# This method is expected to be called with @lock held.
|
185
|
+
def buffer_backtrace_for_thread(thread, timestamp, backtrace, bucket)
|
186
|
+
if should_buffer?(bucket)
|
187
|
+
@buffer[thread] ||= []
|
188
|
+
if @buffer[thread].length < MAX_BUFFER_LENGTH
|
189
|
+
@buffer[thread] << [timestamp, backtrace]
|
190
|
+
else
|
191
|
+
OneApm::Agent.increment_metric('Supportability/XraySessions/DroppedBacktraces')
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# This method is expected to be called with @lock held.
|
197
|
+
def aggregate_global_backtrace(backtrace, bucket, thread)
|
198
|
+
if @profiles[ALL_TRANSACTIONS]
|
199
|
+
@profiles[ALL_TRANSACTIONS].aggregate(backtrace, bucket, thread)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# This method is expected to be called with @lock held.
|
204
|
+
def sample_thread(thread)
|
205
|
+
bucket = AgentThread.bucket_thread(thread, @profile_agent_code)
|
206
|
+
|
207
|
+
if need_backtrace?(bucket)
|
208
|
+
timestamp = Time.now.to_f
|
209
|
+
backtrace = AgentThread.scrub_backtrace(thread, @profile_agent_code)
|
210
|
+
aggregate_global_backtrace(backtrace, bucket, thread)
|
211
|
+
buffer_backtrace_for_thread(thread, timestamp, backtrace, bucket)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# This method is expected to be called with @lock held.
|
216
|
+
def find_effective_polling_period
|
217
|
+
@profiles.values.map { |p| p.requested_period }.min
|
218
|
+
end
|
219
|
+
|
220
|
+
# This method is expected to be called with @lock held.
|
221
|
+
def should_profile_agent_code?
|
222
|
+
@profiles.values.any? { |p| p.profile_agent_code }
|
223
|
+
end
|
224
|
+
|
225
|
+
# If our overhead % exceeds the threshold, bump the next poll period
|
226
|
+
# relative to how much larger our overhead is than allowed
|
227
|
+
def adjust_polling_time(now, poll_start)
|
228
|
+
duration = now - poll_start
|
229
|
+
overhead_percent = duration / effective_polling_period
|
230
|
+
|
231
|
+
if overhead_percent > self.overhead_percent_threshold
|
232
|
+
scale_up_by = overhead_percent / self.overhead_percent_threshold
|
233
|
+
worker_loop.period = effective_polling_period * scale_up_by
|
234
|
+
else
|
235
|
+
worker_loop.period = effective_polling_period
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def record_supportability_metrics(now, poll_start)
|
240
|
+
record_polling_time(now, poll_start)
|
241
|
+
record_skew(poll_start)
|
242
|
+
end
|
243
|
+
|
244
|
+
def record_polling_time(now, poll_start)
|
245
|
+
OneApm::Agent.record_metric('Supportability/ThreadProfiler/PollingTime', now - poll_start)
|
246
|
+
end
|
247
|
+
|
248
|
+
def record_skew(poll_start)
|
249
|
+
if @last_poll
|
250
|
+
skew = poll_start - @last_poll - worker_loop.period
|
251
|
+
OneApm::Agent.record_metric('Supportability/ThreadProfiler/Skew', skew)
|
252
|
+
end
|
253
|
+
@last_poll = poll_start
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|