appoptics_apm_mnfst 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
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