appoptics_apm 4.0.2
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/.codeclimate.yml +43 -0
- data/.dockerignore +5 -0
- data/.gitignore +23 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +82 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +33 -0
- data/Dockerfile +41 -0
- data/Dockerfile_test +66 -0
- data/Gemfile +41 -0
- data/LICENSE +193 -0
- data/README.md +351 -0
- data/Rakefile +202 -0
- data/Vagrantfile +67 -0
- data/appoptics_apm.gemspec +55 -0
- data/build_gems.sh +15 -0
- data/docker-compose.yml +73 -0
- data/examples/DNT.md +35 -0
- data/examples/carrying_context.rb +220 -0
- data/examples/instrumenting_metal_controller.rb +8 -0
- data/examples/puma_on_heroku_config.rb +17 -0
- data/examples/tracing_async_threads.rb +124 -0
- data/examples/tracing_background_jobs.rb +53 -0
- data/examples/tracing_forked_processes.rb +99 -0
- data/examples/unicorn_on_heroku_config.rb +28 -0
- data/ext/oboe_metal/extconf.rb +54 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0.so.0.0.0 +0 -0
- data/ext/oboe_metal/noop/noop.c +7 -0
- data/ext/oboe_metal/src/VERSION +1 -0
- data/ext/oboe_metal/src/bson/bson.h +221 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/oboe.h +883 -0
- data/ext/oboe_metal/src/oboe.hpp +793 -0
- data/ext/oboe_metal/src/oboe_debug.h +50 -0
- data/ext/oboe_metal/src/oboe_wrap.cxx +6088 -0
- data/ext/oboe_metal/tests/test.rb +11 -0
- data/gemfiles/delayed_job.gemfile +36 -0
- data/gemfiles/frameworks.gemfile +44 -0
- data/gemfiles/instrumentation_mocked.gemfile +29 -0
- data/gemfiles/libraries.gemfile +85 -0
- data/gemfiles/rails23.gemfile +39 -0
- data/gemfiles/rails30.gemfile +42 -0
- data/gemfiles/rails31.gemfile +44 -0
- data/gemfiles/rails32.gemfile +54 -0
- data/gemfiles/rails40.gemfile +27 -0
- data/gemfiles/rails41.gemfile +27 -0
- data/gemfiles/rails42.gemfile +35 -0
- data/gemfiles/rails50.gemfile +44 -0
- data/gemfiles/rails51.gemfile +44 -0
- data/get_version.rb +5 -0
- data/init.rb +4 -0
- data/lib/appoptics_apm/api/layerinit.rb +39 -0
- data/lib/appoptics_apm/api/logging.rb +359 -0
- data/lib/appoptics_apm/api/memcache.rb +34 -0
- data/lib/appoptics_apm/api/profiling.rb +201 -0
- data/lib/appoptics_apm/api/tracing.rb +152 -0
- data/lib/appoptics_apm/api/util.rb +128 -0
- data/lib/appoptics_apm/api.rb +18 -0
- data/lib/appoptics_apm/base.rb +252 -0
- data/lib/appoptics_apm/config.rb +281 -0
- data/lib/appoptics_apm/frameworks/grape.rb +93 -0
- data/lib/appoptics_apm/frameworks/padrino/templates.rb +58 -0
- data/lib/appoptics_apm/frameworks/padrino.rb +52 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +106 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +61 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +58 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +56 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +120 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +101 -0
- data/lib/appoptics_apm/frameworks/rails.rb +116 -0
- data/lib/appoptics_apm/frameworks/sinatra/templates.rb +56 -0
- data/lib/appoptics_apm/frameworks/sinatra.rb +71 -0
- data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
- data/lib/appoptics_apm/inst/bunny-consumer.rb +92 -0
- data/lib/appoptics_apm/inst/curb.rb +329 -0
- data/lib/appoptics_apm/inst/dalli.rb +85 -0
- data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
- data/lib/appoptics_apm/inst/em-http-request.rb +105 -0
- data/lib/appoptics_apm/inst/excon.rb +130 -0
- data/lib/appoptics_apm/inst/faraday.rb +77 -0
- data/lib/appoptics_apm/inst/http.rb +83 -0
- data/lib/appoptics_apm/inst/httpclient.rb +176 -0
- data/lib/appoptics_apm/inst/memcache.rb +102 -0
- data/lib/appoptics_apm/inst/memcached.rb +94 -0
- data/lib/appoptics_apm/inst/mongo.rb +242 -0
- data/lib/appoptics_apm/inst/mongo2.rb +225 -0
- data/lib/appoptics_apm/inst/moped.rb +466 -0
- data/lib/appoptics_apm/inst/rack.rb +146 -0
- data/lib/appoptics_apm/inst/redis.rb +275 -0
- data/lib/appoptics_apm/inst/resque.rb +151 -0
- data/lib/appoptics_apm/inst/rest-client.rb +50 -0
- data/lib/appoptics_apm/inst/sequel.rb +178 -0
- data/lib/appoptics_apm/inst/sidekiq-client.rb +53 -0
- data/lib/appoptics_apm/inst/sidekiq-worker.rb +67 -0
- data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
- data/lib/appoptics_apm/inst/typhoeus.rb +113 -0
- data/lib/appoptics_apm/instrumentation.rb +22 -0
- data/lib/appoptics_apm/legacy_method_profiling.rb +97 -0
- data/lib/appoptics_apm/loading.rb +66 -0
- data/lib/appoptics_apm/logger.rb +41 -0
- data/lib/appoptics_apm/method_profiling.rb +33 -0
- data/lib/appoptics_apm/ruby.rb +35 -0
- data/lib/appoptics_apm/support.rb +135 -0
- data/lib/appoptics_apm/test.rb +94 -0
- data/lib/appoptics_apm/thread_local.rb +26 -0
- data/lib/appoptics_apm/util.rb +312 -0
- data/lib/appoptics_apm/version.rb +15 -0
- data/lib/appoptics_apm/xtrace.rb +103 -0
- data/lib/appoptics_apm.rb +72 -0
- data/lib/joboe_metal.rb +214 -0
- data/lib/oboe/README +2 -0
- data/lib/oboe/backward_compatibility.rb +80 -0
- data/lib/oboe/inst/rack.rb +11 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +187 -0
- data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +222 -0
- data/ruby_setup.sh +47 -0
- data/run_docker_build_gem_upload_to_packagecloud.sh +20 -0
- data/run_tests_docker.rb +32 -0
- data/test/benchmark/README.md +65 -0
- data/test/benchmark/logging_bench.rb +54 -0
- data/test/benchmark/with_libraries_gemfile/bunny_bench.rb +69 -0
- data/test/benchmark/with_rails5x_gemfile/action_controller5x_bench.rb +43 -0
- data/test/frameworks/apps/grape_nested.rb +33 -0
- data/test/frameworks/apps/grape_simple.rb +80 -0
- data/test/frameworks/apps/padrino_simple.rb +80 -0
- data/test/frameworks/apps/sinatra_simple.rb +55 -0
- data/test/frameworks/grape_test.rb +286 -0
- data/test/frameworks/padrino_test.rb +222 -0
- data/test/frameworks/rails3x_test.rb +554 -0
- data/test/frameworks/rails4x_test.rb +570 -0
- data/test/frameworks/rails5x_api_test.rb +210 -0
- data/test/frameworks/rails5x_test.rb +376 -0
- data/test/frameworks/rails_shared_tests.rb +172 -0
- data/test/frameworks/sinatra_test.rb +140 -0
- data/test/instrumentation/bunny_client_test.rb +276 -0
- data/test/instrumentation/bunny_consumer_test.rb +204 -0
- data/test/instrumentation/curb_test.rb +398 -0
- data/test/instrumentation/dalli_test.rb +177 -0
- data/test/instrumentation/em_http_request_test.rb +89 -0
- data/test/instrumentation/excon_test.rb +231 -0
- data/test/instrumentation/faraday_test.rb +228 -0
- data/test/instrumentation/http_test.rb +143 -0
- data/test/instrumentation/httpclient_test.rb +320 -0
- data/test/instrumentation/memcache_test.rb +260 -0
- data/test/instrumentation/memcached_test.rb +229 -0
- data/test/instrumentation/mongo_v1_test.rb +479 -0
- data/test/instrumentation/mongo_v2_index_test.rb +124 -0
- data/test/instrumentation/mongo_v2_test.rb +584 -0
- data/test/instrumentation/mongo_v2_view_test.rb +435 -0
- data/test/instrumentation/moped_test.rb +517 -0
- data/test/instrumentation/rack_test.rb +165 -0
- data/test/instrumentation/redis_hashes_test.rb +268 -0
- data/test/instrumentation/redis_keys_test.rb +321 -0
- data/test/instrumentation/redis_lists_test.rb +310 -0
- data/test/instrumentation/redis_misc_test.rb +163 -0
- data/test/instrumentation/redis_sets_test.rb +296 -0
- data/test/instrumentation/redis_sortedsets_test.rb +328 -0
- data/test/instrumentation/redis_strings_test.rb +349 -0
- data/test/instrumentation/resque_test.rb +185 -0
- data/test/instrumentation/rest-client_test.rb +288 -0
- data/test/instrumentation/sequel_mysql2_test.rb +353 -0
- data/test/instrumentation/sequel_mysql_test.rb +334 -0
- data/test/instrumentation/sequel_pg_test.rb +336 -0
- data/test/instrumentation/sidekiq-client_test.rb +159 -0
- data/test/instrumentation/sidekiq-worker_test.rb +180 -0
- data/test/instrumentation/twitter-cassandra_test.rb +424 -0
- data/test/instrumentation/typhoeus_test.rb +284 -0
- data/test/jobs/delayed_job/db_worker_job.rb +29 -0
- data/test/jobs/delayed_job/error_worker_job.rb +10 -0
- data/test/jobs/delayed_job/remote_call_worker_job.rb +20 -0
- data/test/jobs/resque/db_worker_job.rb +29 -0
- data/test/jobs/resque/error_worker_job.rb +10 -0
- data/test/jobs/resque/remote_call_worker_job.rb +20 -0
- data/test/jobs/sidekiq/db_worker_job.rb +29 -0
- data/test/jobs/sidekiq/error_worker_job.rb +10 -0
- data/test/jobs/sidekiq/remote_call_worker_job.rb +20 -0
- data/test/minitest_helper.rb +276 -0
- data/test/mocked/curb_mocked_test.rb +311 -0
- data/test/mocked/excon_mocked_test.rb +166 -0
- data/test/mocked/faraday_mocked_test.rb +93 -0
- data/test/mocked/http_mocked_test.rb +129 -0
- data/test/mocked/httpclient_mocked_test.rb +245 -0
- data/test/mocked/rest_client_mocked_test.rb +103 -0
- data/test/mocked/typhoeus_mocked_test.rb +192 -0
- data/test/models/widget.rb +36 -0
- data/test/profiling/legacy_method_profiling_test.rb +201 -0
- data/test/profiling/method_profiling_test.rb +631 -0
- data/test/queues/delayed_job-client_test.rb +95 -0
- data/test/queues/delayed_job-worker_test.rb +91 -0
- data/test/reporter/reporter_test.rb +14 -0
- data/test/servers/delayed_job.rb +107 -0
- data/test/servers/rackapp_8101.rb +29 -0
- data/test/servers/rails3x_8140.rb +96 -0
- data/test/servers/rails4x_8140.rb +96 -0
- data/test/servers/rails5x_8140.rb +95 -0
- data/test/servers/rails5x_api_8150.rb +78 -0
- data/test/servers/sidekiq.rb +29 -0
- data/test/servers/sidekiq.yml +7 -0
- data/test/servers/sidekiq_initializer.rb +25 -0
- data/test/settings +0 -0
- data/test/support/auto_tracing_test.rb +50 -0
- data/test/support/backcompat_test.rb +276 -0
- data/test/support/config_test.rb +149 -0
- data/test/support/dnt_test.rb +98 -0
- data/test/support/init_report_test.rb +25 -0
- data/test/support/liboboe_settings_test.rb +110 -0
- data/test/support/logging_test.rb +130 -0
- data/test/support/noop_test.rb +88 -0
- data/test/support/sql_sanitize_test.rb +55 -0
- data/test/support/tracing_mode_test.rb +33 -0
- data/test/support/tvalias_test.rb +15 -0
- data/test/support/xtrace_test.rb +41 -0
- metadata +475 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module AppOpticsAPM
|
|
7
|
+
module API
|
|
8
|
+
##
|
|
9
|
+
# Provides the higher-level tracing interface for the API.
|
|
10
|
+
#
|
|
11
|
+
# Traces are best created with a <tt>AppOpticsAPM:API.start_trace</tt> block and
|
|
12
|
+
# <tt>AppOpticsAPM:API.trace</tt> blocks around calls to be traced.
|
|
13
|
+
# These two methods guarantee proper nesting of tracing and handling of the tracing context.
|
|
14
|
+
#
|
|
15
|
+
# Some optional keys that can be used in the +opts+ hash:
|
|
16
|
+
# * +:TransactionName+ - this will show up in the transactions column in the traces dashboard
|
|
17
|
+
# * +:Controller+ - if present will be combined with +Action+ and show up as transaction in the traces dashboard
|
|
18
|
+
# * +:Action+ - if present will be combined with +Controller+ and show up as transaction in the traces dashboard
|
|
19
|
+
# * +:HTTP-Host+ - domain portion of URL
|
|
20
|
+
# * +:URL+ - request URI
|
|
21
|
+
# * +:Method+
|
|
22
|
+
#
|
|
23
|
+
# Invalid keys: +:Label+, +:Layer+, +:Edge+, +:Timestamp+, +:Timestamp_u+
|
|
24
|
+
#
|
|
25
|
+
module Tracing
|
|
26
|
+
# Public: Trace a given block of code. Detect any exceptions thrown by
|
|
27
|
+
# the block and report errors.
|
|
28
|
+
#
|
|
29
|
+
# * +:layer+ - The layer the block of code belongs to.
|
|
30
|
+
# * +:opts+ - A hash containing key/value pairs that will be reported along
|
|
31
|
+
# with the first event of this layer (optional).
|
|
32
|
+
# * +:protect_op+ - The operation being traced. Used to avoid
|
|
33
|
+
# double tracing operations that call each other
|
|
34
|
+
#
|
|
35
|
+
# Example
|
|
36
|
+
#
|
|
37
|
+
# def computation(n)
|
|
38
|
+
# fib(n)
|
|
39
|
+
# raise Exception.new
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# def computation_with_oboe(n)
|
|
43
|
+
# trace('fib', { :number => n }, :fib) do
|
|
44
|
+
# computation(n)
|
|
45
|
+
# end
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# result = computation_with_oboe(1000)
|
|
49
|
+
#
|
|
50
|
+
# Returns the result of the block.
|
|
51
|
+
def trace(layer, opts = {}, protect_op = nil)
|
|
52
|
+
log_entry(layer, opts, protect_op)
|
|
53
|
+
begin
|
|
54
|
+
yield
|
|
55
|
+
rescue Exception => e
|
|
56
|
+
log_exception(layer, e)
|
|
57
|
+
raise
|
|
58
|
+
ensure
|
|
59
|
+
log_exit(layer)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Public: Trace a given block of code which can start a trace depending
|
|
64
|
+
# on configuration and probability. Detect any exceptions thrown by the
|
|
65
|
+
# block and report errors.
|
|
66
|
+
#
|
|
67
|
+
# When start_trace returns control to the calling context, the oboe
|
|
68
|
+
# context will be cleared.
|
|
69
|
+
#
|
|
70
|
+
# layer - The layer the block of code belongs to.
|
|
71
|
+
# opts - A hash containing key/value pairs that will be reported along
|
|
72
|
+
# with the first event of this layer (optional).
|
|
73
|
+
#
|
|
74
|
+
# Example
|
|
75
|
+
#
|
|
76
|
+
# def handle_request(request, response)
|
|
77
|
+
# # ... code that modifies request and response ...
|
|
78
|
+
# end
|
|
79
|
+
#
|
|
80
|
+
# def handle_request_with_oboe(request, response)
|
|
81
|
+
# result, xtrace = start_trace('rails', request['X-Trace']) do
|
|
82
|
+
# handle_request(request, response)
|
|
83
|
+
# end
|
|
84
|
+
# result
|
|
85
|
+
# rescue Exception => e
|
|
86
|
+
# xtrace = e.xtrace
|
|
87
|
+
# ensure
|
|
88
|
+
# response['X-trace'] = xtrace
|
|
89
|
+
# end
|
|
90
|
+
#
|
|
91
|
+
# Returns a list of length two, the first element of which is the result
|
|
92
|
+
# of the block, and the second element of which is the oboe context that
|
|
93
|
+
# was set when the block completed execution.
|
|
94
|
+
def start_trace(layer, xtrace = nil, opts = {})
|
|
95
|
+
log_start(layer, xtrace, opts)
|
|
96
|
+
begin
|
|
97
|
+
result = yield
|
|
98
|
+
rescue Exception => e
|
|
99
|
+
log_exception(layer, e)
|
|
100
|
+
e.instance_variable_set(:@xtrace, log_end(layer))
|
|
101
|
+
raise
|
|
102
|
+
end
|
|
103
|
+
xtrace = log_end(layer)
|
|
104
|
+
|
|
105
|
+
[result, xtrace]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Public: Trace a given block of code which can start a trace depending
|
|
109
|
+
# on configuration and probability. Detect any exceptions thrown by the
|
|
110
|
+
# block and report errors. Assign an X-Trace to the target.
|
|
111
|
+
#
|
|
112
|
+
# The motivating use case for this is HTTP streaming in rails3. We need
|
|
113
|
+
# access to the exit event's trace id so we can set the header before any
|
|
114
|
+
# work is done, and before any headers are sent back to the client.
|
|
115
|
+
#
|
|
116
|
+
# layer - The layer the block of code belongs to.
|
|
117
|
+
# xtrace - string - The X-Trace to continue by the target
|
|
118
|
+
# target - has to respond to #[]=, The target object in which to place the trace information
|
|
119
|
+
# opts - A hash containing key/value pairs that will be reported along
|
|
120
|
+
# with the first event of this layer (optional).
|
|
121
|
+
#
|
|
122
|
+
# Example:
|
|
123
|
+
#
|
|
124
|
+
# def handle_request(request, response)
|
|
125
|
+
# # ... code that does something with request and response ...
|
|
126
|
+
# end
|
|
127
|
+
#
|
|
128
|
+
# def handle_request_with_oboe(request, response)
|
|
129
|
+
# start_trace_with_target('rails', request['X-Trace'], response) do
|
|
130
|
+
# handle_request(request, response)
|
|
131
|
+
# end
|
|
132
|
+
# end
|
|
133
|
+
#
|
|
134
|
+
# Returns the result of the block.
|
|
135
|
+
def start_trace_with_target(layer, xtrace, target, opts = {})
|
|
136
|
+
log_start(layer, xtrace, opts)
|
|
137
|
+
exit_evt = AppOpticsAPM::Context.createEvent
|
|
138
|
+
begin
|
|
139
|
+
target['X-Trace'] = AppOpticsAPM::EventUtil.metadataString(exit_evt) if AppOpticsAPM.tracing?
|
|
140
|
+
yield
|
|
141
|
+
rescue Exception => e
|
|
142
|
+
log_exception(layer, e)
|
|
143
|
+
raise
|
|
144
|
+
ensure
|
|
145
|
+
exit_evt.addEdge(AppOpticsAPM::Context.get)
|
|
146
|
+
log(layer, :exit, {}, exit_evt)
|
|
147
|
+
AppOpticsAPM::Context.clear
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
require 'pp'
|
|
7
|
+
|
|
8
|
+
module AppOpticsAPM
|
|
9
|
+
module API
|
|
10
|
+
##
|
|
11
|
+
# General utility methods for the gem
|
|
12
|
+
module Util
|
|
13
|
+
BACKTRACE_CUTOFF = 200
|
|
14
|
+
|
|
15
|
+
# Internal: Check whether the provided key is reserved or not. Reserved
|
|
16
|
+
# keys are either keys that are handled by liboboe calls or the appoptics_apm gem.
|
|
17
|
+
#
|
|
18
|
+
# key - the key to check.
|
|
19
|
+
#
|
|
20
|
+
# Return a boolean indicating whether or not key is reserved.
|
|
21
|
+
def valid_key?(key)
|
|
22
|
+
![:Label, :Layer, :Edge, :Timestamp, :Timestamp_u].include?(key.to_sym)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Internal: Get the current backtrace.
|
|
26
|
+
#
|
|
27
|
+
# ignore - Number of frames to ignore at the top of the backtrace. Use
|
|
28
|
+
# when you know how many layers deep in the key call is being
|
|
29
|
+
# made.
|
|
30
|
+
#
|
|
31
|
+
# Returns a string with each frame of the backtrace separated by '\r\n'.
|
|
32
|
+
#
|
|
33
|
+
def backtrace(ignore = 0)
|
|
34
|
+
bt = Kernel.caller
|
|
35
|
+
bt.slice!(0, ignore)
|
|
36
|
+
trim_backtrace(bt).join("\r\n")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Internal: Trim a backtrace to a manageable size
|
|
40
|
+
#
|
|
41
|
+
# backtrace - the backtrace (an array of stack frames/from Kernel.caller)
|
|
42
|
+
#
|
|
43
|
+
# Returns a trimmed backtrace
|
|
44
|
+
def trim_backtrace(backtrace)
|
|
45
|
+
return backtrace unless backtrace.is_a?(Array)
|
|
46
|
+
|
|
47
|
+
length = backtrace.size
|
|
48
|
+
if length > BACKTRACE_CUTOFF
|
|
49
|
+
# Trim backtraces by getting the first 180 and last 20 lines
|
|
50
|
+
trimmed = backtrace[0, 180] + ['...[snip]...'] + backtrace[length - 20, 20]
|
|
51
|
+
else
|
|
52
|
+
trimmed = backtrace
|
|
53
|
+
end
|
|
54
|
+
trimmed
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Internal: Check if a host is blacklisted from tracing
|
|
58
|
+
#
|
|
59
|
+
# addr_port - the addr_port from Net::HTTP although this method
|
|
60
|
+
# can be used from any component in reality
|
|
61
|
+
#
|
|
62
|
+
# Returns a boolean on blacklisted state
|
|
63
|
+
def blacklisted?(addr_port)
|
|
64
|
+
return false unless AppOpticsAPM::Config.blacklist
|
|
65
|
+
|
|
66
|
+
# Ensure that the blacklist is an array
|
|
67
|
+
unless AppOpticsAPM::Config.blacklist.is_a?(Array)
|
|
68
|
+
val = AppOpticsAPM::Config[:blacklist]
|
|
69
|
+
AppOpticsAPM::Config[:blacklist] = [val.to_s]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
AppOpticsAPM::Config.blacklist.each do |h|
|
|
73
|
+
return true if addr_port.to_s.match(h.to_s)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Internal: Pretty print a list of arguments for reporting
|
|
80
|
+
#
|
|
81
|
+
# args - the list of arguments to work on
|
|
82
|
+
#
|
|
83
|
+
# Returns a pretty string representation of arguments
|
|
84
|
+
def pps(*args)
|
|
85
|
+
old_out = $stdout
|
|
86
|
+
begin
|
|
87
|
+
s = StringIO.new
|
|
88
|
+
$stdout = s
|
|
89
|
+
pp(*args)
|
|
90
|
+
ensure
|
|
91
|
+
$stdout = old_out
|
|
92
|
+
end
|
|
93
|
+
s.string
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Internal: Determine a string to report representing klass
|
|
97
|
+
#
|
|
98
|
+
# args - an instance of a Class, a Class or a Module
|
|
99
|
+
#
|
|
100
|
+
# Returns a string representation of klass
|
|
101
|
+
def get_class_name(klass)
|
|
102
|
+
kv = {}
|
|
103
|
+
|
|
104
|
+
if klass.to_s =~ /::/
|
|
105
|
+
klass.class.to_s.rpartition('::').last
|
|
106
|
+
else
|
|
107
|
+
if klass.is_a?(Class) && klass.is_a?(Module)
|
|
108
|
+
# Class
|
|
109
|
+
kv['Class'] = klass.to_s
|
|
110
|
+
|
|
111
|
+
elsif !klass.is_a?(Class) && !klass.is_a?(Module)
|
|
112
|
+
# Class instance
|
|
113
|
+
kv['Class'] = klass.class.to_s
|
|
114
|
+
|
|
115
|
+
else
|
|
116
|
+
# Module
|
|
117
|
+
kv['Module'] = klass.to_s
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
kv
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def xtrace_v2?(xtr)
|
|
124
|
+
return xtr && xtr.start_with?('2B')
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
##
|
|
6
|
+
# This module implements the AppOpticsAPM tracing API.
|
|
7
|
+
# See: https://github.com/librato/ruby-appoptics#the-tracing-api
|
|
8
|
+
# and/or: http://rdoc.info/gems/appoptics_apm/AppOpticsAPM/API/Tracing
|
|
9
|
+
module API
|
|
10
|
+
def self.extend_with_tracing
|
|
11
|
+
extend AppOpticsAPM::API::Logging
|
|
12
|
+
extend AppOpticsAPM::API::Tracing
|
|
13
|
+
extend AppOpticsAPM::API::Profiling
|
|
14
|
+
extend AppOpticsAPM::API::LayerInit
|
|
15
|
+
end
|
|
16
|
+
extend AppOpticsAPM::API::Util
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
# Constants from liboboe
|
|
5
|
+
OBOE_TRACE_NEVER = 0
|
|
6
|
+
OBOE_TRACE_ALWAYS = 1
|
|
7
|
+
OBOE_TRACE_THROUGH = 2
|
|
8
|
+
|
|
9
|
+
OBOE_SAMPLE_RATE_SOURCE_FILE = 1
|
|
10
|
+
OBOE_SAMPLE_RATE_SOURCE_DEFAULT = 2
|
|
11
|
+
OBOE_SAMPLE_RATE_SOURCE_OBOE = 3
|
|
12
|
+
OBOE_SAMPLE_RATE_SOURCE_LAST_OBOE = 4
|
|
13
|
+
OBOE_SAMPLE_RATE_SOURCE_DEFAULT_MISCONFIGURED = 5
|
|
14
|
+
OBOE_SAMPLE_RATE_SOURCE_OBOE_DEFAULT = 6
|
|
15
|
+
|
|
16
|
+
# Masks for bitwise ops
|
|
17
|
+
ZERO_MASK = 0b0000000000000000000000000000
|
|
18
|
+
|
|
19
|
+
SAMPLE_RATE_MASK = 0b0000111111111111111111111111
|
|
20
|
+
SAMPLE_SOURCE_MASK = 0b1111000000000000000000000000
|
|
21
|
+
|
|
22
|
+
ZERO_SAMPLE_RATE_MASK = 0b1111000000000000000000000000
|
|
23
|
+
ZERO_SAMPLE_SOURCE_MASK = 0b0000111111111111111111111111
|
|
24
|
+
|
|
25
|
+
APPOPTICS_STR_BLANK = ''.freeze
|
|
26
|
+
APPOPTICS_STR_LAYER = 'Layer'.freeze
|
|
27
|
+
APPOPTICS_STR_LABEL = 'Label'.freeze
|
|
28
|
+
|
|
29
|
+
# Used in tests to store local trace data
|
|
30
|
+
TRACE_FILE = '/tmp/appoptics_traces.bson'.freeze
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# This module is the base module for the various implementations of AppOpticsAPM reporting.
|
|
34
|
+
# Current variations as of 2014-09-10 are a c-extension, JRuby (using AppOpticsAPM Java
|
|
35
|
+
# instrumentation) and a Heroku c-extension (with embedded tracelyzer)
|
|
36
|
+
module AppOpticsAPMBase
|
|
37
|
+
extend ::AppOpticsAPM::ThreadLocal
|
|
38
|
+
|
|
39
|
+
attr_accessor :reporter
|
|
40
|
+
attr_accessor :loaded
|
|
41
|
+
thread_local :sample_source
|
|
42
|
+
thread_local :sample_rate
|
|
43
|
+
thread_local :layer
|
|
44
|
+
thread_local :layer_op
|
|
45
|
+
# Semaphore used during the test suite to test
|
|
46
|
+
# global config options.
|
|
47
|
+
thread_local :config_lock
|
|
48
|
+
|
|
49
|
+
# The following accessors indicate the incoming tracing state received
|
|
50
|
+
# by the rack layer. These are primarily used to identify state
|
|
51
|
+
# between the Ruby and JAppOpticsAPM instrumentation under JRuby.
|
|
52
|
+
#
|
|
53
|
+
# This is because that even though there may be an incoming
|
|
54
|
+
# X-Trace request header, tracing may have already been started
|
|
55
|
+
# by Joboe. Such a scenario occurs when the application is being
|
|
56
|
+
# hosted by a Java container (such as Tomcat or Glassfish) and
|
|
57
|
+
# JAppOpticsAPM has already initiated tracing. In this case, we shouldn't
|
|
58
|
+
# pickup the X-Trace context in the X-Trace header and we shouldn't
|
|
59
|
+
# set the outgoing response X-Trace header or clear context.
|
|
60
|
+
# Yeah I know. Yuck.
|
|
61
|
+
|
|
62
|
+
# Occurs only on Jruby. Indicates that Joboe (the java instrumentation)
|
|
63
|
+
# has already started tracing before it hit the JRuby instrumentation.
|
|
64
|
+
thread_local :has_incoming_context
|
|
65
|
+
|
|
66
|
+
# Indicates the existence of a valid X-Trace request header
|
|
67
|
+
thread_local :has_xtrace_header
|
|
68
|
+
|
|
69
|
+
# This indicates that this trace was continued from
|
|
70
|
+
# an incoming X-Trace request header or in the case
|
|
71
|
+
# of JRuby, a trace already started by JAppOpticsAPM.
|
|
72
|
+
thread_local :is_continued_trace
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# extended
|
|
76
|
+
#
|
|
77
|
+
# Invoked when this module is extended.
|
|
78
|
+
# e.g. extend AppOpticsAPMBase
|
|
79
|
+
#
|
|
80
|
+
def self.extended(cls)
|
|
81
|
+
cls.loaded = true
|
|
82
|
+
|
|
83
|
+
# This gives us pretty accessors with questions marks at the end
|
|
84
|
+
# e.g. is_continued_trace --> is_continued_trace?
|
|
85
|
+
AppOpticsAPM.methods.select { |m| m =~ /^is_|^has_/ }.each do |c|
|
|
86
|
+
unless c =~ /\?$|=$/
|
|
87
|
+
# AppOpticsAPM.logger.debug "aliasing #{c}? to #{c}"
|
|
88
|
+
alias_method "#{c}?", c
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# pickup_context
|
|
95
|
+
#
|
|
96
|
+
# Determines whether we should pickup context
|
|
97
|
+
# from an incoming X-Trace request header. The answer
|
|
98
|
+
# is generally yes but there are cases in JRuby under
|
|
99
|
+
# Tomcat (or Glassfish etc.) where tracing may have
|
|
100
|
+
# been already started by the Java instrumentation (Joboe)
|
|
101
|
+
# in which case we don't want to do this.
|
|
102
|
+
#
|
|
103
|
+
def pickup_context?(xtrace)
|
|
104
|
+
return false unless AppOpticsAPM::XTrace.valid?(xtrace)
|
|
105
|
+
|
|
106
|
+
if defined?(JRUBY_VERSION) && AppOpticsAPM.tracing?
|
|
107
|
+
return false
|
|
108
|
+
else
|
|
109
|
+
return true
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
##
|
|
114
|
+
# tracing_layer?
|
|
115
|
+
#
|
|
116
|
+
# Queries the thread local variable about the current
|
|
117
|
+
# layer being traced. This is used in cases of recursive
|
|
118
|
+
# operation tracing or one instrumented operation calling another.
|
|
119
|
+
#
|
|
120
|
+
def tracing_layer?(layer)
|
|
121
|
+
AppOpticsAPM.layer == layer.to_sym
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
##
|
|
125
|
+
# tracing_layer_op?
|
|
126
|
+
#
|
|
127
|
+
# Queries the thread local variable about the current
|
|
128
|
+
# operation being traced. This is used in cases of recursive
|
|
129
|
+
# operation tracing or one instrumented operation calling another.
|
|
130
|
+
#
|
|
131
|
+
# <operation> can be a single symbol or an array of symbols that
|
|
132
|
+
# will be checked against.
|
|
133
|
+
#
|
|
134
|
+
# In such cases, we only want to trace the outermost operation.
|
|
135
|
+
#
|
|
136
|
+
def tracing_layer_op?(operation)
|
|
137
|
+
if operation.is_a?(Array)
|
|
138
|
+
operation.include?(AppOpticsAPM.layer_op)
|
|
139
|
+
else
|
|
140
|
+
AppOpticsAPM.layer_op == operation.to_sym
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
# Returns true if the tracing_mode is set to always.
|
|
146
|
+
# False otherwise
|
|
147
|
+
#
|
|
148
|
+
def always?
|
|
149
|
+
AppOpticsAPM::Config[:tracing_mode] &&
|
|
150
|
+
AppOpticsAPM::Config[:tracing_mode].to_sym == :always
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
##
|
|
154
|
+
# Returns true if the tracing_mode is set to never.
|
|
155
|
+
# False otherwise
|
|
156
|
+
#
|
|
157
|
+
def never?
|
|
158
|
+
AppOpticsAPM::Config[:tracing_mode] &&
|
|
159
|
+
AppOpticsAPM::Config[:tracing_mode].to_sym == :never
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
##
|
|
163
|
+
# Returns true if we are currently tracing a request
|
|
164
|
+
# False otherwise
|
|
165
|
+
#
|
|
166
|
+
def tracing?
|
|
167
|
+
return false if !AppOpticsAPM.loaded || AppOpticsAPM.never?
|
|
168
|
+
AppOpticsAPM::Context.isSampled
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def heroku?
|
|
172
|
+
ENV.key?('APPOPTICS_URL')
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
##
|
|
176
|
+
# Determines if we are running under a forking webserver
|
|
177
|
+
#
|
|
178
|
+
def forking_webserver?
|
|
179
|
+
if (defined?(::Unicorn) && ($PROGRAM_NAME =~ /unicorn/i)) ||
|
|
180
|
+
(defined?(::Puma) && ($PROGRAM_NAME =~ /puma/i))
|
|
181
|
+
true
|
|
182
|
+
else
|
|
183
|
+
false
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
##
|
|
188
|
+
# Debugging helper method
|
|
189
|
+
#
|
|
190
|
+
def pry!
|
|
191
|
+
# Only valid for development or test environments
|
|
192
|
+
env = ENV['RACK_ENV'] || ENV['RAILS_ENV']
|
|
193
|
+
return unless %w(development, test).include? env
|
|
194
|
+
|
|
195
|
+
if RUBY_VERSION > '1.9.3'
|
|
196
|
+
require 'pry'
|
|
197
|
+
require 'pry-byebug'
|
|
198
|
+
|
|
199
|
+
if defined?(PryByebug)
|
|
200
|
+
Pry.commands.alias_command 'c', 'continue'
|
|
201
|
+
Pry.commands.alias_command 's', 'step'
|
|
202
|
+
Pry.commands.alias_command 'n', 'next'
|
|
203
|
+
Pry.commands.alias_command 'f', 'finish'
|
|
204
|
+
|
|
205
|
+
Pry::Commands.command(/^$/, 'repeat last command') do
|
|
206
|
+
_pry_.run_command Pry.history.to_a.last
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
byebug
|
|
211
|
+
else
|
|
212
|
+
require 'ruby-debug'; debugger
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
##
|
|
217
|
+
# Indicates whether a supported framework is in use
|
|
218
|
+
# or not
|
|
219
|
+
#
|
|
220
|
+
def framework?
|
|
221
|
+
defined?(::Rails) || defined?(::Sinatra) || defined?(::Padrino) || defined?(::Grape)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
##
|
|
225
|
+
# These methods should be implemented by the descendants
|
|
226
|
+
# (Oboe_metal, JOboe_metal (JRuby), Heroku_metal)
|
|
227
|
+
#
|
|
228
|
+
def sample?(_opts = {})
|
|
229
|
+
fail 'sample? should be implemented by metal layer.'
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def log(_layer, _label, _options = {})
|
|
233
|
+
fail 'log should be implemented by metal layer.'
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def set_tracing_mode(_mode)
|
|
237
|
+
fail 'set_tracing_mode should be implemented by metal layer.'
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def set_sample_rate(_rate)
|
|
241
|
+
fail 'set_sample_rate should be implemented by metal layer.'
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
module AppOpticsAPM
|
|
246
|
+
extend AppOpticsAPMBase
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Setup an alias so we don't bug users
|
|
250
|
+
# about single letter capitalization
|
|
251
|
+
Appoptics = AppOpticsAPM
|
|
252
|
+
AO = AppOpticsAPM
|