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,53 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
class SidekiqClient
|
|
6
|
+
def collect_kvs(args)
|
|
7
|
+
begin
|
|
8
|
+
# Attempt to collect up pertinent info. If we hit something unexpected,
|
|
9
|
+
# keep calm and instrument on.
|
|
10
|
+
|
|
11
|
+
report_kvs = {}
|
|
12
|
+
worker_class, msg, queue, _ = args
|
|
13
|
+
|
|
14
|
+
report_kvs[:Spec] = :pushq
|
|
15
|
+
report_kvs[:Flavor] = :sidekiq
|
|
16
|
+
report_kvs[:Queue] = queue
|
|
17
|
+
report_kvs[:Retry] = msg['retry']
|
|
18
|
+
report_kvs[:JobName] = worker_class
|
|
19
|
+
report_kvs[:MsgID] = msg['jid']
|
|
20
|
+
report_kvs[:Args] = msg['args'].to_s[0..1024] if AppOpticsAPM::Config[:sidekiqclient][:log_args]
|
|
21
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sidekiqclient][:collect_backtraces]
|
|
22
|
+
rescue => e
|
|
23
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/sidekiq] Non-fatal error capturing KVs: #{e.message}"
|
|
24
|
+
end
|
|
25
|
+
report_kvs
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def call(*args)
|
|
29
|
+
# args: 0: worker_class, 1: msg, 2: queue, 3: redis_pool
|
|
30
|
+
if AppOpticsAPM.tracing?
|
|
31
|
+
report_kvs = collect_kvs(args)
|
|
32
|
+
AppOpticsAPM::API.log_entry(:'sidekiq-client', report_kvs)
|
|
33
|
+
args[1]['SourceTrace'] = AppOpticsAPM::Context.toString
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
result = yield
|
|
37
|
+
rescue => e
|
|
38
|
+
AppOpticsAPM::API.log_exception(:'sidekiq-client', e, { :JobID => result['jid'] })
|
|
39
|
+
raise
|
|
40
|
+
ensure
|
|
41
|
+
AppOpticsAPM::API.log_exit(:'sidekiq-client', { :JobID => result['jid'] })
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if defined?(::Sidekiq) && RUBY_VERSION >= '2.0' && AppOpticsAPM::Config[:sidekiqclient][:enabled]
|
|
47
|
+
::Sidekiq.configure_client do |config|
|
|
48
|
+
config.client_middleware do |chain|
|
|
49
|
+
::AppOpticsAPM.logger.info '[appoptics_apm/loading] Adding Sidekiq client middleware' if AppOpticsAPM::Config[:verbose]
|
|
50
|
+
chain.add ::AppOpticsAPM::SidekiqClient
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
class SidekiqWorker
|
|
6
|
+
def collect_kvs(args)
|
|
7
|
+
begin
|
|
8
|
+
# Attempt to collect up pertinent info. If we hit something unexpected,
|
|
9
|
+
# keep calm and instrument on.
|
|
10
|
+
report_kvs = {}
|
|
11
|
+
worker, msg, queue = args
|
|
12
|
+
|
|
13
|
+
# Background Job Spec KVs
|
|
14
|
+
report_kvs[:Spec] = :job
|
|
15
|
+
report_kvs[:Flavor] = :sidekiq
|
|
16
|
+
report_kvs[:Queue] = queue
|
|
17
|
+
report_kvs[:Retry] = msg['retry']
|
|
18
|
+
report_kvs[:JobName] = worker.class.to_s
|
|
19
|
+
report_kvs[:MsgID] = msg['jid']
|
|
20
|
+
report_kvs[:Args] = msg['args'].to_s[0..1024] if AppOpticsAPM::Config[:sidekiqworker][:log_args]
|
|
21
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sidekiqworker][:collect_backtraces]
|
|
22
|
+
|
|
23
|
+
# Webserver Spec KVs
|
|
24
|
+
report_kvs[:'HTTP-Host'] = Socket.gethostname
|
|
25
|
+
report_kvs[:Controller] = "Sidekiq_#{queue}"
|
|
26
|
+
report_kvs[:Action] = msg['class']
|
|
27
|
+
report_kvs[:URL] = "/sidekiq/#{queue}/#{msg['class']}"
|
|
28
|
+
rescue => e
|
|
29
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/sidekiq] Non-fatal error capturing KVs: #{e.message}"
|
|
30
|
+
end
|
|
31
|
+
report_kvs
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def call(*args)
|
|
35
|
+
# args: 0: worker, 1: msg, 2: queue
|
|
36
|
+
report_kvs = collect_kvs(args)
|
|
37
|
+
|
|
38
|
+
# Something is happening across Celluloid threads where liboboe settings
|
|
39
|
+
# are being lost. So we re-set the tracing mode to assure
|
|
40
|
+
# we sample as desired. Setting the tracing mode will re-update
|
|
41
|
+
# the liboboe settings.
|
|
42
|
+
AppOpticsAPM::Config[:tracing_mode] = AppOpticsAPM::Config[:tracing_mode]
|
|
43
|
+
|
|
44
|
+
# Continue the trace from the enqueue side?
|
|
45
|
+
if args[1].is_a?(Hash) && AppOpticsAPM::XTrace.valid?(args[1]['SourceTrace'])
|
|
46
|
+
report_kvs[:SourceTrace] = args[1]['SourceTrace']
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
result = AppOpticsAPM::API.start_trace(:'sidekiq-worker', nil, report_kvs) do
|
|
50
|
+
yield
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
result[0]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if defined?(::Sidekiq) && RUBY_VERSION >= '2.0' && AppOpticsAPM::Config[:sidekiqworker][:enabled]
|
|
59
|
+
::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting sidekiq' if AppOpticsAPM::Config[:verbose]
|
|
60
|
+
|
|
61
|
+
::Sidekiq.configure_server do |config|
|
|
62
|
+
config.server_middleware do |chain|
|
|
63
|
+
::AppOpticsAPM.logger.info '[appoptics_apm/loading] Adding Sidekiq worker middleware' if AppOpticsAPM::Config[:verbose]
|
|
64
|
+
chain.add ::AppOpticsAPM::SidekiqWorker
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module Cassandra
|
|
7
|
+
def extract_trace_details(op, column_family, keys, args, options = {})
|
|
8
|
+
report_kvs = {}
|
|
9
|
+
|
|
10
|
+
begin
|
|
11
|
+
report_kvs[:Op] = op.to_s
|
|
12
|
+
report_kvs[:Cf] = column_family.to_s if column_family
|
|
13
|
+
report_kvs[:Key] = keys.inspect if keys
|
|
14
|
+
|
|
15
|
+
# Open issue - how to handle multiple Cassandra servers
|
|
16
|
+
report_kvs[:RemoteHost], report_kvs[:RemotePort] = @servers.first.split(':')
|
|
17
|
+
|
|
18
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:cassandra][:collect_backtraces]
|
|
19
|
+
|
|
20
|
+
if options.empty? && args.is_a?(Array)
|
|
21
|
+
options = args.last if args.last.is_a?(Hash)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
unless options.empty?
|
|
25
|
+
[:start_key, :finish_key, :key_count, :batch_size, :columns, :count, :start,
|
|
26
|
+
:stop, :finish, :finished, :reversed, :consistency, :ttl].each do |k|
|
|
27
|
+
report_kvs[k.to_s.capitalize] = options[k] if options.key?(k)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if op == :get_indexed_slices
|
|
31
|
+
index_clause = columns_and_options[:index_clause] || {}
|
|
32
|
+
unless index_clause.empty?
|
|
33
|
+
[:column_name, :value, :comparison].each do |k|
|
|
34
|
+
report_kvs[k.to_s.capitalize] = index_clause[k] if index_clause.key?(k)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
rescue => e
|
|
40
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
report_kvs
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def insert_with_appoptics(column_family, key, hash, options = {})
|
|
47
|
+
return insert_without_appoptics(column_family, key, hash, options = {}) unless AppOpticsAPM.tracing?
|
|
48
|
+
|
|
49
|
+
report_kvs = extract_trace_details(:insert, column_family, key, hash, options)
|
|
50
|
+
|
|
51
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
52
|
+
insert_without_appoptics(column_family, key, hash, options = {})
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def remove_with_appoptics(column_family, key, *columns_and_options)
|
|
57
|
+
args = [column_family, key] + columns_and_options
|
|
58
|
+
|
|
59
|
+
return send :remove_without_appoptics, *args unless AppOpticsAPM.tracing?
|
|
60
|
+
|
|
61
|
+
report_kvs = extract_trace_details(:remove, column_family, key, columns_and_options)
|
|
62
|
+
|
|
63
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
64
|
+
send :remove_without_appoptics, *args
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def count_columns_with_appoptics(column_family, key, *columns_and_options)
|
|
69
|
+
args = [column_family, key] + columns_and_options
|
|
70
|
+
|
|
71
|
+
return send :count_columns_without_appoptics, *args unless AppOpticsAPM.tracing?
|
|
72
|
+
|
|
73
|
+
report_kvs = extract_trace_details(:count_columns, column_family, key, columns_and_options)
|
|
74
|
+
|
|
75
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
76
|
+
send :count_columns_without_appoptics, *args
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def get_columns_with_appoptics(column_family, key, *columns_and_options)
|
|
81
|
+
args = [column_family, key] + columns_and_options
|
|
82
|
+
|
|
83
|
+
if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:multi_get_columns)
|
|
84
|
+
report_kvs = extract_trace_details(:get_columns, column_family, key, columns_and_options)
|
|
85
|
+
|
|
86
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
87
|
+
send :get_columns_without_appoptics, *args
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
send :get_columns_without_appoptics, *args
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def multi_get_columns_with_appoptics(column_family, key, *columns_and_options)
|
|
95
|
+
args = [column_family, key] + columns_and_options
|
|
96
|
+
|
|
97
|
+
return send :multi_get_columns_without_appoptics, *args unless AppOpticsAPM.tracing?
|
|
98
|
+
|
|
99
|
+
report_kvs = extract_trace_details(:multi_get_columns, column_family, key, columns_and_options)
|
|
100
|
+
|
|
101
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs, :multi_get_columns) do
|
|
102
|
+
send :multi_get_columns_without_appoptics, *args
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def get_with_appoptics(column_family, key, *columns_and_options)
|
|
107
|
+
args = [column_family, key] + columns_and_options
|
|
108
|
+
|
|
109
|
+
return send :get_without_appoptics, *args unless AppOpticsAPM.tracing?
|
|
110
|
+
|
|
111
|
+
report_kvs = extract_trace_details(:get, column_family, key, columns_and_options)
|
|
112
|
+
|
|
113
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs, :get) do
|
|
114
|
+
send :get_without_appoptics, *args
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def multi_get_with_appoptics(column_family, key, *columns_and_options)
|
|
119
|
+
args = [column_family, key] + columns_and_options
|
|
120
|
+
|
|
121
|
+
if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:get)
|
|
122
|
+
report_kvs = extract_trace_details(:multi_get, column_family, key, columns_and_options)
|
|
123
|
+
|
|
124
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
125
|
+
send :multi_get_without_appoptics, *args
|
|
126
|
+
end
|
|
127
|
+
else
|
|
128
|
+
send :multi_get_without_appoptics, *args
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def exists_with_appoptics?(column_family, key, *columns_and_options)
|
|
133
|
+
args = [column_family, key] + columns_and_options
|
|
134
|
+
|
|
135
|
+
return send :exists_without_appoptics?, *args unless AppOpticsAPM.tracing?
|
|
136
|
+
|
|
137
|
+
report_kvs = extract_trace_details(:exists?, column_family, key, columns_and_options)
|
|
138
|
+
|
|
139
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
140
|
+
send :exists_without_appoptics?, *args
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def get_range_single_with_appoptics(column_family, options = {})
|
|
145
|
+
if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:get_range_batch)
|
|
146
|
+
report_kvs = extract_trace_details(:get_range_single, column_family, nil, nil)
|
|
147
|
+
|
|
148
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
149
|
+
get_range_single_without_appoptics(column_family, options)
|
|
150
|
+
end
|
|
151
|
+
else
|
|
152
|
+
get_range_single_without_appoptics(column_family, options)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def get_range_batch_with_appoptics(column_family, options = {})
|
|
157
|
+
return get_range_batch_without_appoptics(column_family, options) unless AppOpticsAPM.tracing?
|
|
158
|
+
|
|
159
|
+
report_kvs = extract_trace_details(:get_range_batch, column_family, nil, nil)
|
|
160
|
+
|
|
161
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs, :get_range_batch) do
|
|
162
|
+
get_range_batch_without_appoptics(column_family, options)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def get_indexed_slices_with_appoptics(column_family, index_clause, *columns_and_options)
|
|
167
|
+
args = [column_family, index_clause] + columns_and_options
|
|
168
|
+
|
|
169
|
+
return send :get_indexed_slices_without_appoptics, *args unless AppOpticsAPM.tracing?
|
|
170
|
+
|
|
171
|
+
report_kvs = extract_trace_details(:get_indexed_slices, column_family, nil, columns_and_options)
|
|
172
|
+
|
|
173
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
174
|
+
send :get_indexed_slices_without_appoptics, *args
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def create_index_with_appoptics(keyspace, column_family, column_name, validation_class)
|
|
179
|
+
unless AppOpticsAPM.tracing?
|
|
180
|
+
return create_index_without_appoptics(keyspace, column_family, column_name, validation_class)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
report_kvs = extract_trace_details(:create_index, column_family, nil, nil)
|
|
184
|
+
begin
|
|
185
|
+
report_kvs[:Keyspace] = keyspace.to_s
|
|
186
|
+
report_kvs[:Column_name] = column_name.to_s
|
|
187
|
+
report_kvs[:Validation_class] = validation_class.to_s
|
|
188
|
+
rescue => e
|
|
189
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
193
|
+
create_index_without_appoptics(keyspace, column_family, column_name, validation_class)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def drop_index_with_appoptics(keyspace, column_family, column_name)
|
|
198
|
+
return drop_index_without_appoptics(keyspace, column_family, column_name) unless AppOpticsAPM.tracing?
|
|
199
|
+
|
|
200
|
+
report_kvs = extract_trace_details(:drop_index, column_family, nil, nil)
|
|
201
|
+
begin
|
|
202
|
+
report_kvs[:Keyspace] = keyspace.to_s
|
|
203
|
+
report_kvs[:Column_name] = column_name.to_s
|
|
204
|
+
rescue => e
|
|
205
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
209
|
+
drop_index_without_appoptics(keyspace, column_family, column_name)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def add_column_family_with_appoptics(cf_def)
|
|
214
|
+
return add_column_family_without_appoptics(cf_def) unless AppOpticsAPM.tracing?
|
|
215
|
+
|
|
216
|
+
report_kvs = extract_trace_details(:add_column_family, nil, nil, nil)
|
|
217
|
+
begin
|
|
218
|
+
report_kvs[:Cf] = cf_def[:name] if cf_def.is_a?(Hash) && cf_def.key?(:name)
|
|
219
|
+
rescue => e
|
|
220
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
224
|
+
add_column_family_without_appoptics(cf_def)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def drop_column_family_with_appoptics(column_family)
|
|
229
|
+
return drop_column_family_without_appoptics(column_family) unless AppOpticsAPM.tracing?
|
|
230
|
+
|
|
231
|
+
report_kvs = extract_trace_details(:drop_column_family, column_family, nil, nil)
|
|
232
|
+
|
|
233
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
234
|
+
drop_column_family_without_appoptics(column_family)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def add_keyspace_with_appoptics(ks_def)
|
|
239
|
+
return add_keyspace_without_appoptics(ks_def) unless AppOpticsAPM.tracing?
|
|
240
|
+
|
|
241
|
+
report_kvs = extract_trace_details(:add_keyspace, nil, nil, nil)
|
|
242
|
+
report_kvs[:Name] = ks_def.name rescue ''
|
|
243
|
+
|
|
244
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
245
|
+
add_keyspace_without_appoptics(ks_def)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def drop_keyspace_with_appoptics(keyspace)
|
|
250
|
+
return drop_keyspace_without_appoptics(keyspace) unless AppOpticsAPM.tracing?
|
|
251
|
+
|
|
252
|
+
report_kvs = extract_trace_details(:drop_keyspace, nil, nil, nil)
|
|
253
|
+
report_kvs[:Name] = keyspace.to_s rescue ''
|
|
254
|
+
|
|
255
|
+
AppOpticsAPM::API.trace(:cassandra, report_kvs) do
|
|
256
|
+
drop_keyspace_without_appoptics(keyspace)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# There are two main Cassandra clients for Ruby. This one from Twitter
|
|
264
|
+
# and the other from datastax. This one defined ::Cassandra as a class
|
|
265
|
+
# and datastax defines it as a module. We use this to detect
|
|
266
|
+
# and differentiate between the client in use.
|
|
267
|
+
|
|
268
|
+
if defined?(::Cassandra) && ::Cassandra.is_a?(Class) && AppOpticsAPM::Config[:cassandra][:enabled]
|
|
269
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting cassandra' if AppOpticsAPM::Config[:verbose]
|
|
270
|
+
|
|
271
|
+
class ::Cassandra
|
|
272
|
+
include AppOpticsAPM::Inst::Cassandra
|
|
273
|
+
|
|
274
|
+
[:insert, :remove, :count_columns, :get_columns, :multi_get_columns, :get,
|
|
275
|
+
:multi_get, :get_range_single, :get_range_batch, :get_indexed_slices,
|
|
276
|
+
:create_index, :drop_index, :add_column_family, :drop_column_family,
|
|
277
|
+
:add_keyspace, :drop_keyspace].each do |m|
|
|
278
|
+
if method_defined?(m)
|
|
279
|
+
class_eval "alias #{m}_without_appoptics #{m}"
|
|
280
|
+
class_eval "alias #{m} #{m}_with_appoptics"
|
|
281
|
+
else AppOpticsAPM.logger.warn "[appoptics_apm/loading] Couldn't properly instrument Cassandra (#{m}). Partial traces may occur."
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Special case handler for question mark methods
|
|
286
|
+
if method_defined?(:exists?)
|
|
287
|
+
alias exists_without_appoptics? exists?
|
|
288
|
+
alias exists? exists_with_appoptics?
|
|
289
|
+
else AppOpticsAPM.logger.warn '[appoptics_apm/loading] Couldn\'t properly instrument Cassandra (exists?). Partial traces may occur.'
|
|
290
|
+
end
|
|
291
|
+
end # class Cassandra
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module TyphoeusRequestOps
|
|
7
|
+
|
|
8
|
+
def self.included(klass)
|
|
9
|
+
::AppOpticsAPM::Util.method_alias(klass, :run, ::Typhoeus::Request::Operations)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run_with_appoptics
|
|
13
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(url)
|
|
14
|
+
unless AppOpticsAPM.tracing?
|
|
15
|
+
context = AppOpticsAPM::Context.toString
|
|
16
|
+
options[:headers]['X-Trace'] = context if AppOpticsAPM::XTrace.valid?(context) && !blacklisted
|
|
17
|
+
return run_without_appoptics
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
AppOpticsAPM::API.log_entry(:typhoeus)
|
|
22
|
+
|
|
23
|
+
# Prepare X-Trace header handling
|
|
24
|
+
context = AppOpticsAPM::Context.toString
|
|
25
|
+
options[:headers]['X-Trace'] = context unless blacklisted
|
|
26
|
+
|
|
27
|
+
response = run_without_appoptics
|
|
28
|
+
|
|
29
|
+
if response.code == 0
|
|
30
|
+
AppOpticsAPM::API.log(:typhoeus, :error, { :ErrorClass => response.return_code,
|
|
31
|
+
:ErrorMsg => response.return_message })
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
kvs = {}
|
|
35
|
+
kvs[:IsService] = 1
|
|
36
|
+
kvs[:HTTPStatus] = response.code
|
|
37
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:typhoeus][:collect_backtraces]
|
|
38
|
+
|
|
39
|
+
uri = URI(response.effective_url)
|
|
40
|
+
|
|
41
|
+
# Conditionally log query params
|
|
42
|
+
if AppOpticsAPM::Config[:typhoeus][:log_args]
|
|
43
|
+
kvs[:RemoteURL] = uri.to_s
|
|
44
|
+
else
|
|
45
|
+
kvs[:RemoteURL] = uri.to_s.split('?').first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
kvs[:HTTPMethod] = ::AppOpticsAPM::Util.upcase(options[:method])
|
|
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 = response.headers['X-Trace']
|
|
55
|
+
AppOpticsAPM::XTrace.continue_service_context(context, xtrace)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
AppOpticsAPM::API.log_info(:typhoeus, kvs)
|
|
59
|
+
response
|
|
60
|
+
rescue => e
|
|
61
|
+
AppOpticsAPM::API.log_exception(:typhoeus, e)
|
|
62
|
+
raise e
|
|
63
|
+
ensure
|
|
64
|
+
AppOpticsAPM::API.log_exit(:typhoeus)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
module TyphoeusHydraRunnable
|
|
70
|
+
def self.included(klass)
|
|
71
|
+
::AppOpticsAPM::Util.method_alias(klass, :run, ::Typhoeus::Hydra)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def run_with_appoptics
|
|
75
|
+
unless AppOpticsAPM.tracing?
|
|
76
|
+
context = AppOpticsAPM::Context.toString
|
|
77
|
+
queued_requests.map do |request|
|
|
78
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(request.base_url)
|
|
79
|
+
request.options[:headers]['X-Trace'] = context if AppOpticsAPM::XTrace.valid?(context) && !blacklisted
|
|
80
|
+
end
|
|
81
|
+
return run_without_appoptics
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
kvs = {}
|
|
85
|
+
|
|
86
|
+
kvs[:queued_requests] = queued_requests.count
|
|
87
|
+
kvs[:max_concurrency] = max_concurrency
|
|
88
|
+
kvs[:Async] = 1
|
|
89
|
+
|
|
90
|
+
# FIXME: Until we figure out a strategy to deal with libcurl internal
|
|
91
|
+
# threading and Ethon's use of easy handles, here we just do a simple
|
|
92
|
+
# trace of the hydra run.
|
|
93
|
+
AppOpticsAPM::API.trace(:typhoeus_hydra, kvs) do
|
|
94
|
+
queued_requests.map do |request|
|
|
95
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(request.base_url)
|
|
96
|
+
request.options[:headers]['X-Trace'] = AppOpticsAPM::Context.toString unless blacklisted
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
run_without_appoptics
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
if AppOpticsAPM::Config[:typhoeus][:enabled]
|
|
108
|
+
if defined?(::Typhoeus)
|
|
109
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting typhoeus' if AppOpticsAPM::Config[:verbose]
|
|
110
|
+
::AppOpticsAPM::Util.send_include(::Typhoeus::Request::Operations, ::AppOpticsAPM::Inst::TyphoeusRequestOps)
|
|
111
|
+
::AppOpticsAPM::Util.send_include(::Typhoeus::Hydra, ::AppOpticsAPM::Inst::TyphoeusHydraRunnable)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
##
|
|
6
|
+
# The Inst module holds all of the instrumentation extensions for various
|
|
7
|
+
# libraries suchs as Redis, Dalli and Resque.
|
|
8
|
+
module Inst
|
|
9
|
+
def self.load_instrumentation
|
|
10
|
+
# Load the general instrumentation
|
|
11
|
+
pattern = File.join(File.dirname(__FILE__), 'inst', '*.rb')
|
|
12
|
+
Dir.glob(pattern) do |f|
|
|
13
|
+
begin
|
|
14
|
+
require f
|
|
15
|
+
rescue => e
|
|
16
|
+
AppOpticsAPM.logger.error "[appoptics_apm/loading] Error loading instrumentation file '#{f}' : #{e}"
|
|
17
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/loading] #{e.backtrace.first}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Provides the methods necessary for method profiling. Profiling
|
|
6
|
+
# results are sent to the AppOptics dashboard.
|
|
7
|
+
#
|
|
8
|
+
# Example usage:
|
|
9
|
+
# class MyApp
|
|
10
|
+
# include AppOpticsAPMMethodProfiling
|
|
11
|
+
#
|
|
12
|
+
# def process_request()
|
|
13
|
+
# # The hard work
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# # call syntax: profile_method <method>, <profile_name>
|
|
17
|
+
# profile_method :process_request, 'request_processor'
|
|
18
|
+
# end
|
|
19
|
+
module AppOpticsAPMMethodProfiling
|
|
20
|
+
def self.included(klass)
|
|
21
|
+
klass.extend ClassMethods
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module ClassMethods
|
|
25
|
+
def profile_method_noop(*args)
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def profile_method_real(method_name, profile_name, store_args = false, store_return = false, *_)
|
|
30
|
+
begin
|
|
31
|
+
# this only gets file and line where profiling is turned on, presumably
|
|
32
|
+
# right after the function definition. ruby 1.9 and 2.0 has nice introspection (Method.source_location)
|
|
33
|
+
# but its appears no such luck for ruby 1.8
|
|
34
|
+
file = ''
|
|
35
|
+
line = ''
|
|
36
|
+
if RUBY_VERSION >= '1.9'
|
|
37
|
+
info = instance_method(method_name).source_location
|
|
38
|
+
unless info.nil?
|
|
39
|
+
file = info[0].to_s
|
|
40
|
+
line = info[1].to_s
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
info = Kernel.caller[0].split(':')
|
|
44
|
+
file = info.first.to_s
|
|
45
|
+
line = info.last.to_s
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Safety: Make sure there are no quotes or double quotes to break the class_eval
|
|
49
|
+
file = file.gsub(/[\'\"]/, '')
|
|
50
|
+
line = line.gsub(/[\'\"]/, '')
|
|
51
|
+
|
|
52
|
+
# profiling via ruby-prof, is it possible to get return value of profiled code?
|
|
53
|
+
code = "def _appoptics_profiled_#{method_name}(*args, &block)
|
|
54
|
+
entry_kvs = {}
|
|
55
|
+
entry_kvs['Language'] = 'ruby'
|
|
56
|
+
entry_kvs['ProfileName'] = '#{AppOpticsAPM::Util.prettify(profile_name)}'
|
|
57
|
+
entry_kvs['FunctionName'] = '#{AppOpticsAPM::Util.prettify(method_name)}'
|
|
58
|
+
entry_kvs['File'] = '#{file}'
|
|
59
|
+
entry_kvs['LineNumber'] = '#{line}'
|
|
60
|
+
entry_kvs['Args'] = AppOpticsAPM::API.pps(*args) if #{store_args}
|
|
61
|
+
entry_kvs.merge!(::AppOpticsAPM::API.get_class_name(self))
|
|
62
|
+
|
|
63
|
+
AppOpticsAPM::API.log(nil, 'profile_entry', entry_kvs)
|
|
64
|
+
|
|
65
|
+
ret = _appoptics_orig_#{method_name}(*args, &block)
|
|
66
|
+
|
|
67
|
+
exit_kvs = {}
|
|
68
|
+
exit_kvs['Language'] = 'ruby'
|
|
69
|
+
exit_kvs['ProfileName'] = '#{AppOpticsAPM::Util.prettify(profile_name)}'
|
|
70
|
+
exit_kvs['ReturnValue'] = AppOpticsAPM::API.pps(ret) if #{store_return}
|
|
71
|
+
|
|
72
|
+
AppOpticsAPM::API.log(nil, 'profile_exit', exit_kvs)
|
|
73
|
+
ret
|
|
74
|
+
end"
|
|
75
|
+
rescue => e
|
|
76
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/warn] profile_method: #{e.inspect}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
begin
|
|
80
|
+
class_eval code, __FILE__, __LINE__
|
|
81
|
+
alias_method "_appoptics_orig_#{method_name}", method_name
|
|
82
|
+
alias_method method_name, "_appoptics_profiled_#{method_name}"
|
|
83
|
+
rescue => e
|
|
84
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/warn] Fatal error profiling method (#{method_name}): #{e.inspect}" if AppOpticsAPM::Config[:verbose]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# This allows this module to be included and called even if the gem is in
|
|
89
|
+
# no-op mode (no base libraries).
|
|
90
|
+
if AppOpticsAPM.loaded
|
|
91
|
+
alias :profile_method :profile_method_real
|
|
92
|
+
else
|
|
93
|
+
alias :profile_method :profile_method_noop
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
end
|