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,130 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module ExconConnection
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
::AppOpticsAPM::Util.method_alias(klass, :request, ::Excon::Connection)
|
|
9
|
+
::AppOpticsAPM::Util.method_alias(klass, :requests, ::Excon::Connection)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def appoptics_collect(params)
|
|
15
|
+
kvs = {}
|
|
16
|
+
kvs[:IsService] = 1
|
|
17
|
+
kvs[:RemoteProtocol] = ::AppOpticsAPM::Util.upcase(@data[:scheme])
|
|
18
|
+
kvs[:RemoteHost] = @data[:host]
|
|
19
|
+
|
|
20
|
+
# Conditionally log query args
|
|
21
|
+
if AppOpticsAPM::Config[:excon][:log_args] && @data[:query]
|
|
22
|
+
if @data[:query].is_a?(Hash)
|
|
23
|
+
if RUBY_VERSION >= '1.9.2'
|
|
24
|
+
kvs[:ServiceArg] = "#{@data[:path]}?#{URI.encode_www_form(@data[:query])}"
|
|
25
|
+
else
|
|
26
|
+
# An imperfect solution for the lack of URI.encode_www_form for Ruby versions before
|
|
27
|
+
# 1.9.2. We manually create a query string for reporting purposes only.
|
|
28
|
+
query_arg = ""
|
|
29
|
+
@data[:query].each_pair { |k,v| query_arg += "#{k}=#{v}?"; }
|
|
30
|
+
kvs[:ServiceArg] = "#{@data[:path]}?#{query_arg.chop}"
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
kvs[:ServiceArg] = "#{@data[:path]}?#{@data[:query]}"
|
|
34
|
+
end
|
|
35
|
+
else
|
|
36
|
+
kvs[:ServiceArg] = @data[:path]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# In the case of HTTP pipelining, params could be an array of
|
|
40
|
+
# request hashes.
|
|
41
|
+
if params.is_a?(Array)
|
|
42
|
+
methods = []
|
|
43
|
+
params.each do |p|
|
|
44
|
+
methods << ::AppOpticsAPM::Util.upcase(p[:method])
|
|
45
|
+
end
|
|
46
|
+
kvs[:HTTPMethods] = methods.join(', ')[0..1024]
|
|
47
|
+
kvs[:Pipeline] = true
|
|
48
|
+
else
|
|
49
|
+
kvs[:HTTPMethod] = ::AppOpticsAPM::Util.upcase(params[:method])
|
|
50
|
+
end
|
|
51
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:excon][:collect_backtraces]
|
|
52
|
+
kvs
|
|
53
|
+
rescue => e
|
|
54
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error capturing excon KVs: #{e.message}"
|
|
55
|
+
AppOpticsAPM.logger.debug e.backtrace.join('\n') if ::AppOpticsAPM::Config[:verbose]
|
|
56
|
+
ensure
|
|
57
|
+
return kvs
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
public
|
|
61
|
+
|
|
62
|
+
def requests_with_appoptics(pipeline_params)
|
|
63
|
+
responses = nil
|
|
64
|
+
AppOpticsAPM::API.trace(:excon, appoptics_collect(pipeline_params)) do
|
|
65
|
+
responses = requests_without_appoptics(pipeline_params)
|
|
66
|
+
end
|
|
67
|
+
responses
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def request_with_appoptics(params={}, &block)
|
|
71
|
+
# Avoid cross host tracing for blacklisted domains
|
|
72
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(@data[:hostname])
|
|
73
|
+
|
|
74
|
+
# If we're not tracing, just do a fast return.
|
|
75
|
+
# If making HTTP pipeline requests (ordered batched)
|
|
76
|
+
# then just return as we're tracing from parent
|
|
77
|
+
# <tt>requests</tt>
|
|
78
|
+
if !AppOpticsAPM.tracing? || params[:pipeline]
|
|
79
|
+
@data[:headers]['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid && !blacklisted
|
|
80
|
+
return request_without_appoptics(params, &block)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
response_context = nil
|
|
85
|
+
|
|
86
|
+
kvs = appoptics_collect(params)
|
|
87
|
+
kvs[:Blacklisted] = true if blacklisted
|
|
88
|
+
|
|
89
|
+
AppOpticsAPM::API.log_entry(:excon, kvs)
|
|
90
|
+
kvs.clear
|
|
91
|
+
|
|
92
|
+
req_context = AppOpticsAPM::Context.toString
|
|
93
|
+
@data[:headers]['X-Trace'] = req_context unless blacklisted
|
|
94
|
+
|
|
95
|
+
# The core excon call
|
|
96
|
+
response = request_without_appoptics(params, &block)
|
|
97
|
+
|
|
98
|
+
# excon only passes back a hash (datum) for HTTP pipelining...
|
|
99
|
+
# In that case, we should never arrive here but for the OCD, double check
|
|
100
|
+
# the datatype before trying to extract pertinent info
|
|
101
|
+
if response.is_a?(Excon::Response)
|
|
102
|
+
response_context = response.headers['X-Trace']
|
|
103
|
+
kvs[:HTTPStatus] = response.status
|
|
104
|
+
|
|
105
|
+
# If we get a redirect, report the location header
|
|
106
|
+
if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
|
|
107
|
+
kvs[:Location] = response.headers['Location']
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if response_context && !blacklisted
|
|
111
|
+
AppOpticsAPM::XTrace.continue_service_context(req_context, response_context)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
response
|
|
116
|
+
rescue => e
|
|
117
|
+
AppOpticsAPM::API.log_exception(:excon, e)
|
|
118
|
+
raise e
|
|
119
|
+
ensure
|
|
120
|
+
AppOpticsAPM::API.log_exit(:excon, kvs) unless params[:pipeline]
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
if AppOpticsAPM::Config[:excon][:enabled] && defined?(::Excon)
|
|
128
|
+
::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting excon' if AppOpticsAPM::Config[:verbose]
|
|
129
|
+
::AppOpticsAPM::Util.send_include(::Excon::Connection, ::AppOpticsAPM::Inst::ExconConnection)
|
|
130
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module FaradayConnection
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
::AppOpticsAPM::Util.method_alias(klass, :run_request, ::Faraday::Connection)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run_request_with_appoptics(method, url, body, headers, &block)
|
|
12
|
+
unless AppOpticsAPM.tracing?
|
|
13
|
+
xtrace = AppOpticsAPM::Context.toString
|
|
14
|
+
@headers['X-Trace'] = xtrace if AppOpticsAPM::XTrace.valid?(xtrace) && !AppOpticsAPM::API.blacklisted?(@url_prefix.to_s)
|
|
15
|
+
return run_request_without_appoptics(method, url, body, headers, &block)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
AppOpticsAPM::API.log_entry(:faraday)
|
|
20
|
+
|
|
21
|
+
xtrace = AppOpticsAPM::Context.toString
|
|
22
|
+
@headers['X-Trace'] = xtrace if AppOpticsAPM::XTrace.valid?(xtrace) && !AppOpticsAPM::API.blacklisted?(@url_prefix.to_s)
|
|
23
|
+
result = run_request_without_appoptics(method, url, body, headers, &block)
|
|
24
|
+
|
|
25
|
+
kvs = {}
|
|
26
|
+
kvs[:Middleware] = @builder.handlers
|
|
27
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:faraday][:collect_backtraces]
|
|
28
|
+
|
|
29
|
+
# Only send service KVs if we're not using the Net::HTTP adapter
|
|
30
|
+
# Otherwise, the Net::HTTP instrumentation will send the service KVs
|
|
31
|
+
handle_service = !@builder.handlers.include?(Faraday::Adapter::NetHttp) &&
|
|
32
|
+
!@builder.handlers.include?(Faraday::Adapter::Excon)
|
|
33
|
+
if handle_service
|
|
34
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(@url_prefix.to_s)
|
|
35
|
+
context = AppOpticsAPM::Context.toString
|
|
36
|
+
task_id = AppOpticsAPM::XTrace.task_id(context)
|
|
37
|
+
|
|
38
|
+
# Avoid cross host tracing for blacklisted domains
|
|
39
|
+
# Conditionally add the X-Trace header to the outgoing request
|
|
40
|
+
@headers['X-Trace'] = context unless blacklisted
|
|
41
|
+
|
|
42
|
+
kvs[:IsService] = 1
|
|
43
|
+
kvs[:RemoteProtocol] = (@url_prefix.scheme == 'https') ? 'HTTPS' : 'HTTP'
|
|
44
|
+
kvs[:RemoteHost] = @url_prefix.host
|
|
45
|
+
kvs[:RemotePort] = @url_prefix.port
|
|
46
|
+
kvs[:ServiceArg] = url
|
|
47
|
+
kvs[:HTTPMethod] = method
|
|
48
|
+
kvs[:HTTPStatus] = result.status
|
|
49
|
+
kvs[:Blacklisted] = true if blacklisted
|
|
50
|
+
|
|
51
|
+
# Re-attach net::http edge unless it's blacklisted or if we don't have a
|
|
52
|
+
# valid X-Trace header
|
|
53
|
+
unless blacklisted
|
|
54
|
+
xtrace = result.headers['X-Trace']
|
|
55
|
+
AppOpticsAPM::XTrace.continue_service_context(context, xtrace)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
AppOpticsAPM::API.log(:faraday, :info, kvs)
|
|
60
|
+
result
|
|
61
|
+
rescue => e
|
|
62
|
+
AppOpticsAPM::API.log_exception(:faraday, e)
|
|
63
|
+
raise e
|
|
64
|
+
ensure
|
|
65
|
+
AppOpticsAPM::API.log_exit(:faraday)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if AppOpticsAPM::Config[:faraday][:enabled]
|
|
73
|
+
if defined?(::Faraday)
|
|
74
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting faraday' if AppOpticsAPM::Config[:verbose]
|
|
75
|
+
::AppOpticsAPM::Util.send_include(::Faraday::Connection, ::AppOpticsAPM::Inst::FaradayConnection)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
require 'net/http'
|
|
5
|
+
|
|
6
|
+
if AppOpticsAPM::Config[:nethttp][:enabled]
|
|
7
|
+
|
|
8
|
+
Net::HTTP.class_eval do
|
|
9
|
+
def request_with_appoptics(*args, &block)
|
|
10
|
+
# Avoid cross host tracing for blacklisted domains
|
|
11
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(addr_port)
|
|
12
|
+
|
|
13
|
+
# If we're not tracing, just do a fast return. Since
|
|
14
|
+
# net/http.request calls itself, only trace
|
|
15
|
+
# once the http session has been started.
|
|
16
|
+
if !AppOpticsAPM.tracing? || !started?
|
|
17
|
+
unless blacklisted
|
|
18
|
+
xtrace = AppOpticsAPM::Context.toString
|
|
19
|
+
args[0]['X-Trace'] = xtrace if AppOpticsAPM::XTrace.valid?(xtrace)
|
|
20
|
+
end
|
|
21
|
+
return request_without_appoptics(*args, &block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
AppOpticsAPM::API.trace(:'net-http') do
|
|
25
|
+
opts = {}
|
|
26
|
+
context = AppOpticsAPM::Context.toString
|
|
27
|
+
task_id = AppOpticsAPM::XTrace.task_id(context)
|
|
28
|
+
|
|
29
|
+
# Collect KVs to report in the info event
|
|
30
|
+
if args.length && args[0]
|
|
31
|
+
req = args[0]
|
|
32
|
+
|
|
33
|
+
opts[:IsService] = 1
|
|
34
|
+
opts[:RemoteProtocol] = use_ssl? ? :HTTPS : :HTTP
|
|
35
|
+
opts[:RemoteHost] = addr_port
|
|
36
|
+
|
|
37
|
+
# Conditionally log query params
|
|
38
|
+
if AppOpticsAPM::Config[:nethttp][:log_args]
|
|
39
|
+
opts[:ServiceArg] = req.path
|
|
40
|
+
else
|
|
41
|
+
opts[:ServiceArg] = req.path.split('?').first
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
opts[:HTTPMethod] = req.method
|
|
45
|
+
opts[:Blacklisted] = true if blacklisted
|
|
46
|
+
opts[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:nethttp][:collect_backtraces]
|
|
47
|
+
|
|
48
|
+
req['X-Trace'] = context unless blacklisted
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
begin
|
|
52
|
+
# The actual net::http call
|
|
53
|
+
resp = request_without_appoptics(*args, &block)
|
|
54
|
+
|
|
55
|
+
# Re-attach net::http edge unless blacklisted and is a valid X-Trace ID
|
|
56
|
+
unless blacklisted
|
|
57
|
+
xtrace = resp.get_fields('X-Trace')
|
|
58
|
+
xtrace = xtrace[0] if xtrace && xtrace.is_a?(Array)
|
|
59
|
+
|
|
60
|
+
AppOpticsAPM::XTrace.continue_service_context(context, xtrace)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
opts[:HTTPStatus] = resp.code
|
|
64
|
+
|
|
65
|
+
# If we get a redirect, report the location header
|
|
66
|
+
if ((300..308).to_a.include? resp.code.to_i) && resp.header["Location"]
|
|
67
|
+
opts[:Location] = resp.header["Location"]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
next resp
|
|
71
|
+
ensure
|
|
72
|
+
# Log the info event with the KVs in opts
|
|
73
|
+
AppOpticsAPM::API.log(:'net-http', :info, opts)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
alias request_without_appoptics request
|
|
79
|
+
alias request request_with_appoptics
|
|
80
|
+
|
|
81
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting net/http' if AppOpticsAPM::Config[:verbose]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module HTTPClient
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
::AppOpticsAPM::Util.method_alias(klass, :do_request, ::HTTPClient)
|
|
9
|
+
::AppOpticsAPM::Util.method_alias(klass, :do_request_async, ::HTTPClient)
|
|
10
|
+
::AppOpticsAPM::Util.method_alias(klass, :do_get_stream, ::HTTPClient)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def appoptics_collect(method, uri, query = nil)
|
|
14
|
+
kvs = {}
|
|
15
|
+
kvs[:IsService] = 1
|
|
16
|
+
|
|
17
|
+
# Conditionally log URL query params
|
|
18
|
+
# Because of the hook points, the query arg can come in under <tt>query</tt>
|
|
19
|
+
# or as a part of <tt>uri</tt> (not both). Here we handle both cases.
|
|
20
|
+
if AppOpticsAPM::Config[:httpclient][:log_args]
|
|
21
|
+
if query
|
|
22
|
+
kvs[:RemoteURL] = uri.to_s + '?' + AppOpticsAPM::Util.to_query(query)
|
|
23
|
+
else
|
|
24
|
+
kvs[:RemoteURL] = uri.to_s
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
kvs[:RemoteURL] = uri.to_s.split('?').first
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
kvs[:RemoteProtocol] = uri.scheme.upcase
|
|
31
|
+
kvs[:RemoteHost] = "#{uri.host}:#{uri.port}"
|
|
32
|
+
kvs[:ServiceArg] = "/?#{uri.query}"
|
|
33
|
+
kvs[:HTTPMethod] = ::AppOpticsAPM::Util.upcase(method)
|
|
34
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:httpclient][:collect_backtraces]
|
|
35
|
+
kvs
|
|
36
|
+
rescue => e
|
|
37
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error capturing httpclient KVs: #{e.message}"
|
|
38
|
+
AppOpticsAPM.logger.debug e.backtrace.join('\n') if ::AppOpticsAPM::Config[:verbose]
|
|
39
|
+
ensure
|
|
40
|
+
return kvs
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def do_request_with_appoptics(method, uri, query, body, header, &block)
|
|
44
|
+
# Avoid cross host tracing for blacklisted domains
|
|
45
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(uri.hostname)
|
|
46
|
+
|
|
47
|
+
# If we're not tracing, just do a fast return.
|
|
48
|
+
unless AppOpticsAPM.tracing?
|
|
49
|
+
add_xtrace_header(header) unless blacklisted
|
|
50
|
+
return do_request_without_appoptics(method, uri, query, body, header, &block)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
begin
|
|
54
|
+
req_context = nil
|
|
55
|
+
response_context = nil
|
|
56
|
+
|
|
57
|
+
kvs = appoptics_collect(method, uri, query)
|
|
58
|
+
kvs[:Blacklisted] = true if blacklisted
|
|
59
|
+
|
|
60
|
+
AppOpticsAPM::API.log_entry(:httpclient, kvs)
|
|
61
|
+
kvs.clear
|
|
62
|
+
|
|
63
|
+
req_context = add_xtrace_header(header) unless blacklisted
|
|
64
|
+
|
|
65
|
+
# The core httpclient call
|
|
66
|
+
response = do_request_without_appoptics(method, uri, query, body, header, &block)
|
|
67
|
+
|
|
68
|
+
response_context = response.headers['X-Trace']
|
|
69
|
+
kvs[:HTTPStatus] = response.status_code
|
|
70
|
+
|
|
71
|
+
# If we get a redirect, report the location header
|
|
72
|
+
if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
|
|
73
|
+
kvs[:Location] = response.headers['Location']
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if response_context && !blacklisted
|
|
77
|
+
AppOpticsAPM::XTrace.continue_service_context(req_context, response_context)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
response
|
|
81
|
+
rescue => e
|
|
82
|
+
AppOpticsAPM::API.log_exception(:httpclient, e)
|
|
83
|
+
raise e
|
|
84
|
+
ensure
|
|
85
|
+
AppOpticsAPM::API.log_exit(:httpclient, kvs)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def do_request_async_with_appoptics(method, uri, query, body, header)
|
|
90
|
+
add_xtrace_header(header)
|
|
91
|
+
do_request_async_without_appoptics(method, uri, query, body, header)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def do_get_stream_with_appoptics(req, proxy, conn)
|
|
95
|
+
AppOpticsAPM::Context.fromString(req.header['X-Trace'].first) unless req.header['X-Trace'].empty?
|
|
96
|
+
# Avoid cross host tracing for blacklisted domains
|
|
97
|
+
uri = req.http_header.request_uri
|
|
98
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(uri.hostname)
|
|
99
|
+
|
|
100
|
+
unless AppOpticsAPM.tracing?
|
|
101
|
+
req.header.delete('X-Trace') if blacklisted
|
|
102
|
+
return do_get_stream_without_appoptics(req, proxy, conn)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
begin
|
|
106
|
+
response = nil
|
|
107
|
+
req_context = nil
|
|
108
|
+
method = req.http_header.request_method
|
|
109
|
+
|
|
110
|
+
kvs = appoptics_collect(method, uri)
|
|
111
|
+
kvs[:Blacklisted] = true if blacklisted
|
|
112
|
+
kvs[:Async] = 1
|
|
113
|
+
|
|
114
|
+
AppOpticsAPM::API.log_entry(:httpclient, kvs)
|
|
115
|
+
kvs.clear
|
|
116
|
+
|
|
117
|
+
blacklisted ? req.header.delete('X-Trace') : req_context = add_xtrace_header(req.header)
|
|
118
|
+
|
|
119
|
+
# The core httpclient call
|
|
120
|
+
result = do_get_stream_without_appoptics(req, proxy, conn)
|
|
121
|
+
|
|
122
|
+
# Older HTTPClient < 2.6.0 returns HTTPClient::Connection
|
|
123
|
+
if result.is_a?(::HTTP::Message)
|
|
124
|
+
response = result
|
|
125
|
+
else
|
|
126
|
+
response = conn.pop
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
response_context = response.headers['X-Trace']
|
|
130
|
+
kvs[:HTTPStatus] = response.status_code
|
|
131
|
+
|
|
132
|
+
# If we get a redirect, report the location header
|
|
133
|
+
if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
|
|
134
|
+
kvs[:Location] = response.headers['Location']
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
if response_context && !blacklisted
|
|
138
|
+
AppOpticsAPM::XTrace.continue_service_context(req_context, response_context)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Older HTTPClient < 2.6.0 returns HTTPClient::Connection
|
|
142
|
+
conn.push response if result.is_a?(::HTTPClient::Connection)
|
|
143
|
+
result
|
|
144
|
+
rescue => e
|
|
145
|
+
AppOpticsAPM::API.log_exception(:httpclient, e)
|
|
146
|
+
raise e
|
|
147
|
+
ensure
|
|
148
|
+
# AppOpticsAPM::API.log_exit('httpclient', kvs.merge('Async' => 1))
|
|
149
|
+
AppOpticsAPM::API.log_exit(:httpclient, kvs)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def add_xtrace_header(headers)
|
|
156
|
+
req_context = AppOpticsAPM::Context.toString
|
|
157
|
+
return nil unless AppOpticsAPM::XTrace.valid?(req_context)
|
|
158
|
+
# Be aware of various ways to call/use httpclient
|
|
159
|
+
if headers.is_a?(Array)
|
|
160
|
+
headers.delete_if { |kv| kv[0] == 'X-Trace' }
|
|
161
|
+
headers.push ['X-Trace', req_context]
|
|
162
|
+
elsif headers.is_a?(Hash)
|
|
163
|
+
headers['X-Trace'] = req_context
|
|
164
|
+
elsif headers.is_a? HTTP::Message::Headers
|
|
165
|
+
headers.set('X-Trace', req_context)
|
|
166
|
+
end
|
|
167
|
+
req_context
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
if AppOpticsAPM::Config[:httpclient][:enabled] && defined?(::HTTPClient)
|
|
174
|
+
::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting httpclient' if AppOpticsAPM::Config[:verbose]
|
|
175
|
+
::AppOpticsAPM::Util.send_include(::HTTPClient, ::AppOpticsAPM::Inst::HTTPClient)
|
|
176
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module MemCache
|
|
7
|
+
include AppOpticsAPM::API::Memcache
|
|
8
|
+
|
|
9
|
+
def self.included(cls)
|
|
10
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting memcache' if AppOpticsAPM::Config[:verbose]
|
|
11
|
+
|
|
12
|
+
cls.class_eval do
|
|
13
|
+
MEMCACHE_OPS.reject { |m| !method_defined?(m) }.each do |m|
|
|
14
|
+
|
|
15
|
+
define_method("#{m}_with_appoptics") do |*args|
|
|
16
|
+
report_kvs = { :KVOp => m }
|
|
17
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcache][:collect_backtraces]
|
|
18
|
+
|
|
19
|
+
if AppOpticsAPM.tracing?
|
|
20
|
+
AppOpticsAPM::API.trace(:memcache, report_kvs) do
|
|
21
|
+
send("#{m}_without_appoptics", *args)
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
send("#{m}_without_appoptics", *args)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class_eval "alias #{m}_without_appoptics #{m}"
|
|
29
|
+
class_eval "alias #{m} #{m}_with_appoptics"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
[:request_setup, :cache_get, :get_multi].each do |m|
|
|
34
|
+
if ::MemCache.method_defined? :request_setup
|
|
35
|
+
cls.class_eval "alias #{m}_without_appoptics #{m}"
|
|
36
|
+
cls.class_eval "alias #{m} #{m}_with_appoptics"
|
|
37
|
+
elsif AppOpticsAPM::Config[:verbose]
|
|
38
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/loading] Couldn't properly instrument Memcache: #{m}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_multi_with_appoptics(*args)
|
|
44
|
+
return get_multi_without_appoptics(args) unless AppOpticsAPM.tracing?
|
|
45
|
+
|
|
46
|
+
info_kvs = {}
|
|
47
|
+
|
|
48
|
+
begin
|
|
49
|
+
info_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcache][:collect_backtraces]
|
|
50
|
+
|
|
51
|
+
if args.last.is_a?(Hash) || args.last.nil?
|
|
52
|
+
info_kvs[:KVKeyCount] = args.flatten.length - 1
|
|
53
|
+
else
|
|
54
|
+
info_kvs[:KVKeyCount] = args.flatten.length
|
|
55
|
+
end
|
|
56
|
+
rescue StandardError => e
|
|
57
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error collecting info keys: #{e.message}"
|
|
58
|
+
AppOpticsAPM.logger.debug e.backtrace
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
AppOpticsAPM::API.trace(:memcache, { :KVOp => :get_multi }, :get_multi) do
|
|
62
|
+
values = get_multi_without_appoptics(args)
|
|
63
|
+
|
|
64
|
+
info_kvs[:KVHitCount] = values.length
|
|
65
|
+
AppOpticsAPM::API.log(:memcache, :info, info_kvs)
|
|
66
|
+
|
|
67
|
+
values
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def request_setup_with_appoptics(*args)
|
|
72
|
+
if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:get_multi)
|
|
73
|
+
server, cache_key = request_setup_without_appoptics(*args)
|
|
74
|
+
|
|
75
|
+
info_kvs = { :KVKey => cache_key, :RemoteHost => server.host }
|
|
76
|
+
info_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcache][:collect_backtraces]
|
|
77
|
+
AppOpticsAPM::API.log(:memcache, :info, info_kvs)
|
|
78
|
+
|
|
79
|
+
[server, cache_key]
|
|
80
|
+
else
|
|
81
|
+
request_setup_without_appoptics(*args)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def cache_get_with_appoptics(server, cache_key)
|
|
86
|
+
result = cache_get_without_appoptics(server, cache_key)
|
|
87
|
+
|
|
88
|
+
info_kvs = { :KVHit => memcache_hit?(result) }
|
|
89
|
+
info_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcache][:collect_backtraces]
|
|
90
|
+
AppOpticsAPM::API.log(:memcache, :info, info_kvs)
|
|
91
|
+
|
|
92
|
+
result
|
|
93
|
+
end
|
|
94
|
+
end # module MemCache
|
|
95
|
+
end # module Inst
|
|
96
|
+
end # module AppOpticsAPM
|
|
97
|
+
|
|
98
|
+
if defined?(::MemCache) && AppOpticsAPM::Config[:memcache][:enabled]
|
|
99
|
+
::MemCache.class_eval do
|
|
100
|
+
include AppOpticsAPM::Inst::MemCache
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module Memcached
|
|
7
|
+
include AppOpticsAPM::API::Memcache
|
|
8
|
+
|
|
9
|
+
def self.included(cls)
|
|
10
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting memcached' if AppOpticsAPM::Config[:verbose]
|
|
11
|
+
|
|
12
|
+
cls.class_eval do
|
|
13
|
+
MEMCACHE_OPS.reject { |m| !method_defined?(m) }.each do |m|
|
|
14
|
+
define_method("#{m}_with_appoptics") do |*args|
|
|
15
|
+
opts = { :KVOp => m }
|
|
16
|
+
|
|
17
|
+
if args.length && !args[0].is_a?(Array)
|
|
18
|
+
opts[:KVKey] = args[0].to_s
|
|
19
|
+
rhost = remote_host(args[0].to_s)
|
|
20
|
+
opts[:RemoteHost] = rhost if rhost
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
AppOpticsAPM::API.trace(:memcache, opts) do
|
|
24
|
+
result = send("#{m}_without_appoptics", *args)
|
|
25
|
+
|
|
26
|
+
info_kvs = {}
|
|
27
|
+
info_kvs[:KVHit] = memcache_hit?(result) if m == :get && args.length && args[0].class == String
|
|
28
|
+
info_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcached][:collect_backtraces]
|
|
29
|
+
|
|
30
|
+
AppOpticsAPM::API.log(:memcache, :info, info_kvs) unless info_kvs.empty?
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class_eval "alias #{m}_without_appoptics #{m}"
|
|
36
|
+
class_eval "alias #{m} #{m}_with_appoptics"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end # module Memcached
|
|
42
|
+
|
|
43
|
+
module MemcachedRails
|
|
44
|
+
def self.included(cls)
|
|
45
|
+
cls.class_eval do
|
|
46
|
+
if ::Memcached::Rails.method_defined? :get_multi
|
|
47
|
+
alias get_multi_without_appoptics get_multi
|
|
48
|
+
alias get_multi get_multi_with_appoptics
|
|
49
|
+
elsif AppOpticsAPM::Config[:verbose]
|
|
50
|
+
AppOpticsAPM.logger.warn '[appoptics_apm/loading] Couldn\'t properly instrument Memcached. Partial traces may occur.'
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def get_multi_with_appoptics(keys, raw = false)
|
|
56
|
+
if AppOpticsAPM.tracing?
|
|
57
|
+
layer_kvs = {}
|
|
58
|
+
layer_kvs[:KVOp] = :get_multi
|
|
59
|
+
|
|
60
|
+
AppOpticsAPM::API.trace(:memcache, layer_kvs || {}, :get_multi) do
|
|
61
|
+
begin
|
|
62
|
+
info_kvs = {}
|
|
63
|
+
info_kvs[:KVKeyCount] = keys.flatten.length
|
|
64
|
+
|
|
65
|
+
values = get_multi_without_appoptics(keys, raw)
|
|
66
|
+
|
|
67
|
+
info_kvs[:KVHitCount] = values.length
|
|
68
|
+
info_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcached][:collect_backtraces]
|
|
69
|
+
|
|
70
|
+
AppOpticsAPM::API.log(:memcache, :info, info_kvs)
|
|
71
|
+
rescue
|
|
72
|
+
values = get_multi_without_appoptics(keys, raw)
|
|
73
|
+
end
|
|
74
|
+
values
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
get_multi_without_appoptics(keys, raw)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end # module MemcachedRails
|
|
81
|
+
end # module Inst
|
|
82
|
+
end # module AppOpticsAPM
|
|
83
|
+
|
|
84
|
+
if defined?(::Memcached) && AppOpticsAPM::Config[:memcached][:enabled]
|
|
85
|
+
::Memcached.class_eval do
|
|
86
|
+
include AppOpticsAPM::Inst::Memcached
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if defined?(::Memcached::Rails)
|
|
90
|
+
::Memcached::Rails.class_eval do
|
|
91
|
+
include AppOpticsAPM::Inst::MemcachedRails
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|