appoptics_apm_mnfst 4.5.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.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.gitignore +29 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +121 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +769 -0
  9. data/CONFIG.md +33 -0
  10. data/Gemfile +29 -0
  11. data/LICENSE +193 -0
  12. data/README.md +393 -0
  13. data/Rakefile +230 -0
  14. data/appoptics_apm.gemspec +61 -0
  15. data/bin/appoptics_apm_config +15 -0
  16. data/build_gem.sh +15 -0
  17. data/build_gem_upload_to_packagecloud.sh +20 -0
  18. data/examples/SDK/01_basic_tracing.rb +67 -0
  19. data/examples/carrying_context.rb +220 -0
  20. data/ext/oboe_metal/extconf.rb +114 -0
  21. data/ext/oboe_metal/lib/.keep +0 -0
  22. data/ext/oboe_metal/noop/noop.c +7 -0
  23. data/ext/oboe_metal/src/VERSION +1 -0
  24. data/init.rb +4 -0
  25. data/lib/appoptics_apm.rb +76 -0
  26. data/lib/appoptics_apm/api.rb +20 -0
  27. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  28. data/lib/appoptics_apm/api/logging.rb +375 -0
  29. data/lib/appoptics_apm/api/memcache.rb +37 -0
  30. data/lib/appoptics_apm/api/metrics.rb +55 -0
  31. data/lib/appoptics_apm/api/profiling.rb +203 -0
  32. data/lib/appoptics_apm/api/tracing.rb +53 -0
  33. data/lib/appoptics_apm/api/util.rb +122 -0
  34. data/lib/appoptics_apm/base.rb +230 -0
  35. data/lib/appoptics_apm/config.rb +254 -0
  36. data/lib/appoptics_apm/frameworks/grape.rb +97 -0
  37. data/lib/appoptics_apm/frameworks/padrino.rb +108 -0
  38. data/lib/appoptics_apm/frameworks/rails.rb +94 -0
  39. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  40. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +55 -0
  41. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  42. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  43. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  44. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  45. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  46. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  47. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  48. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  49. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  50. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  51. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +108 -0
  52. data/lib/appoptics_apm/frameworks/sinatra.rb +125 -0
  53. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  54. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  55. data/lib/appoptics_apm/inst/curb.rb +330 -0
  56. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  57. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  58. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  59. data/lib/appoptics_apm/inst/excon.rb +125 -0
  60. data/lib/appoptics_apm/inst/faraday.rb +94 -0
  61. data/lib/appoptics_apm/inst/grpc_client.rb +162 -0
  62. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  63. data/lib/appoptics_apm/inst/http.rb +73 -0
  64. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  65. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  66. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  67. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  68. data/lib/appoptics_apm/inst/moped.rb +466 -0
  69. data/lib/appoptics_apm/inst/rack.rb +199 -0
  70. data/lib/appoptics_apm/inst/redis.rb +275 -0
  71. data/lib/appoptics_apm/inst/resque.rb +151 -0
  72. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  73. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  74. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  75. data/lib/appoptics_apm/inst/sidekiq-worker.rb +65 -0
  76. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  77. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  78. data/lib/appoptics_apm/instrumentation.rb +22 -0
  79. data/lib/appoptics_apm/legacy_method_profiling.rb +90 -0
  80. data/lib/appoptics_apm/loading.rb +65 -0
  81. data/lib/appoptics_apm/logger.rb +42 -0
  82. data/lib/appoptics_apm/method_profiling.rb +33 -0
  83. data/lib/appoptics_apm/noop/README.md +9 -0
  84. data/lib/appoptics_apm/noop/context.rb +26 -0
  85. data/lib/appoptics_apm/noop/metadata.rb +22 -0
  86. data/lib/appoptics_apm/ruby.rb +35 -0
  87. data/lib/appoptics_apm/sdk/custom_metrics.rb +92 -0
  88. data/lib/appoptics_apm/sdk/tracing.rb +315 -0
  89. data/lib/appoptics_apm/support.rb +119 -0
  90. data/lib/appoptics_apm/test.rb +94 -0
  91. data/lib/appoptics_apm/thread_local.rb +26 -0
  92. data/lib/appoptics_apm/util.rb +319 -0
  93. data/lib/appoptics_apm/version.rb +15 -0
  94. data/lib/appoptics_apm/xtrace.rb +103 -0
  95. data/lib/joboe_metal.rb +212 -0
  96. data/lib/oboe.rb +7 -0
  97. data/lib/oboe/README +2 -0
  98. data/lib/oboe/backward_compatibility.rb +80 -0
  99. data/lib/oboe/inst/rack.rb +11 -0
  100. data/lib/oboe_metal.rb +198 -0
  101. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  102. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +265 -0
  103. data/yardoc_frontpage.md +26 -0
  104. metadata +266 -0
