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,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OneApm
|
4
|
+
module Agent
|
5
|
+
class InboundRequestMonitor
|
6
|
+
|
7
|
+
attr_reader :obfuscator
|
8
|
+
|
9
|
+
def initialize(events)
|
10
|
+
events.subscribe(:finished_configuring) do
|
11
|
+
setup_obfuscator
|
12
|
+
on_finished_configuring(events)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_obfuscator
|
17
|
+
@obfuscator = OneApm::Agent::Obfuscator.new(OneApm::Agent.config[:encoding_key])
|
18
|
+
end
|
19
|
+
|
20
|
+
def deserialize_header(encoded_header, key)
|
21
|
+
decoded_header = obfuscator.deobfuscate(encoded_header)
|
22
|
+
OneApm::JSONWrapper.load(decoded_header)
|
23
|
+
rescue => err
|
24
|
+
OneApm::Agent.logger.debug("Failure deserializing encoded header '#{key}' in #{self.class}, #{err.class}, #{err.message}")
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'one_apm/support/obfuscator'
|
5
|
+
require 'one_apm/transaction/transaction_timings'
|
6
|
+
|
7
|
+
module OneApm
|
8
|
+
module Agent
|
9
|
+
class JavascriptInstrumentor
|
10
|
+
include OneApm::Coerce
|
11
|
+
|
12
|
+
RUM_KEY_LENGTH = 13
|
13
|
+
|
14
|
+
def initialize(event_listener)
|
15
|
+
event_listener.subscribe(:finished_configuring, &method(:log_configuration))
|
16
|
+
end
|
17
|
+
|
18
|
+
def log_configuration
|
19
|
+
OneApm::Agent.logger.debug("JS agent loader requested: #{OneApm::Agent.config[:'browser_monitoring.loader']}",
|
20
|
+
"JS agent loader debug: #{OneApm::Agent.config[:'browser_monitoring.debug']}",
|
21
|
+
"JS agent loader version: #{OneApm::Agent.config[:'browser_monitoring.loader_version']}")
|
22
|
+
|
23
|
+
if !OneApm::Agent.config[:'rum.enabled']
|
24
|
+
OneApm::Agent.logger.debug("Real User Monitoring is disabled for this agent. Edit your configuration to change this.")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def enabled?
|
29
|
+
Agent.config[:'rum.enabled'] && !!Agent.config[:beacon]
|
30
|
+
end
|
31
|
+
|
32
|
+
def obfuscator
|
33
|
+
@obfuscator ||= OneApm::Agent::Obfuscator.new(OneApm::Agent.config[:license_key], RUM_KEY_LENGTH)
|
34
|
+
end
|
35
|
+
|
36
|
+
def js_enabled_and_ready?
|
37
|
+
if !enabled?
|
38
|
+
::OneApm::Agent.logger.log_once(:debug, :js_agent_disabled,
|
39
|
+
"JS agent instrumentation is disabled.")
|
40
|
+
false
|
41
|
+
elsif missing_config?(:js_agent_loader)
|
42
|
+
::OneApm::Agent.logger.log_once(:debug, :missing_js_agent_loader,
|
43
|
+
"Missing :js_agent_loader. Skipping browser instrumentation.")
|
44
|
+
false
|
45
|
+
elsif missing_config?(:beacon)
|
46
|
+
::OneApm::Agent.logger.log_once(:debug, :missing_beacon,
|
47
|
+
"Beacon configuration not received (yet?). Skipping browser instrumentation.")
|
48
|
+
false
|
49
|
+
elsif missing_config?(:browser_key)
|
50
|
+
::OneApm::Agent.logger.log_once(:debug, :missing_browser_key,
|
51
|
+
"Browser key is not set. Skipping browser instrumentation.")
|
52
|
+
false
|
53
|
+
else
|
54
|
+
true
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
::OneApm::Agent.logger.debug "Failure during 'js_enabled_and_ready?'", e
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
def insert_js?(state)
|
62
|
+
if !state.current_transaction
|
63
|
+
::OneApm::Agent.logger.debug "Not in transaction. Skipping browser instrumentation."
|
64
|
+
false
|
65
|
+
elsif !state.is_transaction_traced?
|
66
|
+
::OneApm::Agent.logger.debug "Transaction is not traced. Skipping browser instrumentation."
|
67
|
+
false
|
68
|
+
elsif !state.is_execution_traced?
|
69
|
+
::OneApm::Agent.logger.debug "Execution is not traced. Skipping browser instrumentation."
|
70
|
+
false
|
71
|
+
elsif state.current_transaction.ignore_enduser?
|
72
|
+
::OneApm::Agent.logger.debug "Ignore end user for this transaction is set. Skipping browser instrumentation."
|
73
|
+
false
|
74
|
+
else
|
75
|
+
true
|
76
|
+
end
|
77
|
+
rescue => e
|
78
|
+
::OneApm::Agent.logger.debug "Failure during insert_js", e
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def missing_config?(key)
|
83
|
+
value = OneApm::Agent.config[key]
|
84
|
+
value.nil? || value.empty?
|
85
|
+
end
|
86
|
+
|
87
|
+
def browser_timing_header #THREAD_LOCAL_ACCESS
|
88
|
+
return '' unless js_enabled_and_ready? # fast exit
|
89
|
+
|
90
|
+
state = OneApm::TransactionState.tl_get
|
91
|
+
|
92
|
+
return '' unless insert_js?(state) # slower exit
|
93
|
+
|
94
|
+
bt_config = browser_timing_config(state)
|
95
|
+
return '' if bt_config.empty?
|
96
|
+
|
97
|
+
bt_config + browser_timing_loader
|
98
|
+
rescue => e
|
99
|
+
::OneApm::Agent.logger.debug "Failure during RUM browser_timing_header construction", e
|
100
|
+
''
|
101
|
+
end
|
102
|
+
|
103
|
+
def browser_timing_loader
|
104
|
+
html_safe_if_needed("\n<script type=\"text/javascript\" src=\"#{Agent.config[:js_agent_loader]}\"></script>")
|
105
|
+
end
|
106
|
+
|
107
|
+
def browser_timing_config(state)
|
108
|
+
txn = state.current_transaction
|
109
|
+
return '' if txn.nil?
|
110
|
+
|
111
|
+
txn.freeze_name_and_execute_if_not_ignored do
|
112
|
+
data = data_for_js_agent(state)
|
113
|
+
json = OneApm::JSONWrapper.dump(data)
|
114
|
+
return html_safe_if_needed("\n<script type=\"text/javascript\">window.BWEUM||(BWEUM={});BWEUM.info=#{json}</script>")
|
115
|
+
end
|
116
|
+
|
117
|
+
''
|
118
|
+
end
|
119
|
+
|
120
|
+
BEACON_KEY = "beacon".freeze
|
121
|
+
ERROR_BEACON_KEY = "errorBeacon".freeze
|
122
|
+
LICENSE_KEY_KEY = "licenseKey".freeze
|
123
|
+
APPLICATIONID_KEY = "applicationID".freeze
|
124
|
+
TRANSACTION_NAME_KEY = "transactionName".freeze
|
125
|
+
QUEUE_TIME_KEY = "queueTime".freeze
|
126
|
+
APPLICATION_TIME_KEY = "applicationTime".freeze
|
127
|
+
AGENT_KEY = "agent".freeze
|
128
|
+
USER_ATTRIBUTES_KEY = "userAttributes".freeze
|
129
|
+
SSL_FOR_HTTP_KEY = "sslForHttp".freeze
|
130
|
+
|
131
|
+
# NOTE: Internal prototyping may override this, so leave name stable!
|
132
|
+
def data_for_js_agent(state)
|
133
|
+
timings = state.timings
|
134
|
+
|
135
|
+
data = {
|
136
|
+
BEACON_KEY => OneApm::Agent.config[:beacon],
|
137
|
+
ERROR_BEACON_KEY => OneApm::Agent.config[:error_beacon],
|
138
|
+
LICENSE_KEY_KEY => OneApm::Agent.config[:browser_key],
|
139
|
+
APPLICATIONID_KEY => OneApm::Agent.config[:application_id],
|
140
|
+
TRANSACTION_NAME_KEY => obfuscator.obfuscate(timings.transaction_name_or_unknown),
|
141
|
+
QUEUE_TIME_KEY => timings.queue_time_in_millis,
|
142
|
+
APPLICATION_TIME_KEY => timings.app_time_in_millis,
|
143
|
+
AGENT_KEY => OneApm::Agent.config[:js_agent_file]
|
144
|
+
}
|
145
|
+
|
146
|
+
add_ssl_for_http(data)
|
147
|
+
add_user_attributes(data, state.current_transaction)
|
148
|
+
|
149
|
+
data
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_ssl_for_http(data)
|
153
|
+
ssl_for_http = OneApm::Agent.config[:'browser_monitoring.ssl_for_http']
|
154
|
+
unless ssl_for_http.nil?
|
155
|
+
data[SSL_FOR_HTTP_KEY] = ssl_for_http
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def add_user_attributes(data, txn)
|
160
|
+
return unless include_custom_parameters?(txn)
|
161
|
+
|
162
|
+
params = event_params(txn.custom_parameters)
|
163
|
+
json = OneApm::JSONWrapper.dump(params)
|
164
|
+
data[USER_ATTRIBUTES_KEY] = obfuscator.obfuscate(json)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Still support deprecated capture_attributes.page_view_events for
|
168
|
+
# clients that use it. Could potentially be removed if we don't have
|
169
|
+
# anymore users with it set according to zeitgeist.
|
170
|
+
def include_custom_parameters?(txn)
|
171
|
+
has_custom_parameters?(txn) &&
|
172
|
+
(OneApm::Agent.config[:'browser_monitoring.capture_attributes'] ||
|
173
|
+
OneApm::Agent.config[:'capture_attributes.page_view_events'])
|
174
|
+
end
|
175
|
+
|
176
|
+
def has_custom_parameters?(txn)
|
177
|
+
txn && txn.custom_parameters && !txn.custom_parameters.empty?
|
178
|
+
end
|
179
|
+
|
180
|
+
def html_safe_if_needed(string)
|
181
|
+
string = string.html_safe if string.respond_to?(:html_safe)
|
182
|
+
string
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module OneApm
|
6
|
+
module Agent
|
7
|
+
|
8
|
+
#--
|
9
|
+
# Manages the registering and servicing of pipes used by child
|
10
|
+
# processes to report data to their parent, rather than directly
|
11
|
+
# to the collector.
|
12
|
+
module PipeChannelManager
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def register_report_channel(id)
|
16
|
+
listener.register_pipe(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def channels
|
20
|
+
listener.pipes
|
21
|
+
end
|
22
|
+
|
23
|
+
def listener
|
24
|
+
@listener ||= Listener.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Expected initial sequence of events for Pipe usage:
|
28
|
+
#
|
29
|
+
# 1. Pipe is created in parent process (read and write ends open)
|
30
|
+
# 2. Parent process forks
|
31
|
+
# 3. An after_fork hook is invoked in the child
|
32
|
+
# 4. From after_fork hook, child closes read end of pipe, and
|
33
|
+
# writes a ready marker on the pipe (after_fork_in_child).
|
34
|
+
# 5. The parent receives the ready marker, and closes the write end of the
|
35
|
+
# pipe in response (after_fork_in_parent).
|
36
|
+
#
|
37
|
+
# After this sequence of steps, an exit (whether clean or not) of the
|
38
|
+
# child will result in the pipe being marked readable again, and giving an
|
39
|
+
# EOF marker (nil) when read. Note that closing of the unused ends of the
|
40
|
+
# pipe in the parent and child processes is essential in order for the EOF
|
41
|
+
# to be correctly triggered. The ready marker mechanism is used because
|
42
|
+
# there's no easy hook for after_fork in the parent process.
|
43
|
+
#
|
44
|
+
# This class provides message framing (separation of individual messages),
|
45
|
+
# but not serialization. Serialization / deserialization is the
|
46
|
+
# responsibility of clients.
|
47
|
+
#
|
48
|
+
# Message framing works like this:
|
49
|
+
#
|
50
|
+
# Each message sent across the pipe is preceded by a length tag that
|
51
|
+
# specifies the length of the message that immediately follows, in bytes.
|
52
|
+
# The length tags are serialized as unsigned big-endian long values, (4
|
53
|
+
# bytes each). This means that the maximum theoretical message size is
|
54
|
+
# 4 GB - much larger than we'd ever need or want for this application.
|
55
|
+
#
|
56
|
+
class Pipe
|
57
|
+
READY_MARKER = "READY"
|
58
|
+
NUM_LENGTH_BYTES = 4
|
59
|
+
|
60
|
+
attr_accessor :in, :out
|
61
|
+
attr_reader :last_read, :parent_pid
|
62
|
+
|
63
|
+
def initialize
|
64
|
+
@out, @in = IO.pipe
|
65
|
+
if defined?(::Encoding::ASCII_8BIT)
|
66
|
+
@in.set_encoding(::Encoding::ASCII_8BIT)
|
67
|
+
end
|
68
|
+
@last_read = Time.now
|
69
|
+
@parent_pid = $$
|
70
|
+
end
|
71
|
+
|
72
|
+
def close
|
73
|
+
@out.close unless @out.closed?
|
74
|
+
@in.close unless @in.closed?
|
75
|
+
end
|
76
|
+
|
77
|
+
def serialize_message_length(data)
|
78
|
+
[data.bytesize].pack("L>")
|
79
|
+
end
|
80
|
+
|
81
|
+
def deserialize_message_length(data)
|
82
|
+
data.unpack("L>").first
|
83
|
+
end
|
84
|
+
|
85
|
+
def write(data)
|
86
|
+
@out.close unless @out.closed?
|
87
|
+
@in << serialize_message_length(data)
|
88
|
+
@in << data
|
89
|
+
end
|
90
|
+
|
91
|
+
def read
|
92
|
+
@in.close unless @in.closed?
|
93
|
+
@last_read = Time.now
|
94
|
+
length_bytes = @out.read(NUM_LENGTH_BYTES)
|
95
|
+
if length_bytes
|
96
|
+
message_length = deserialize_message_length(length_bytes)
|
97
|
+
if message_length
|
98
|
+
@out.read(message_length)
|
99
|
+
else
|
100
|
+
length_hex = length_bytes.bytes.map { |b| b.to_s(16) }.join(' ')
|
101
|
+
OneApm::Agent.logger.error("Failed to deserialize message length from pipe. Bytes: [#{length_hex}]")
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
else
|
105
|
+
OneApm::Agent.logger.error("Failed to read bytes for length from pipe.")
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def eof?
|
111
|
+
!@out.closed? && @out.eof?
|
112
|
+
end
|
113
|
+
|
114
|
+
def after_fork_in_child
|
115
|
+
@out.close unless @out.closed?
|
116
|
+
write(READY_MARKER)
|
117
|
+
end
|
118
|
+
|
119
|
+
def after_fork_in_parent
|
120
|
+
@in.close unless @in.closed?
|
121
|
+
end
|
122
|
+
|
123
|
+
def closed?
|
124
|
+
@out.closed? && @in.closed?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Listener
|
129
|
+
attr_reader :thread
|
130
|
+
|
131
|
+
# This attr_accessor intentionally provides unsynchronized access to the
|
132
|
+
# @pipes hash. It is used to look up the write end of the pipe from
|
133
|
+
# within the Resque child process, and must be unsynchronized in order
|
134
|
+
# to avoid a potential deadlock in which the PipeChannelManager::Listener
|
135
|
+
# thread in the parent process is holding the @pipes_lock at the time of
|
136
|
+
# the fork.
|
137
|
+
attr_accessor :pipes, :timeout, :select_timeout
|
138
|
+
|
139
|
+
def initialize
|
140
|
+
@pipes = {}
|
141
|
+
@pipes_lock = Mutex.new
|
142
|
+
|
143
|
+
@timeout = 360
|
144
|
+
@select_timeout = 60
|
145
|
+
end
|
146
|
+
|
147
|
+
def wakeup
|
148
|
+
wake.in << '.'
|
149
|
+
end
|
150
|
+
|
151
|
+
def register_pipe(id)
|
152
|
+
@pipes_lock.synchronize do
|
153
|
+
@pipes[id] = Pipe.new
|
154
|
+
end
|
155
|
+
|
156
|
+
wakeup
|
157
|
+
end
|
158
|
+
|
159
|
+
def start
|
160
|
+
return if @started == true
|
161
|
+
@started = true
|
162
|
+
@thread = OneApm::Agent::Threading::AgentThread.create('Pipe Channel Manager') do
|
163
|
+
now = nil
|
164
|
+
loop do
|
165
|
+
clean_up_pipes
|
166
|
+
|
167
|
+
pipes_to_listen_to = @pipes_lock.synchronize do
|
168
|
+
@pipes.values.map{|pipe| pipe.out} + [wake.out]
|
169
|
+
end
|
170
|
+
|
171
|
+
OneApm::Agent.record_metric('Supportability/Listeners',
|
172
|
+
(Time.now - now).to_f) if now
|
173
|
+
|
174
|
+
if ready = IO.select(pipes_to_listen_to, [], [], @select_timeout)
|
175
|
+
now = Time.now
|
176
|
+
|
177
|
+
ready_pipes = ready[0]
|
178
|
+
ready_pipes.each do |pipe|
|
179
|
+
merge_data_from_pipe(pipe) unless pipe == wake.out
|
180
|
+
end
|
181
|
+
|
182
|
+
wake.out.read(1) if ready_pipes.include?(wake.out)
|
183
|
+
end
|
184
|
+
|
185
|
+
break unless should_keep_listening?
|
186
|
+
end
|
187
|
+
end
|
188
|
+
sleep 0.001 # give time for the thread to spawn
|
189
|
+
end
|
190
|
+
|
191
|
+
def stop_listener_thread
|
192
|
+
@started = false
|
193
|
+
wakeup
|
194
|
+
@thread.join
|
195
|
+
end
|
196
|
+
|
197
|
+
def stop
|
198
|
+
return unless @started == true
|
199
|
+
stop_listener_thread
|
200
|
+
close_all_pipes
|
201
|
+
@wake.close
|
202
|
+
@wake = nil
|
203
|
+
end
|
204
|
+
|
205
|
+
def close_all_pipes
|
206
|
+
@pipes_lock.synchronize do
|
207
|
+
@pipes.each do |id, pipe|
|
208
|
+
pipe.close if pipe
|
209
|
+
end
|
210
|
+
@pipes = {}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def wake
|
215
|
+
@wake ||= Pipe.new
|
216
|
+
end
|
217
|
+
|
218
|
+
def started?
|
219
|
+
@started
|
220
|
+
end
|
221
|
+
|
222
|
+
protected
|
223
|
+
|
224
|
+
def merge_data_from_pipe(pipe_handle)
|
225
|
+
pipe = find_pipe_for_handle(pipe_handle)
|
226
|
+
raw_payload = pipe.read
|
227
|
+
if raw_payload && !raw_payload.empty?
|
228
|
+
if raw_payload == Pipe::READY_MARKER
|
229
|
+
pipe.after_fork_in_parent
|
230
|
+
else
|
231
|
+
payload = unmarshal(raw_payload)
|
232
|
+
if payload
|
233
|
+
endpoint, items = payload
|
234
|
+
OneApm::Agent.instance.merge_data_for_endpoint(endpoint, items)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
pipe.close if pipe.eof?
|
240
|
+
end
|
241
|
+
|
242
|
+
def unmarshal(data)
|
243
|
+
OneApm::LanguageSupport.with_cautious_gc do
|
244
|
+
Marshal.load(data)
|
245
|
+
end
|
246
|
+
rescue StandardError => e
|
247
|
+
::OneApm::Agent.logger.error "Failure unmarshalling message from Resque child process", e
|
248
|
+
::OneApm::Agent.logger.debug Base64.encode64(data)
|
249
|
+
nil
|
250
|
+
end
|
251
|
+
|
252
|
+
def should_keep_listening?
|
253
|
+
@started || @pipes_lock.synchronize { @pipes.values.find{|pipe| !pipe.in.closed?} }
|
254
|
+
end
|
255
|
+
|
256
|
+
def clean_up_pipes
|
257
|
+
@pipes_lock.synchronize do
|
258
|
+
@pipes.values.each do |pipe|
|
259
|
+
if pipe.last_read.to_f + @timeout < Time.now.to_f
|
260
|
+
pipe.close unless pipe.closed?
|
261
|
+
end
|
262
|
+
end
|
263
|
+
@pipes.reject! {|id, pipe| pipe.out.closed? }
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def find_pipe_for_handle(out_handle)
|
268
|
+
@pipes_lock.synchronize do
|
269
|
+
@pipes.values.find{|pipe| pipe.out == out_handle }
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|