solarwinds_apm 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.dockerignore +5 -0
- data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
- data/.github/workflows/build_and_release_gem.yml +112 -0
- data/.github/workflows/build_for_packagecloud.yml +70 -0
- data/.github/workflows/docker-images.yml +47 -0
- data/.github/workflows/run_cpluplus_tests.yml +73 -0
- data/.github/workflows/run_tests.yml +155 -0
- data/.github/workflows/scripts/test_install.rb +23 -0
- data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
- data/.github/workflows/test_on_4_linux.yml +161 -0
- data/.gitignore +39 -0
- data/.rubocop.yml +29 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +31 -0
- data/Gemfile +14 -0
- data/LICENSE +202 -0
- data/README.md +383 -0
- data/bin/solarwinds_apm_config +15 -0
- data/examples/prepend.rb +13 -0
- data/examples/sdk_examples.rb +158 -0
- data/ext/oboe_metal/README.md +69 -0
- data/ext/oboe_metal/extconf.rb +141 -0
- data/ext/oboe_metal/extconf_local.rb +75 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/noop/noop.c +8 -0
- data/ext/oboe_metal/src/README.md +6 -0
- data/ext/oboe_metal/src/VERSION +2 -0
- data/ext/oboe_metal/src/bson/bson.h +220 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/frames.cc +247 -0
- data/ext/oboe_metal/src/frames.h +40 -0
- data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
- data/ext/oboe_metal/src/logging.cc +95 -0
- data/ext/oboe_metal/src/logging.h +35 -0
- data/ext/oboe_metal/src/oboe.h +1169 -0
- data/ext/oboe_metal/src/oboe_api.cpp +658 -0
- data/ext/oboe_metal/src/oboe_api.hpp +433 -0
- data/ext/oboe_metal/src/oboe_debug.h +59 -0
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
- data/ext/oboe_metal/src/profiling.cc +435 -0
- data/ext/oboe_metal/src/profiling.h +78 -0
- data/ext/oboe_metal/test/CMakeLists.txt +53 -0
- data/ext/oboe_metal/test/FindGMock.cmake +43 -0
- data/ext/oboe_metal/test/README.md +56 -0
- data/ext/oboe_metal/test/frames_test.cc +164 -0
- data/ext/oboe_metal/test/profiling_test.cc +93 -0
- data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
- data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
- data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
- data/ext/oboe_metal/test/test.h +11 -0
- data/ext/oboe_metal/test/test_main.cc +32 -0
- data/init.rb +4 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +172 -0
- data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
- data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
- data/lib/solarwinds_apm/api/layerinit.rb +41 -0
- data/lib/solarwinds_apm/api/logging.rb +356 -0
- data/lib/solarwinds_apm/api/memcache.rb +37 -0
- data/lib/solarwinds_apm/api/metrics.rb +63 -0
- data/lib/solarwinds_apm/api/util.rb +98 -0
- data/lib/solarwinds_apm/api.rb +21 -0
- data/lib/solarwinds_apm/base.rb +160 -0
- data/lib/solarwinds_apm/config.rb +301 -0
- data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
- data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
- data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
- data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
- data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
- data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
- data/lib/solarwinds_apm/inst/curb.rb +288 -0
- data/lib/solarwinds_apm/inst/dalli.rb +89 -0
- data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
- data/lib/solarwinds_apm/inst/excon.rb +113 -0
- data/lib/solarwinds_apm/inst/faraday.rb +96 -0
- data/lib/solarwinds_apm/inst/graphql.rb +206 -0
- data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
- data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
- data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
- data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
- data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
- data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
- data/lib/solarwinds_apm/inst/memcached.rb +86 -0
- data/lib/solarwinds_apm/inst/mongo.rb +246 -0
- data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
- data/lib/solarwinds_apm/inst/moped.rb +466 -0
- data/lib/solarwinds_apm/inst/net_http.rb +60 -0
- data/lib/solarwinds_apm/inst/rack.rb +217 -0
- data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
- data/lib/solarwinds_apm/inst/redis.rb +273 -0
- data/lib/solarwinds_apm/inst/resque.rb +129 -0
- data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
- data/lib/solarwinds_apm/inst/sequel.rb +241 -0
- data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
- data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
- data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
- data/lib/solarwinds_apm/instrumentation.rb +22 -0
- data/lib/solarwinds_apm/loading.rb +65 -0
- data/lib/solarwinds_apm/logger.rb +14 -0
- data/lib/solarwinds_apm/noop/README.md +9 -0
- data/lib/solarwinds_apm/noop/context.rb +26 -0
- data/lib/solarwinds_apm/noop/metadata.rb +25 -0
- data/lib/solarwinds_apm/noop/profiling.rb +21 -0
- data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
- data/lib/solarwinds_apm/ruby.rb +35 -0
- data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
- data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
- data/lib/solarwinds_apm/sdk/logging.rb +37 -0
- data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
- data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
- data/lib/solarwinds_apm/support/profiling.rb +22 -0
- data/lib/solarwinds_apm/support/trace_context.rb +53 -0
- data/lib/solarwinds_apm/support/trace_state.rb +69 -0
- data/lib/solarwinds_apm/support/trace_string.rb +89 -0
- data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
- data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
- data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
- data/lib/solarwinds_apm/support.rb +12 -0
- data/lib/solarwinds_apm/support_report.rb +113 -0
- data/lib/solarwinds_apm/test.rb +165 -0
- data/lib/solarwinds_apm/thread_local.rb +26 -0
- data/lib/solarwinds_apm/util.rb +334 -0
- data/lib/solarwinds_apm/version.rb +17 -0
- data/lib/solarwinds_apm.rb +72 -0
- data/log/.keep +0 -0
- data/log/postgresql/.keep +0 -0
- data/solarwinds_apm.gemspec +52 -0
- data/yardoc_frontpage.md +24 -0
- metadata +228 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module SolarWindsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module BunnyExchange
|
|
7
|
+
include SolarWindsAPM::SDK::TraceContextHeaders
|
|
8
|
+
|
|
9
|
+
def self.included(klass)
|
|
10
|
+
SolarWindsAPM::Util.method_alias(klass, :delete, ::Bunny::Exchange)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def delete_with_sw_apm(opts = {})
|
|
14
|
+
# If we're not tracing, just do a fast return.
|
|
15
|
+
return delete_without_sw_apm(opts) if !SolarWindsAPM.tracing?
|
|
16
|
+
|
|
17
|
+
begin
|
|
18
|
+
kvs = {}
|
|
19
|
+
kvs[:Spec] = :pushq
|
|
20
|
+
kvs[:Flavor] = :rabbitmq
|
|
21
|
+
kvs[:Op] = :delete
|
|
22
|
+
kvs[:ExchangeType] = @type
|
|
23
|
+
kvs[:RemoteHost] = channel.connection.host
|
|
24
|
+
kvs[:RemotePort] = channel.connection.port.to_i
|
|
25
|
+
kvs[:VirtualHost] = channel.connection.vhost
|
|
26
|
+
|
|
27
|
+
if @name.is_a?(String) && !@name.empty?
|
|
28
|
+
kvs[:ExchangeName] = @name
|
|
29
|
+
else
|
|
30
|
+
kvs[:ExchangeName] = :default
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
SolarWindsAPM::API.log_entry(:'rabbitmq-client')
|
|
34
|
+
delete_without_sw_apm(opts)
|
|
35
|
+
rescue => e
|
|
36
|
+
SolarWindsAPM::API.log_exception(:'rabbitmq-client', e)
|
|
37
|
+
raise e
|
|
38
|
+
ensure
|
|
39
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:bunnyclient][:collect_backtraces]
|
|
40
|
+
SolarWindsAPM::API.log_exit(:'rabbitmq-client', kvs)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module BunnyChannel
|
|
46
|
+
include SolarWindsAPM::SDK::TraceContextHeaders
|
|
47
|
+
|
|
48
|
+
def self.included(klass)
|
|
49
|
+
SolarWindsAPM::Util.method_alias(klass, :basic_publish, ::Bunny::Channel)
|
|
50
|
+
SolarWindsAPM::Util.method_alias(klass, :queue, ::Bunny::Channel)
|
|
51
|
+
SolarWindsAPM::Util.method_alias(klass, :wait_for_confirms, ::Bunny::Channel)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def collect_channel_kvs
|
|
55
|
+
kvs = {}
|
|
56
|
+
kvs[:Spec] = :pushq
|
|
57
|
+
kvs[:Flavor] = :rabbitmq
|
|
58
|
+
kvs[:RemoteHost] = @connection.host
|
|
59
|
+
kvs[:RemotePort] = @connection.port.to_i
|
|
60
|
+
kvs[:VirtualHost] = @connection.vhost
|
|
61
|
+
kvs
|
|
62
|
+
rescue => e
|
|
63
|
+
SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
|
|
64
|
+
ensure
|
|
65
|
+
return kvs
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def basic_publish_with_sw_apm(payload, exchange, routing_key, opts = {})
|
|
69
|
+
# If we're not tracing, just do a fast return.
|
|
70
|
+
return basic_publish_without_sw_apm(payload, exchange, routing_key, opts) if !SolarWindsAPM.tracing?
|
|
71
|
+
|
|
72
|
+
begin
|
|
73
|
+
kvs = collect_channel_kvs
|
|
74
|
+
|
|
75
|
+
if exchange.respond_to?(:name)
|
|
76
|
+
kvs[:ExchangeName] = exchange.name
|
|
77
|
+
elsif exchange.respond_to?(:empty?) && !exchange.empty?
|
|
78
|
+
kvs[:ExchangeName] = exchange
|
|
79
|
+
else
|
|
80
|
+
kvs[:ExchangeName] = :default
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
kvs[:Queue] = opts[:queue] if opts.key?(:queue)
|
|
84
|
+
kvs[:RoutingKey] = routing_key if routing_key
|
|
85
|
+
kvs[:Op] = :publish
|
|
86
|
+
|
|
87
|
+
SolarWindsAPM::API.log_entry(:'rabbitmq-client')
|
|
88
|
+
# Pass the tracing context as a header
|
|
89
|
+
opts[:headers] ||= {}
|
|
90
|
+
opts[:headers][:SourceTrace] = SolarWindsAPM::Context.toString
|
|
91
|
+
add_tracecontext_headers(opts[:headers])
|
|
92
|
+
|
|
93
|
+
basic_publish_without_sw_apm(payload, exchange, routing_key, opts)
|
|
94
|
+
rescue => e
|
|
95
|
+
SolarWindsAPM::API.log_exception(:'rabbitmq-client', e)
|
|
96
|
+
raise e
|
|
97
|
+
ensure
|
|
98
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:bunnyclient][:collect_backtraces]
|
|
99
|
+
SolarWindsAPM::API.log_exit(:'rabbitmq-client', kvs)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def queue_with_sw_apm(name = AMQ::Protocol::EMPTY_STRING, opts = {})
|
|
104
|
+
# If we're not tracing, just do a fast return.
|
|
105
|
+
return queue_without_sw_apm(name, opts) if !SolarWindsAPM.tracing?
|
|
106
|
+
|
|
107
|
+
begin
|
|
108
|
+
kvs = collect_channel_kvs
|
|
109
|
+
kvs[:Op] = :queue
|
|
110
|
+
|
|
111
|
+
SolarWindsAPM::API.log_entry(:'rabbitmq-client')
|
|
112
|
+
opts[:headers] ||= {}
|
|
113
|
+
add_tracecontext_headers(opts[:headers])
|
|
114
|
+
|
|
115
|
+
result = queue_without_sw_apm(name, opts)
|
|
116
|
+
kvs[:Queue] = result.name
|
|
117
|
+
result
|
|
118
|
+
rescue => e
|
|
119
|
+
SolarWindsAPM::API.log_exception(:'rabbitmq-client', e)
|
|
120
|
+
raise e
|
|
121
|
+
ensure
|
|
122
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:bunnyclient][:collect_backtraces]
|
|
123
|
+
SolarWindsAPM::API.log_exit(:'rabbitmq-client', kvs)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def wait_for_confirms_with_sw_apm
|
|
128
|
+
# If we're not tracing, just do a fast return.
|
|
129
|
+
return wait_for_confirms_without_sw_apm if !SolarWindsAPM.tracing?
|
|
130
|
+
|
|
131
|
+
begin
|
|
132
|
+
kvs = collect_channel_kvs
|
|
133
|
+
kvs[:Op] = :wait_for_confirms
|
|
134
|
+
|
|
135
|
+
SolarWindsAPM::API.log_entry(:'rabbitmq-client')
|
|
136
|
+
# can't continue trace for wait on consumer, because we can't send opts for wait
|
|
137
|
+
# Seems ok, since this is waiting client side
|
|
138
|
+
# and not actually spending time on the consumer
|
|
139
|
+
|
|
140
|
+
wait_for_confirms_without_sw_apm
|
|
141
|
+
rescue => e
|
|
142
|
+
SolarWindsAPM::API.log_exception(:'rabbitmq-client', e)
|
|
143
|
+
raise e
|
|
144
|
+
ensure
|
|
145
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:bunnyclient][:collect_backtraces]
|
|
146
|
+
SolarWindsAPM::API.log_exit(:'rabbitmq-client', kvs)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
if defined?(Bunny) && SolarWindsAPM::Config[:bunnyclient][:enabled]
|
|
154
|
+
SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting bunny client' if SolarWindsAPM::Config[:verbose]
|
|
155
|
+
SolarWindsAPM::Util.send_include(Bunny::Exchange, SolarWindsAPM::Inst::BunnyExchange)
|
|
156
|
+
SolarWindsAPM::Util.send_include(Bunny::Channel, SolarWindsAPM::Inst::BunnyChannel)
|
|
157
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module SolarWindsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module BunnyConsumer
|
|
7
|
+
include SolarWindsAPM::SDK::TraceContextHeaders
|
|
8
|
+
|
|
9
|
+
def self.included(klass)
|
|
10
|
+
SolarWindsAPM::Util.method_alias(klass, :call, ::Bunny::Consumer)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def collect_consumer_kvs(args)
|
|
14
|
+
kvs = {}
|
|
15
|
+
kvs[:Spec] = :job
|
|
16
|
+
kvs[:Flavor] = :rabbitmq
|
|
17
|
+
kvs[:RemoteHost] = @channel.connection.host
|
|
18
|
+
kvs[:RemotePort] = @channel.connection.port.to_i
|
|
19
|
+
kvs[:VirtualHost] = @channel.connection.vhost
|
|
20
|
+
|
|
21
|
+
mp = args[1]
|
|
22
|
+
kvs[:RoutingKey] = args[0].routing_key if args[0].routing_key
|
|
23
|
+
kvs[:MsgID] = args[1].message_id if mp.message_id
|
|
24
|
+
kvs[:AppID] = args[1].app_id if mp.app_id
|
|
25
|
+
kvs[:Priority] = args[1].priority if mp.priority
|
|
26
|
+
|
|
27
|
+
if @queue.respond_to?(:name)
|
|
28
|
+
kvs[:Queue] = @queue.name
|
|
29
|
+
else
|
|
30
|
+
kvs[:Queue] = @queue
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Report configurable Controller/Action KVs
|
|
34
|
+
# See SolarWindsAPM::Config[:bunnyconsumer] in lib/solarwinds_apm/config.rb
|
|
35
|
+
# Used for dashboard trace filtering
|
|
36
|
+
controller_key = SolarWindsAPM::Config[:bunnyconsumer][:controller]
|
|
37
|
+
if mp.respond_to?(controller_key)
|
|
38
|
+
value = mp.method(controller_key).call
|
|
39
|
+
kvs[:Controller] = value if value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
action_key = SolarWindsAPM::Config[:bunnyconsumer][:action]
|
|
43
|
+
if mp.respond_to?(action_key)
|
|
44
|
+
value = mp.method(action_key).call
|
|
45
|
+
kvs[:Action] = value if value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if kvs[:Queue]
|
|
49
|
+
kvs[:URL] = "/bunny/#{kvs[:Queue]}"
|
|
50
|
+
else
|
|
51
|
+
kvs[:URL] = "/bunny/consumer"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if SolarWindsAPM::Config[:bunnyconsumer][:log_args] && @arguments
|
|
55
|
+
kvs[:Args] = @arguments.to_s
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:bunnyconsumer][:collect_backtraces]
|
|
59
|
+
|
|
60
|
+
kvs
|
|
61
|
+
rescue => e
|
|
62
|
+
SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
|
|
63
|
+
ensure
|
|
64
|
+
return kvs
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def call_with_sw_apm(*args)
|
|
68
|
+
report_kvs = collect_consumer_kvs(args)
|
|
69
|
+
|
|
70
|
+
# TODO all of this (to the next empty line) can be removed
|
|
71
|
+
# once all of our agents (actually only Node) use w3c-header for RabbitMQ
|
|
72
|
+
# w3c headers are read and added by the logging code
|
|
73
|
+
# If SourceTrace was passed:
|
|
74
|
+
# - capture it, report it
|
|
75
|
+
# - and add it as traceparent and tracestate header for use by start_trace
|
|
76
|
+
headers = args[1][:headers]
|
|
77
|
+
if headers && headers['SourceTrace']
|
|
78
|
+
report_kvs[:SourceTrace] = headers['SourceTrace']
|
|
79
|
+
# Remove SourceTrace
|
|
80
|
+
headers.delete('SourceTrace')
|
|
81
|
+
unless headers['traceparent'] && headers['tracestate']
|
|
82
|
+
add_tracecontext_headers(headers)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# the context either gets propagated via w3c headers
|
|
87
|
+
# or a new one should be started
|
|
88
|
+
# lets clear any context that may exist
|
|
89
|
+
# TODO revert with NH-11132
|
|
90
|
+
SolarWindsAPM::Context.clear
|
|
91
|
+
SolarWindsAPM::SDK.start_trace(:'rabbitmq-consumer', kvs: report_kvs, headers: headers) do
|
|
92
|
+
call_without_sw_apm(*args)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if SolarWindsAPM::Config[:bunnyconsumer][:enabled] && defined?(Bunny)
|
|
100
|
+
SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting bunny consumer' if SolarWindsAPM::Config[:verbose]
|
|
101
|
+
SolarWindsAPM::Util.send_include(Bunny::Consumer, SolarWindsAPM::Inst::BunnyConsumer)
|
|
102
|
+
end
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module SolarWindsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
|
|
7
|
+
# Curb instrumentation wraps instance and class methods in two classes:
|
|
8
|
+
# Curl::Easy and Curl::Multi. This CurlUtility module is used as a common module
|
|
9
|
+
# to be shared among both modules.
|
|
10
|
+
module CurlUtility
|
|
11
|
+
include SolarWindsAPM::SDK::TraceContextHeaders
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
##
|
|
15
|
+
# sw_apm_collect
|
|
16
|
+
#
|
|
17
|
+
# Used as a central area to retrieve and return values
|
|
18
|
+
# that we're interesting in reporting to SolarWindsAPM
|
|
19
|
+
#
|
|
20
|
+
def sw_apm_collect(verb = nil)
|
|
21
|
+
kvs = {}
|
|
22
|
+
|
|
23
|
+
kvs[:Spec] = 'rsc'
|
|
24
|
+
kvs[:IsService] = 1
|
|
25
|
+
|
|
26
|
+
# Conditionally log query args
|
|
27
|
+
if SolarWindsAPM::Config[:curb][:log_args]
|
|
28
|
+
kvs[:RemoteURL] = url
|
|
29
|
+
else
|
|
30
|
+
kvs[:RemoteURL] = url.split('?').first
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
kvs[:HTTPMethod] = verb if verb
|
|
34
|
+
|
|
35
|
+
kvs
|
|
36
|
+
rescue => e
|
|
37
|
+
SolarWindsAPM.logger.debug "[solarwinds_apm/debug] Error capturing curb KVs: #{e.message}"
|
|
38
|
+
if SolarWindsAPM::Config[:verbose]
|
|
39
|
+
SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
|
|
40
|
+
SolarWindsAPM.logger.debug e.backtrace.join('\n')
|
|
41
|
+
end
|
|
42
|
+
ensure
|
|
43
|
+
return kvs
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# trace_curb_method
|
|
48
|
+
#
|
|
49
|
+
# An agnostic method that will profile any Curl::Easy method (and optional args and block)
|
|
50
|
+
# that you throw at it.
|
|
51
|
+
#
|
|
52
|
+
def trace_curb_method(kvs, method, args, &block)
|
|
53
|
+
# If we're not tracing, just do a fast return.
|
|
54
|
+
unless SolarWindsAPM.tracing?
|
|
55
|
+
add_tracecontext_headers(self.headers)
|
|
56
|
+
return self.send(method, args, &block)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
kvs.merge! sw_apm_collect
|
|
61
|
+
|
|
62
|
+
SolarWindsAPM::API.log_entry(:curb, kvs)
|
|
63
|
+
kvs.clear
|
|
64
|
+
|
|
65
|
+
# The core curb call
|
|
66
|
+
add_tracecontext_headers(self.headers)
|
|
67
|
+
response = self.send(method, *args, &block)
|
|
68
|
+
|
|
69
|
+
kvs[:HTTPStatus] = response_code
|
|
70
|
+
|
|
71
|
+
# If we get a redirect, report the location header
|
|
72
|
+
if ((300..308).to_a.include? response_code) && headers.key?("Location")
|
|
73
|
+
kvs[:Location] = headers["Location"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
response
|
|
77
|
+
rescue => e
|
|
78
|
+
SolarWindsAPM::API.log_exception(:curb, e)
|
|
79
|
+
raise e
|
|
80
|
+
ensure
|
|
81
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:curb][:collect_backtraces]
|
|
82
|
+
SolarWindsAPM::API.log_exit(:curb, kvs)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end # CurlUtility
|
|
87
|
+
|
|
88
|
+
# Instrumentation specific to ::Curl::Easy
|
|
89
|
+
module CurlEasy
|
|
90
|
+
# Common methods
|
|
91
|
+
include SolarWindsAPM::Inst::CurlUtility
|
|
92
|
+
|
|
93
|
+
def self.included(klass)
|
|
94
|
+
SolarWindsAPM::Util.method_alias(klass, :http, ::Curl::Easy)
|
|
95
|
+
SolarWindsAPM::Util.method_alias(klass, :perform, ::Curl::Easy)
|
|
96
|
+
SolarWindsAPM::Util.method_alias(klass, :http_put, ::Curl::Easy)
|
|
97
|
+
SolarWindsAPM::Util.method_alias(klass, :http_post, ::Curl::Easy)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# http_post_with_sw_apm
|
|
102
|
+
#
|
|
103
|
+
# ::Curl::Easy.new.http_post wrapper
|
|
104
|
+
#
|
|
105
|
+
def http_post_with_sw_apm(*args, &block)
|
|
106
|
+
# If we're not tracing, just do a fast return.
|
|
107
|
+
if !SolarWindsAPM.tracing? || SolarWindsAPM.tracing_layer?(:curb)
|
|
108
|
+
add_tracecontext_headers(self.headers)
|
|
109
|
+
return http_post_without_sw_apm(*args)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
kvs = {}
|
|
113
|
+
kvs[:HTTPMethod] = :POST
|
|
114
|
+
|
|
115
|
+
trace_curb_method(kvs, :http_post_without_sw_apm, args, &block)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
##
|
|
119
|
+
# http_put_with_sw_apm
|
|
120
|
+
#
|
|
121
|
+
# ::Curl::Easy.new.http_put wrapper
|
|
122
|
+
#
|
|
123
|
+
def http_put_with_sw_apm(*args, &block)
|
|
124
|
+
# If we're not tracing, just do a fast return.
|
|
125
|
+
if !SolarWindsAPM.tracing? || SolarWindsAPM.tracing_layer?(:curb)
|
|
126
|
+
add_tracecontext_headers(self.headers)
|
|
127
|
+
return http_put_without_sw_apm(data)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
kvs = {}
|
|
131
|
+
kvs[:HTTPMethod] = :PUT
|
|
132
|
+
|
|
133
|
+
trace_curb_method(kvs, :http_put_without_sw_apm, args, &block)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
##
|
|
137
|
+
# perform_with_sw_apm
|
|
138
|
+
#
|
|
139
|
+
# ::Curl::Easy.new.perform wrapper
|
|
140
|
+
#
|
|
141
|
+
def perform_with_sw_apm(&block)
|
|
142
|
+
# If we're not tracing, just do a fast return.
|
|
143
|
+
# excluding curb layer: because the curb C code for easy.http calls perform,
|
|
144
|
+
# we have to make sure we don't log again
|
|
145
|
+
if !SolarWindsAPM.tracing? || SolarWindsAPM.tracing_layer?(:curb)
|
|
146
|
+
add_tracecontext_headers(self.headers)
|
|
147
|
+
return perform_without_sw_apm(&block)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
kvs = {}
|
|
151
|
+
# This perform gets called from two places, ::Curl::Easy.new.perform
|
|
152
|
+
# and Curl::Easy.new.http_head. In the case of http_head we detect the
|
|
153
|
+
# HTTP verb via get info.
|
|
154
|
+
if self.getinfo(self.sym2curl(:nobody))
|
|
155
|
+
kvs[:HTTPMethod] = :HEAD
|
|
156
|
+
else
|
|
157
|
+
kvs[:HTTPMethod] = :GET
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
trace_curb_method(kvs, :perform_without_sw_apm, nil, &block)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# http_with_sw_apm
|
|
165
|
+
#
|
|
166
|
+
# ::Curl::Easy.new.http wrapper
|
|
167
|
+
#
|
|
168
|
+
def http_with_sw_apm(verb, &block)
|
|
169
|
+
unless SolarWindsAPM.tracing?
|
|
170
|
+
add_tracecontext_headers(self.headers)
|
|
171
|
+
# If we're not tracing, just do a fast return.
|
|
172
|
+
return http_without_sw_apm(verb)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
kvs = {}
|
|
176
|
+
kvs[:HTTPMethod] = verb
|
|
177
|
+
|
|
178
|
+
trace_curb_method(kvs, :http_without_sw_apm, [verb], &block)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
##
|
|
183
|
+
# CurlMultiCM
|
|
184
|
+
#
|
|
185
|
+
# This module contains the class method wrappers for the CurlMulti class.
|
|
186
|
+
# This module should be _extended_ by CurlMulti.
|
|
187
|
+
#
|
|
188
|
+
module CurlMultiCM
|
|
189
|
+
include SolarWindsAPM::Inst::CurlUtility
|
|
190
|
+
|
|
191
|
+
def self.extended(klass)
|
|
192
|
+
SolarWindsAPM::Util.class_method_alias(klass, :http, ::Curl::Multi)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
##
|
|
196
|
+
# http_with_sw_apm
|
|
197
|
+
#
|
|
198
|
+
# ::Curl::Multi.new.http wrapper
|
|
199
|
+
#
|
|
200
|
+
def http_with_sw_apm(urls_with_config, multi_options={}, &block)
|
|
201
|
+
# If we're not tracing, just do a fast return.
|
|
202
|
+
unless SolarWindsAPM.tracing?
|
|
203
|
+
urls_with_config.each do |conf|
|
|
204
|
+
conf[:headers] ||= {}
|
|
205
|
+
add_tracecontext_headers(conf[:headers])
|
|
206
|
+
end
|
|
207
|
+
return http_without_sw_apm(urls_with_config, multi_options, &block)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
begin
|
|
211
|
+
kvs = {}
|
|
212
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:curb][:collect_backtraces]
|
|
213
|
+
|
|
214
|
+
SolarWindsAPM::API.log_entry(:curb_multi, kvs)
|
|
215
|
+
context = SolarWindsAPM::Context.toString
|
|
216
|
+
|
|
217
|
+
traces = []
|
|
218
|
+
urls_with_config.each do |conf|
|
|
219
|
+
conf[:headers] ||= {}
|
|
220
|
+
add_tracecontext_headers(conf[:headers])
|
|
221
|
+
end
|
|
222
|
+
# The core curb call
|
|
223
|
+
http_without_sw_apm(urls_with_config, multi_options)
|
|
224
|
+
rescue => e
|
|
225
|
+
SolarWindsAPM::API.log_exception(:curb_multi, e)
|
|
226
|
+
raise e
|
|
227
|
+
ensure
|
|
228
|
+
SolarWindsAPM::API.log_exit(:curb_multi)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
##
|
|
234
|
+
# CurlMultiIM
|
|
235
|
+
#
|
|
236
|
+
# This module contains the instance method wrappers for the CurlMulti class.
|
|
237
|
+
# This module should be _included_ into CurlMulti.
|
|
238
|
+
#
|
|
239
|
+
module CurlMultiIM
|
|
240
|
+
include SolarWindsAPM::Inst::CurlUtility
|
|
241
|
+
|
|
242
|
+
def self.included(klass)
|
|
243
|
+
SolarWindsAPM::Util.method_alias(klass, :perform, ::Curl::Multi)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
##
|
|
247
|
+
# perform_with_sw_apm
|
|
248
|
+
#
|
|
249
|
+
# ::Curl::Multi.new.perform wrapper
|
|
250
|
+
#
|
|
251
|
+
# the reason we instrument this method is because it can be called directly,
|
|
252
|
+
# therefore we exclude calls that already have a curb layer assigned
|
|
253
|
+
# Be aware: this method is also called from the c-implementation
|
|
254
|
+
#
|
|
255
|
+
def perform_with_sw_apm(&block)
|
|
256
|
+
self.requests.each do |request|
|
|
257
|
+
request = request[1] if request.is_a?(Array)
|
|
258
|
+
add_tracecontext_headers(request.headers)
|
|
259
|
+
end
|
|
260
|
+
# If we're not tracing or we're already tracing curb, just do a fast return.
|
|
261
|
+
if !SolarWindsAPM.tracing? || [:curb, :curb_multi].include?(SolarWindsAPM.layer)
|
|
262
|
+
return perform_without_sw_apm(&block)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
begin
|
|
266
|
+
kvs = {}
|
|
267
|
+
kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:curb][:collect_backtraces]
|
|
268
|
+
|
|
269
|
+
SolarWindsAPM::API.log_entry(:curb_multi, kvs)
|
|
270
|
+
|
|
271
|
+
perform_without_sw_apm(&block)
|
|
272
|
+
rescue => e
|
|
273
|
+
SolarWindsAPM::API.log_exception(:curb_multi, e)
|
|
274
|
+
raise e
|
|
275
|
+
ensure
|
|
276
|
+
SolarWindsAPM::API.log_exit(:curb_multi)
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
if SolarWindsAPM::Config[:curb][:enabled] && defined?(::Curl)
|
|
284
|
+
SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting curb' if SolarWindsAPM::Config[:verbose]
|
|
285
|
+
SolarWindsAPM::Util.send_include(::Curl::Easy, SolarWindsAPM::Inst::CurlEasy)
|
|
286
|
+
SolarWindsAPM::Util.send_extend(::Curl::Multi, SolarWindsAPM::Inst::CurlMultiCM)
|
|
287
|
+
SolarWindsAPM::Util.send_include(::Curl::Multi, SolarWindsAPM::Inst::CurlMultiIM)
|
|
288
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module SolarWindsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
module Dalli
|
|
7
|
+
include SolarWindsAPM::API::Memcache
|
|
8
|
+
|
|
9
|
+
def self.included(cls)
|
|
10
|
+
cls.class_eval do
|
|
11
|
+
SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting memcache (dalli)' if SolarWindsAPM::Config[:verbose]
|
|
12
|
+
if ::Dalli::Client.private_method_defined? :perform
|
|
13
|
+
alias perform_without_sw_apm perform
|
|
14
|
+
alias perform perform_with_sw_apm
|
|
15
|
+
else
|
|
16
|
+
SolarWindsAPM.logger.warn '[solarwinds_apm/loading] Couldn\'t properly instrument Memcache (Dalli). Partial traces may occur.'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if ::Dalli::Client.method_defined? :get_multi
|
|
20
|
+
alias get_multi_without_sw_apm get_multi
|
|
21
|
+
alias get_multi get_multi_with_sw_apm
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def perform_with_sw_apm(*all_args, &blk)
|
|
27
|
+
op, key, *args = *all_args
|
|
28
|
+
|
|
29
|
+
report_kvs = {}
|
|
30
|
+
report_kvs[:KVOp] = op
|
|
31
|
+
report_kvs[:KVKey] = key
|
|
32
|
+
|
|
33
|
+
servers = @servers || @normalized_servers # name change since Dall 3.2.0
|
|
34
|
+
if servers.is_a?(Array) && !servers.empty?
|
|
35
|
+
report_kvs[:RemoteHost] = servers.join(", ")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if SolarWindsAPM.tracing? && !SolarWindsAPM.tracing_layer_op?(:get_multi)
|
|
39
|
+
SolarWindsAPM::SDK.trace(:memcache, kvs: report_kvs) do
|
|
40
|
+
result = perform_without_sw_apm(*all_args, &blk)
|
|
41
|
+
|
|
42
|
+
# Clear the hash for a potential info event
|
|
43
|
+
report_kvs.clear
|
|
44
|
+
report_kvs[:KVHit] = memcache_hit?(result) if op == :get && key.class == String
|
|
45
|
+
report_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:dalli][:collect_backtraces]
|
|
46
|
+
|
|
47
|
+
result
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
perform_without_sw_apm(*all_args, &blk)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def get_multi_with_sw_apm(*keys)
|
|
55
|
+
return get_multi_without_sw_apm(*keys) unless SolarWindsAPM.tracing?
|
|
56
|
+
|
|
57
|
+
info_kvs = {}
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
info_kvs[:KVKeyCount] = keys.flatten.length
|
|
61
|
+
info_kvs[:KVKeyCount] = (info_kvs[:KVKeyCount] - 1) if keys.last.is_a?(Hash) || keys.last.nil?
|
|
62
|
+
|
|
63
|
+
servers = @servers || @normalized_servers # name change since Dalli 3.2.1
|
|
64
|
+
if servers.is_a?(Array) && !servers.empty?
|
|
65
|
+
info_kvs[:RemoteHost] = servers.join(", ")
|
|
66
|
+
end
|
|
67
|
+
rescue => e
|
|
68
|
+
SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
info_kvs[:KVOp] = :get_multi
|
|
72
|
+
info_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:dalli][:collect_backtraces]
|
|
73
|
+
SolarWindsAPM::SDK.trace(:memcache, kvs: info_kvs, protect_op: :get_multi) do
|
|
74
|
+
values = get_multi_without_sw_apm(*keys)
|
|
75
|
+
|
|
76
|
+
info_kvs[:KVHitCount] = values.length
|
|
77
|
+
|
|
78
|
+
values
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if defined?(Dalli) && SolarWindsAPM::Config[:dalli][:enabled]
|
|
86
|
+
::Dalli::Client.module_eval do
|
|
87
|
+
include SolarWindsAPM::Inst::Dalli
|
|
88
|
+
end
|
|
89
|
+
end
|