@@ -0,0 +1,330 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
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
+
12
+ private
13
+ ##
14
+ # appoptics_collect
15
+ #
16
+ # Used as a central area to retrieve and return values
17
+ # that we're interesting in reporting to AppOpticsAPM
18
+ #
19
+ def appoptics_collect(verb = nil)
20
+ kvs = {}
21
+
22
+ kvs[:Spec] = 'rsc'
23
+ kvs[:IsService] = 1
24
+
25
+ # Conditionally log query args
26
+ if AppOpticsAPM::Config[:curb][:log_args]
27
+ kvs[:RemoteURL] = url
28
+ else
29
+ kvs[:RemoteURL] = url.split('?').first
30
+ end
31
+
32
+ kvs[:HTTPMethod] = verb if verb
33
+
34
+ # Avoid cross host tracing for blacklisted domains
35
+ kvs[:blacklisted] = AppOpticsAPM::API.blacklisted?(URI(url).hostname)
36
+
37
+ kvs
38
+ rescue => e
39
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error capturing curb KVs: #{e.message}"
40
+ if AppOpticsAPM::Config[:verbose]
41
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
42
+ AppOpticsAPM.logger.debug e.backtrace.join('\n')
43
+ end
44
+ ensure
45
+ return kvs
46
+ end
47
+
48
+ ##
49
+ # profile_curb_method
50
+ #
51
+ # An agnostic method that will profile any Curl::Easy method (and optional args and block)
52
+ # that you throw at it.
53
+ #
54
+ def profile_curb_method(kvs, method, args, &block)
55
+ # If we're not tracing, just do a fast return.
56
+ unless AppOpticsAPM.tracing?
57
+ unless AppOpticsAPM::API.blacklisted?(URI(url).hostname)
58
+ self.headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid
59
+ end
60
+ return self.send(method, args, &block)
61
+ end
62
+
63
+ begin
64
+ response_context = nil
65
+ kvs.merge! appoptics_collect
66
+
67
+ AppOpticsAPM::API.log_entry(:curb, kvs)
68
+ kvs.clear
69
+
70
+ # The core curb call
71
+ unless AppOpticsAPM::API.blacklisted?(URI(url).hostname)
72
+ self.headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid
73
+ end
74
+ response = self.send(method, *args, &block)
75
+
76
+ kvs[:HTTPStatus] = response_code
77
+
78
+ # If we get a redirect, report the location header
79
+ if ((300..308).to_a.include? response_code) && headers.key?("Location")
80
+ kvs[:Location] = headers["Location"]
81
+ end
82
+
83
+ _, *response_headers = header_str.split(/[\r\n]+/).map(&:strip)
84
+ response_headers = Hash[response_headers.flat_map{ |s| s.scan(/^(\S+): (.+)/) }]
85
+
86
+ response_context = response_headers['X-Trace']
87
+ if response_context && !kvs[:blacklisted]
88
+ AppOpticsAPM::XTrace.continue_service_context(self.headers['X-Trace'], response_context)
89
+ end
90
+
91
+ response
92
+ rescue => e
93
+ AppOpticsAPM::API.log_exception(:curb, e)
94
+ raise e
95
+ ensure
96
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:curb][:collect_backtraces]
97
+ AppOpticsAPM::API.log_exit(:curb, kvs)
98
+ end
99
+ end
100
+
101
+ end # CurlUtility
102
+
103
+ # Instrumentation specific to ::Curl::Easy
104
+ module CurlEasy
105
+ # Common methods
106
+ include AppOpticsAPM::Inst::CurlUtility
107
+
108
+ def self.included(klass)
109
+ AppOpticsAPM::Util.method_alias(klass, :http, ::Curl::Easy)
110
+ AppOpticsAPM::Util.method_alias(klass, :perform, ::Curl::Easy)
111
+ AppOpticsAPM::Util.method_alias(klass, :http_put, ::Curl::Easy)
112
+ AppOpticsAPM::Util.method_alias(klass, :http_post, ::Curl::Easy)
113
+ end
114
+
115
+ ##
116
+ # http_post_with_appoptics
117
+ #
118
+ # ::Curl::Easy.new.http_post wrapper
119
+ #
120
+ def http_post_with_appoptics(*args, &block)
121
+ # If we're not tracing, just do a fast return.
122
+ if !AppOpticsAPM.tracing? || AppOpticsAPM.tracing_layer?(:curb)
123
+ unless AppOpticsAPM::API.blacklisted?(URI(url).hostname)
124
+ self.headers['X-Trace'] = AppOpticsAPM::Context.toString() if AppOpticsAPM::Context.isValid
125
+ end
126
+ return http_post_without_appoptics(*args)
127
+ end
128
+
129
+ kvs = {}
130
+ kvs[:HTTPMethod] = :POST
131
+
132
+ profile_curb_method(kvs, :http_post_without_appoptics, args, &block)
133
+ end
134
+
135
+ ##
136
+ # http_put_with_appoptics
137
+ #
138
+ # ::Curl::Easy.new.http_put wrapper
139
+ #
140
+ def http_put_with_appoptics(*args, &block)
141
+ # If we're not tracing, just do a fast return.
142
+ if !AppOpticsAPM.tracing? || AppOpticsAPM.tracing_layer?(:curb)
143
+ unless AppOpticsAPM::API.blacklisted?(URI(url).hostname)
144
+ self.headers['X-Trace'] = AppOpticsAPM::Context.toString() if AppOpticsAPM::Context.isValid
145
+ end
146
+ return http_put_without_appoptics(data)
147
+ end
148
+
149
+ kvs = {}
150
+ kvs[:HTTPMethod] = :PUT
151
+
152
+ profile_curb_method(kvs, :http_put_without_appoptics, args, &block)
153
+ end
154
+
155
+ ##
156
+ # perform_with_appoptics
157
+ #
158
+ # ::Curl::Easy.new.perform wrapper
159
+ #
160
+ def perform_with_appoptics(&block)
161
+ # If we're not tracing, just do a fast return.
162
+ # excluding curb layer: because the curb C code for easy.http calls perform,
163
+ # we have to make sure we don't log again
164
+ if !AppOpticsAPM.tracing? || AppOpticsAPM.tracing_layer?(:curb)
165
+ unless AppOpticsAPM::API.blacklisted?(URI(url).hostname)
166
+ self.headers['X-Trace'] = AppOpticsAPM::Context.toString() if AppOpticsAPM::Context.isValid
167
+ end
168
+ return perform_without_appoptics(&block)
169
+ end
170
+
171
+ kvs = {}
172
+ # This perform gets called from two places, ::Curl::Easy.new.perform
173
+ # and Curl::Easy.new.http_head. In the case of http_head we detect the
174
+ # HTTP verb via get info.
175
+ if self.getinfo(self.sym2curl(:nobody))
176
+ kvs[:HTTPMethod] = :HEAD
177
+ else
178
+ kvs[:HTTPMethod] = :GET
179
+ end
180
+
181
+ profile_curb_method(kvs, :perform_without_appoptics, nil, &block)
182
+ end
183
+
184
+ ##
185
+ # http_with_appoptics
186
+ #
187
+ # ::Curl::Easy.new.http wrapper
188
+ #
189
+ def http_with_appoptics(verb, &block)
190
+ # If we're not tracing, just do a fast return.
191
+ unless AppOpticsAPM.tracing?
192
+ unless AppOpticsAPM::API.blacklisted?(URI(url).hostname)
193
+ self.headers['X-Trace'] = AppOpticsAPM::Context.toString() if AppOpticsAPM::Context.isValid
194
+ end
195
+ return http_without_appoptics(verb)
196
+ end
197
+
198
+ kvs = {}
199
+ kvs[:HTTPMethod] = verb
200
+
201
+ profile_curb_method(kvs, :http_without_appoptics, [verb], &block)
202
+ end
203
+ end
204
+
205
+ ##
206
+ # CurlMultiCM
207
+ #
208
+ # This module contains the class method wrappers for the CurlMulti class.
209
+ # This module should be _extended_ by CurlMulti.
210
+ #
211
+ module CurlMultiCM
212
+ include AppOpticsAPM::Inst::CurlUtility
213
+
214
+ def self.extended(klass)
215
+ AppOpticsAPM::Util.class_method_alias(klass, :http, ::Curl::Multi)
216
+ end
217
+
218
+ ##
219
+ # http_with_appoptics
220
+ #
221
+ # ::Curl::Multi.new.http wrapper
222
+ #
223
+ def http_with_appoptics(urls_with_config, multi_options={}, &block)
224
+ # If we're not tracing, just do a fast return.
225
+ unless AppOpticsAPM.tracing?
226
+ urls_with_config.each do |conf|
227
+ unless AppOpticsAPM::API.blacklisted?(URI(conf[:url]).hostname)
228
+ conf[:headers] ||= {}
229
+ conf[:headers]['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid
230
+ end
231
+ end
232
+ return http_without_appoptics(urls_with_config, multi_options, &block)
233
+ end
234
+
235
+ begin
236
+ kvs = {}
237
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:curb][:collect_backtraces]
238
+
239
+ AppOpticsAPM::API.log_entry(:curb_multi, kvs)
240
+ context = AppOpticsAPM::Context.toString
241
+ urls_with_config.each do |conf|
242
+ unless AppOpticsAPM::API.blacklisted?(URI(conf[:url]).hostname)
243
+ conf[:headers] ||= {}
244
+ conf[:headers]['X-Trace'] = context if AppOpticsAPM::Context.isValid
245
+ end
246
+ end
247
+
248
+ traces = []
249
+ # The core curb call
250
+ http_without_appoptics(urls_with_config, multi_options) do |easy, response_code, method|
251
+ # this is the only way we can access the headers, they are not exposed otherwise
252
+ unless AppOpticsAPM::API.blacklisted?(URI(easy.url).hostname)
253
+ xtrace = easy.header_str.scan(/X-Trace: ([0-9A-F]*)/).map{ |m| m[0] }
254
+ traces << xtrace[0] unless xtrace.empty?
255
+ end
256
+ block.call(easy, response_code, method) if block
257
+ end
258
+ AppOpticsAPM::XTrace.continue_service_context(context, traces.pop) unless traces.empty?
259
+ rescue => e
260
+ AppOpticsAPM::API.log_exception(:curb_multi, e)
261
+ raise e
262
+ ensure
263
+ AppOpticsAPM::API.log_multi_exit(:curb_multi, traces)
264
+ end
265
+ end
266
+ end
267
+
268
+ ##
269
+ # CurlMultiIM
270
+ #
271
+ # This module contains the instance method wrappers for the CurlMulti class.
272
+ # This module should be _included_ into CurlMulti.
273
+ #
274
+ module CurlMultiIM
275
+ include AppOpticsAPM::Inst::CurlUtility
276
+
277
+ def self.included(klass)
278
+ AppOpticsAPM::Util.method_alias(klass, :perform, ::Curl::Multi)
279
+ end
280
+
281
+ ##
282
+ # perform_with_appoptics
283
+ #
284
+ # ::Curl::Multi.new.perform wrapper
285
+ #
286
+ # the reason we instrument this method is because it can be called directly,
287
+ # therefore we exclude calls that already have a curb layer assigned
288
+ # Be aware: this method is also called from the c-implementation
289
+ #
290
+ def perform_with_appoptics(&block)
291
+ # If we're not tracing or we're already tracing curb, just do a fast return.
292
+ if !AppOpticsAPM.tracing? || [:curb, :curb_multi].include?(AppOpticsAPM.layer)
293
+ self.requests.each do |_, request|
294
+ unless AppOpticsAPM::API.blacklisted?(URI(request.url).hostname)
295
+ request.headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid
296
+ end
297
+ end
298
+ return perform_without_appoptics(&block)
299
+ end
300
+
301
+ begin
302
+ kvs = {}
303
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:curb][:collect_backtraces]
304
+
305
+ AppOpticsAPM::API.log_entry(:curb_multi, kvs)
306
+
307
+ self.requests.each do |_, request|
308
+ unless AppOpticsAPM::API.blacklisted?(URI(request.url).hostname)
309
+ request.headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid
310
+ end
311
+ end
312
+
313
+ perform_without_appoptics(&block)
314
+ rescue => e
315
+ AppOpticsAPM::API.log_exception(:curb_multi, e)
316
+ raise e
317
+ ensure
318
+ AppOpticsAPM::API.log_exit(:curb_multi)
319
+ end
320
+ end
321
+ end
322
+ end
323
+ end
324
+
325
+ if AppOpticsAPM::Config[:curb][:enabled] && defined?(::Curl)
326
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting curb' if AppOpticsAPM::Config[:verbose]
327
+ AppOpticsAPM::Util.send_include(::Curl::Easy, AppOpticsAPM::Inst::CurlEasy)
328
+ AppOpticsAPM::Util.send_extend(::Curl::Multi, AppOpticsAPM::Inst::CurlMultiCM)
329
+ AppOpticsAPM::Util.send_include(::Curl::Multi, AppOpticsAPM::Inst::CurlMultiIM)
330
+ end
@@ -0,0 +1,85 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module Dalli
7
+ include AppOpticsAPM::API::Memcache
8
+
9
+ def self.included(cls)
10
+ cls.class_eval do
11
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting memcache (dalli)' if AppOpticsAPM::Config[:verbose]
12
+ if ::Dalli::Client.private_method_defined? :perform
13
+ alias perform_without_appoptics perform
14
+ alias perform perform_with_appoptics
15
+ else
16
+ AppOpticsAPM.logger.warn '[appoptics_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_appoptics get_multi
21
+ alias get_multi get_multi_with_appoptics
22
+ end
23
+ end
24
+ end
25
+
26
+ def perform_with_appoptics(*all_args, &blk)
27
+ op, key, *args = *all_args
28
+
29
+ report_kvs = {}
30
+ report_kvs[:KVOp] = op
31
+ report_kvs[:KVKey] = key
32
+ if @servers.is_a?(Array) && !@servers.empty?
33
+ report_kvs[:RemoteHost] = @servers.join(", ")
34
+ end
35
+
36
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:get_multi)
37
+ AppOpticsAPM::API.trace(:memcache, report_kvs) do
38
+ result = perform_without_appoptics(*all_args, &blk)
39
+
40
+ # Clear the hash for a potential info event
41
+ report_kvs.clear
42
+ report_kvs[:KVHit] = memcache_hit?(result) if op == :get && key.class == String
43
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:dalli][:collect_backtraces]
44
+
45
+ result
46
+ end
47
+ else
48
+ perform_without_appoptics(*all_args, &blk)
49
+ end
50
+ end
51
+
52
+ def get_multi_with_appoptics(*keys)
53
+ return get_multi_without_appoptics(*keys) unless AppOpticsAPM.tracing?
54
+
55
+ info_kvs = {}
56
+
57
+ begin
58
+ info_kvs[:KVKeyCount] = keys.flatten.length
59
+ info_kvs[:KVKeyCount] = (info_kvs[:KVKeyCount] - 1) if keys.last.is_a?(Hash) || keys.last.nil?
60
+ if @servers.is_a?(Array) && !@servers.empty?
61
+ info_kvs[:RemoteHost] = @servers.join(", ")
62
+ end
63
+ rescue => e
64
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
65
+ end
66
+
67
+ info_kvs[:KVOp] = :get_multi
68
+ info_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:dalli][:collect_backtraces]
69
+ AppOpticsAPM::API.trace(:memcache, info_kvs, :get_multi) do
70
+ values = get_multi_without_appoptics(*keys)
71
+
72
+ info_kvs[:KVHitCount] = values.length
73
+
74
+ values
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ if defined?(Dalli) && AppOpticsAPM::Config[:dalli][:enabled]
82
+ ::Dalli::Client.module_eval do
83
+ include AppOpticsAPM::Inst::Dalli
84
+ end
85
+ end
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ if defined?(Delayed)
5
+ module AppOpticsAPM
6
+ module Inst
7
+ module DelayedJob
8
+ ##
9
+ # ForkHandler
10
+ #
11
+ # Since delayed job doesn't offer a hook into `after_fork`, we alias the method
12
+ # here to do our magic after a fork happens.
13
+ #
14
+ module ForkHandler
15
+ def self.extended(klass)
16
+ AppOpticsAPM::Util.class_method_alias(klass, :after_fork, ::Delayed::Worker)
17
+ end
18
+
19
+ def after_fork_with_appoptics
20
+ AppOpticsAPM.logger.info '[appoptics_apm/delayed_job] Detected fork. Restarting AppOpticsAPM reporter.' if AppOpticsAPM::Config[:verbose]
21
+ AppOpticsAPM::Reporter.restart unless ENV.key?('APPOPTICS_GEM_TEST')
22
+
23
+ after_fork_without_appoptics
24
+ end
25
+ end
26
+
27
+ ##
28
+ # AppOpticsAPM::Inst::DelayedJob::Plugin
29
+ #
30
+ # The AppOpticsAPM DelayedJob plugin. Here we wrap `enqueue` and
31
+ # `perform` to capture the timing of the bits we're interested
32
+ # in.
33
+ #
34
+ class Plugin < Delayed::Plugin
35
+ callbacks do |lifecycle|
36
+
37
+ # enqueue
38
+ if AppOpticsAPM::Config[:delayed_jobclient][:enabled]
39
+ lifecycle.around(:enqueue) do |job, &block|
40
+ begin
41
+ report_kvs = {}
42
+ report_kvs[:Spec] = :pushq
43
+ report_kvs[:Flavor] = :DelayedJob
44
+ report_kvs[:JobName] = job.name
45
+ report_kvs[:MsgID] = job.id
46
+ report_kvs[:Queue] = job.queue if job.queue
47
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:delayed_jobclient][:collect_backtraces]
48
+
49
+ AppOpticsAPM::API.trace(:'delayed_job-client', report_kvs) do
50
+ block.call(job)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # invoke_job
57
+ if AppOpticsAPM::Config[:delayed_jobworker][:enabled]
58
+ lifecycle.around(:perform) do |worker, job, &block|
59
+ begin
60
+ report_kvs = {}
61
+ report_kvs[:Spec] = :job
62
+ report_kvs[:Flavor] = :DelayedJob
63
+ report_kvs[:JobName] = job.name
64
+ report_kvs[:MsgID] = job.id
65
+ report_kvs[:Queue] = job.queue if job.queue
66
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:delayed_jobworker][:collect_backtraces]
67
+
68
+ # DelayedJob Specific KVs
69
+ report_kvs[:priority] = job.priority
70
+ report_kvs[:attempts] = job.attempts
71
+ report_kvs[:WorkerName] = job.locked_by
72
+ rescue => e
73
+ AppOpticsAPM.logger.warn "[appoptics_apm/warning] inst/delayed_job.rb: #{e.message}"
74
+ end
75
+
76
+ AppOpticsAPM::SDK.start_trace(:'delayed_job-worker', nil, report_kvs) do
77
+ result = block.call(worker, job)
78
+ AppOpticsAPM::API.log_exception(:'delayed_job-worker', job.error) if job.error
79
+ result
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting delayed_job' if AppOpticsAPM::Config[:verbose]
90
+ AppOpticsAPM::Util.send_extend(::Delayed::Worker, AppOpticsAPM::Inst::DelayedJob::ForkHandler)
91
+ Delayed::Worker.plugins << AppOpticsAPM::Inst::DelayedJob::Plugin
92
+ end