oboe 2.7.0.3-java

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 (102) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +51 -0
  4. data/Appraisals +10 -0
  5. data/CHANGELOG.md +223 -0
  6. data/Gemfile +49 -0
  7. data/LICENSE +199 -0
  8. data/README.md +380 -0
  9. data/Rakefile +106 -0
  10. data/ext/oboe_metal/extconf.rb +61 -0
  11. data/ext/oboe_metal/noop/noop.c +7 -0
  12. data/ext/oboe_metal/src/bson/bson.h +221 -0
  13. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  14. data/ext/oboe_metal/src/oboe.h +275 -0
  15. data/ext/oboe_metal/src/oboe.hpp +352 -0
  16. data/ext/oboe_metal/src/oboe_wrap.cxx +3886 -0
  17. data/ext/oboe_metal/tests/test.rb +11 -0
  18. data/gemfiles/mongo.gemfile +33 -0
  19. data/gemfiles/moped.gemfile +33 -0
  20. data/get_version.rb +5 -0
  21. data/init.rb +4 -0
  22. data/lib/base.rb +99 -0
  23. data/lib/joboe_metal.rb +185 -0
  24. data/lib/method_profiling.rb +70 -0
  25. data/lib/oboe.rb +50 -0
  26. data/lib/oboe/api.rb +14 -0
  27. data/lib/oboe/api/layerinit.rb +99 -0
  28. data/lib/oboe/api/logging.rb +129 -0
  29. data/lib/oboe/api/memcache.rb +29 -0
  30. data/lib/oboe/api/profiling.rb +50 -0
  31. data/lib/oboe/api/tracing.rb +134 -0
  32. data/lib/oboe/api/util.rb +117 -0
  33. data/lib/oboe/config.rb +140 -0
  34. data/lib/oboe/frameworks/grape.rb +74 -0
  35. data/lib/oboe/frameworks/padrino.rb +66 -0
  36. data/lib/oboe/frameworks/padrino/templates.rb +59 -0
  37. data/lib/oboe/frameworks/rails.rb +139 -0
  38. data/lib/oboe/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  39. data/lib/oboe/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  40. data/lib/oboe/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  41. data/lib/oboe/frameworks/rails/inst/action_controller.rb +123 -0
  42. data/lib/oboe/frameworks/rails/inst/action_view.rb +56 -0
  43. data/lib/oboe/frameworks/rails/inst/action_view_2x.rb +54 -0
  44. data/lib/oboe/frameworks/rails/inst/action_view_30.rb +48 -0
  45. data/lib/oboe/frameworks/rails/inst/active_record.rb +24 -0
  46. data/lib/oboe/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  47. data/lib/oboe/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  48. data/lib/oboe/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  49. data/lib/oboe/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  50. data/lib/oboe/frameworks/rails/inst/connection_adapters/utils.rb +118 -0
  51. data/lib/oboe/frameworks/sinatra.rb +96 -0
  52. data/lib/oboe/frameworks/sinatra/templates.rb +56 -0
  53. data/lib/oboe/inst/cassandra.rb +281 -0
  54. data/lib/oboe/inst/dalli.rb +75 -0
  55. data/lib/oboe/inst/http.rb +72 -0
  56. data/lib/oboe/inst/memcache.rb +105 -0
  57. data/lib/oboe/inst/memcached.rb +96 -0
  58. data/lib/oboe/inst/mongo.rb +240 -0
  59. data/lib/oboe/inst/moped.rb +474 -0
  60. data/lib/oboe/inst/rack.rb +81 -0
  61. data/lib/oboe/inst/redis.rb +273 -0
  62. data/lib/oboe/inst/resque.rb +193 -0
  63. data/lib/oboe/instrumentation.rb +18 -0
  64. data/lib/oboe/loading.rb +98 -0
  65. data/lib/oboe/logger.rb +41 -0
  66. data/lib/oboe/ruby.rb +11 -0
  67. data/lib/oboe/util.rb +129 -0
  68. data/lib/oboe/version.rb +13 -0
  69. data/lib/oboe/xtrace.rb +52 -0
  70. data/lib/oboe_metal.rb +140 -0
  71. data/lib/rails/generators/oboe/install_generator.rb +76 -0
  72. data/lib/rails/generators/oboe/templates/oboe_initializer.rb +94 -0
  73. data/oboe.gemspec +29 -0
  74. data/release.sh +65 -0
  75. data/test/frameworks/apps/grape_simple.rb +10 -0
  76. data/test/frameworks/apps/padrino_simple.rb +41 -0
  77. data/test/frameworks/apps/sinatra_simple.rb +20 -0
  78. data/test/frameworks/grape_test.rb +27 -0
  79. data/test/frameworks/padrino_test.rb +25 -0
  80. data/test/frameworks/sinatra_test.rb +25 -0
  81. data/test/instrumentation/cassandra_test.rb +381 -0
  82. data/test/instrumentation/dalli_test.rb +164 -0
  83. data/test/instrumentation/http_test.rb +97 -0
  84. data/test/instrumentation/memcache_test.rb +251 -0
  85. data/test/instrumentation/memcached_test.rb +226 -0
  86. data/test/instrumentation/mongo_test.rb +462 -0
  87. data/test/instrumentation/moped_test.rb +473 -0
  88. data/test/instrumentation/rack_test.rb +73 -0
  89. data/test/instrumentation/redis_hashes_test.rb +265 -0
  90. data/test/instrumentation/redis_keys_test.rb +318 -0
  91. data/test/instrumentation/redis_lists_test.rb +310 -0
  92. data/test/instrumentation/redis_misc_test.rb +160 -0
  93. data/test/instrumentation/redis_sets_test.rb +293 -0
  94. data/test/instrumentation/redis_sortedsets_test.rb +325 -0
  95. data/test/instrumentation/redis_strings_test.rb +333 -0
  96. data/test/instrumentation/resque_test.rb +62 -0
  97. data/test/minitest_helper.rb +148 -0
  98. data/test/profiling/method_test.rb +198 -0
  99. data/test/support/config_test.rb +39 -0
  100. data/test/support/liboboe_settings_test.rb +46 -0
  101. data/test/support/xtrace_test.rb +35 -0
  102. metadata +200 -0
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ require 'uri'
5
+
6
+ module Oboe
7
+ class Rack
8
+ attr_reader :app
9
+
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ def collect(req, env)
15
+ report_kvs = {}
16
+
17
+ begin
18
+ report_kvs['HTTP-Host'] = req.host
19
+ report_kvs['Port'] = req.port
20
+ report_kvs['Proto'] = req.scheme
21
+ report_kvs['Query-String'] = URI.unescape(req.query_string) unless req.query_string.empty?
22
+ report_kvs[:URL] = URI.unescape(req.path)
23
+ report_kvs[:Method] = req.request_method
24
+ report_kvs['AJAX'] = true if req.xhr?
25
+ report_kvs['ClientIP'] = req.ip
26
+
27
+ report_kvs['X-TV-Meta'] = env['HTTP_X_TV_META'] if env.has_key?('HTTP_X_TV_META')
28
+
29
+ # Report any request queue'ing headers. Report as 'Request-Start' or the summed Queue-Time
30
+ report_kvs['Request-Start'] = env['HTTP_X_REQUEST_START'] if env.has_key?('HTTP_X_REQUEST_START')
31
+ report_kvs['Request-Start'] = env['HTTP_X_QUEUE_START'] if env.has_key?('HTTP_X_QUEUE_START')
32
+ report_kvs['Queue-Time'] = env['HTTP_X_QUEUE_TIME'] if env.has_key?('HTTP_X_QUEUE_TIME')
33
+
34
+ report_kvs['Forwarded-For'] = env['HTTP_X_FORWARDED_FOR'] if env.has_key?('HTTP_X_FORWARDED_FOR')
35
+ report_kvs['Forwarded-Host'] = env['HTTP_X_FORWARDED_HOST'] if env.has_key?('HTTP_X_FORWARDED_HOST')
36
+ report_kvs['Forwarded-Proto'] = env['HTTP_X_FORWARDED_PROTO'] if env.has_key?('HTTP_X_FORWARDED_PROTO')
37
+ report_kvs['Forwarded-Port'] = env['HTTP_X_FORWARDED_PORT'] if env.has_key?('HTTP_X_FORWARDED_PORT')
38
+
39
+ report_kvs['Ruby.Oboe.Version'] = ::Oboe::Version::STRING
40
+ rescue StandardError => e
41
+ # Discard any potential exceptions. Debug log and report whatever we can.
42
+ Oboe.logger.debug "[oboe/debug] Rack KV collection error: #{e.inspect}"
43
+ end
44
+ report_kvs
45
+ end
46
+
47
+ def call(env)
48
+ req = ::Rack::Request.new(env)
49
+
50
+ report_kvs = {}
51
+ report_kvs[:URL] = URI.unescape(req.path)
52
+
53
+ if Oboe.always?
54
+ # Only report these KVs under tracing_mode 'always' (never for 'through')
55
+ report_kvs[:SampleRate] = Oboe.sample_rate
56
+ report_kvs[:SampleSource] = Oboe.sample_source
57
+ end
58
+
59
+ xtrace = env.is_a?(Hash) ? env['HTTP_X_TRACE'] : nil
60
+
61
+ result, xtrace = Oboe::API.start_trace('rack', xtrace, report_kvs) do
62
+
63
+ status, headers, response = @app.call(env)
64
+
65
+ if Oboe.tracing?
66
+ report_kvs = collect(req, env)
67
+ Oboe::API.log(nil, 'info', report_kvs.merge!({ :Status => status }))
68
+ end
69
+
70
+ [status, headers, response]
71
+ end
72
+ rescue Exception => e
73
+ xtrace = e.instance_variable_get(:@xtrace)
74
+ raise
75
+ ensure
76
+ result[1]['X-Trace'] = xtrace if result and Oboe::XTrace.valid?(xtrace)
77
+ return result
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,273 @@
1
+ # Copyright (c) 2014 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module Oboe
5
+ module Inst
6
+ module Redis
7
+ module Client
8
+ # The operations listed in this constant skip collecting KVKey
9
+ NO_KEY_OPS = [ :keys, :randomkey, :scan, :sdiff, :sdiffstore, :sinter,
10
+ :sinterstore, :smove, :sunion, :sunionstore, :zinterstore,
11
+ :zunionstore, :publish, :select, :eval, :evalsha, :script ]
12
+
13
+ # Instead of a giant switch statement, we use a hash constant to map out what
14
+ # KVs need to be collected for each of the many many Redis operations
15
+ # Hash formatting by undiagnosed OCD
16
+ KV_COLLECT_MAP = {
17
+ :brpoplpush => { :destination => 2 }, :rpoplpush => { :destination => 2 },
18
+ :sdiffstore => { :destination => 1 }, :sinterstore => { :destination => 1 },
19
+ :sunionstore => { :destination => 1 }, :zinterstore => { :destination => 1 },
20
+ :zunionstore => { :destination => 1 }, :publish => { :channel => 1 },
21
+ :incrby => { :increment => 2 }, :incrbyfloat => { :increment => 2 },
22
+ :pexpire => { :milliseconds => 2 }, :pexpireat => { :milliseconds => 2 },
23
+ :expireat => { :timestamp => 2 }, :decrby => { :decrement => 2 },
24
+ :psetex => { :ttl => 2 }, :restore => { :ttl => 2 },
25
+ :setex => { :ttl => 2 }, :setnx => { :ttl => 2 },
26
+ :move => { :db => 2 }, :select => { :db => 1 },
27
+ :lindex => { :index => 2 }, :getset => { :value => 2 },
28
+ :keys => { :pattern => 1 }, :expire => { :seconds => 2 },
29
+ :rename => { :newkey => 2 }, :renamenx => { :newkey => 2 },
30
+ :getbit => { :offset => 2 }, :setbit => { :offset => 2 },
31
+ :setrange => { :offset => 2 }, :evalsha => { :sha => 1 },
32
+ :getrange => { :start => 2, :end => 3 },
33
+ :zrange => { :start => 2, :end => 3 },
34
+ :bitcount => { :start => 2, :stop => 3 },
35
+ :lrange => { :start => 2, :stop => 3 },
36
+ :zrevrange => { :start => 2, :stop => 3 },
37
+ :hincrby => { :field => 2, :increment => 3 },
38
+ :smove => { :source => 1, :destination => 2 },
39
+ :bitop => { :operation => 1, :destkey => 2 },
40
+ :hincrbyfloat => { :field => 2, :increment => 3 },
41
+ :zremrangebyrank => { :start => 2, :stop => 3 },
42
+ }
43
+
44
+ # The following operations don't require any special handling. For these,
45
+ # we only collect KVKey and KVOp
46
+ #
47
+ # :append, :blpop, :brpop, :decr, :del, :dump, :exists,
48
+ # :hgetall, :hkeys, :hlen, :hvals, :hmset, :incr, :linsert,
49
+ # :llen, :lpop, :lpush, :lpushx, :lrem, :lset, :ltrim,
50
+ # :persist, :pttl, :hscan, :rpop, :rpush, :rpushx, :sadd,
51
+ # :scard, :sismember, :smembers, :strlen, :sort, :spop,
52
+ # :srandmember, :srem, :sscan, :ttl, :type, :zadd, :zcard,
53
+ # :zcount, :zincrby, :zrangebyscore, :zrank, :zrem,
54
+ # :zremrangebyscore, :zrevrank, :zrevrangebyscore, :zscore
55
+ #
56
+ # For the operations in NO_KEY_OPS (above) we only collect
57
+ # KVOp (no KVKey)
58
+
59
+ def self.included(klass)
60
+ # We wrap two of the Redis methods to instrument
61
+ # operations
62
+ ::Oboe::Util.method_alias(klass, :call, ::Redis::Client)
63
+ ::Oboe::Util.method_alias(klass, :call_pipeline, ::Redis::Client)
64
+ end
65
+
66
+ # Given any Redis operation command array, this method
67
+ # extracts the Key/Values to report to the TraceView
68
+ # dashboard.
69
+ #
70
+ # @param command [Array] the Redis operation array
71
+ # @param r [Return] the return value from the operation
72
+ # @return [Hash] the Key/Values to report
73
+ def extract_trace_details(command, r)
74
+ kvs = {}
75
+ op = command.first
76
+
77
+ begin
78
+ kvs[:KVOp] = command[0]
79
+ kvs[:RemoteHost] = @options[:host]
80
+
81
+ unless NO_KEY_OPS.include? op or (command[1].is_a?(Array) and command[1].count > 1)
82
+ if command[1].is_a?(Array)
83
+ kvs[:KVKey] = command[1].first
84
+ else
85
+ kvs[:KVKey] = command[1]
86
+ end
87
+ end
88
+
89
+ if KV_COLLECT_MAP[op]
90
+ # Extract KVs from command for this op
91
+ KV_COLLECT_MAP[op].each { |k, v|
92
+ kvs[k] = command[v]
93
+ }
94
+ else
95
+ # This case statement handle special cases not handled
96
+ # by KV_COLLECT_MAP
97
+ case op
98
+ when :set
99
+ if command.count > 3
100
+ options = command[3]
101
+ kvs[:ex] = options[:ex] if options.has_key?(:ex)
102
+ kvs[:px] = options[:px] if options.has_key?(:px)
103
+ kvs[:nx] = options[:nx] if options.has_key?(:nx)
104
+ kvs[:xx] = options[:xx] if options.has_key?(:xx)
105
+ end
106
+
107
+ when :get
108
+ kvs[:KVHit] = r.nil? ? 0 : 1
109
+
110
+ when :hdel, :hexists, :hget, :hset, :hsetnx
111
+ kvs[:field] = command[2] unless command[2].is_a?(Array)
112
+ if op == :hget
113
+ kvs[:KVHit] = r.nil? ? 0 : 1
114
+ end
115
+
116
+ when :eval
117
+ if command[1].length > 1024
118
+ kvs[:Script] = command[1][0..1023] + "(...snip...)"
119
+ else
120
+ kvs[:Script] = command[1]
121
+ end
122
+
123
+ when :script
124
+ kvs[:subcommand] = command[1]
125
+ kvs[:Backtrace] = Oboe::API.backtrace if Oboe::Config[:redis][:collect_backtraces]
126
+ if command[1] == "load"
127
+ if command[1].length > 1024
128
+ kvs[:Script] = command[2][0..1023] + "(...snip...)"
129
+ else
130
+ kvs[:Script] = command[2]
131
+ end
132
+ elsif command[1] == :exists
133
+ if command[2].is_a?(Array)
134
+ kvs[:KVKey] = command[2].inspect
135
+ else
136
+ kvs[:KVKey] = command[2]
137
+ end
138
+ end
139
+
140
+ when :mget
141
+ if command[1].is_a?(Array)
142
+ kvs[:KVKeyCount] = command[1].count
143
+ else
144
+ kvs[:KVKeyCount] = command.count - 1
145
+ end
146
+ values = r.select{ |i| i }
147
+ kvs[:KVHitCount] = values.count
148
+
149
+ when :hmget
150
+ kvs[:KVKeyCount] = command.count - 2
151
+ values = r.select{ |i| i }
152
+ kvs[:KVHitCount] = values.count
153
+
154
+ when :mset, :msetnx
155
+ if command[1].is_a?(Array)
156
+ kvs[:KVKeyCount] = command[1].count / 2
157
+ else
158
+ kvs[:KVKeyCount] = (command.count - 1) / 2
159
+ end
160
+ end # case op
161
+ end # if KV_COLLECT_MAP[op]
162
+
163
+ rescue StandardError => e
164
+ Oboe.logger.debug "Error collecting redis KVs: #{e.message}"
165
+ Oboe.logger.debug e.backtrace.join("\n")
166
+ end
167
+
168
+ kvs
169
+ end
170
+
171
+ # Extracts the Key/Values to report from a pipelined
172
+ # call to the TraceView dashboard.
173
+ #
174
+ # @param pipeline [Redis::Pipeline] the Redis pipeline instance
175
+ # @return [Hash] the Key/Values to report
176
+ def extract_pipeline_details(pipeline)
177
+ kvs = {}
178
+
179
+ begin
180
+ kvs[:RemoteHost] = @options[:host]
181
+ kvs[:Backtrace] = Oboe::API.backtrace if Oboe::Config[:redis][:collect_backtraces]
182
+
183
+ command_count = pipeline.commands.count
184
+ kvs[:KVOpCount] = command_count
185
+
186
+ if pipeline.commands.first == :multi
187
+ kvs[:KVOp] = :multi
188
+ else
189
+ kvs[:KVOp] = :pipeline
190
+ end
191
+
192
+ # Report pipelined operations if the number
193
+ # of ops is reasonable
194
+ if command_count < 12
195
+ ops = []
196
+ pipeline.commands.each do |c|
197
+ ops << c.first
198
+ end
199
+ kvs[:KVOps] = ops.join(", ")
200
+ end
201
+ rescue StandardError => e
202
+ Oboe.logger.debug "[oboe/debug] Error extracting pipelined commands: #{e.message}"
203
+ Oboe.logger.debug e.backtrace
204
+ end
205
+ kvs
206
+ end
207
+
208
+ #
209
+ # The wrapper method for Redis::Client.call. Here
210
+ # (when tracing) we capture KVs to report and pass
211
+ # the call along
212
+ #
213
+ def call_with_oboe(command, &block)
214
+ if Oboe.tracing?
215
+ ::Oboe::API.log_entry('redis', {})
216
+
217
+ begin
218
+ r = call_without_oboe(command, &block)
219
+ report_kvs = extract_trace_details(command, r)
220
+ r
221
+ rescue StandardError => e
222
+ ::Oboe::API.log_exception('redis', e)
223
+ raise
224
+ ensure
225
+ ::Oboe::API.log_exit('redis', report_kvs)
226
+ end
227
+
228
+ else
229
+ call_without_oboe(command, &block)
230
+ end
231
+ end
232
+
233
+ #
234
+ # The wrapper method for Redis::Client.call_pipeline. Here
235
+ # (when tracing) we capture KVs to report and pass the call along
236
+ #
237
+ def call_pipeline_with_oboe(pipeline)
238
+ if Oboe.tracing?
239
+ report_kvs = {}
240
+
241
+ # Fall back to the raw tracing API so we can pass KVs
242
+ # back on exit (a limitation of the Oboe::API.trace
243
+ # block method) This removes the need for an info
244
+ # event to send additonal KVs
245
+ ::Oboe::API.log_entry('redis', {})
246
+
247
+ report_kvs = extract_pipeline_details(pipeline)
248
+
249
+ begin
250
+ call_pipeline_without_oboe(pipeline)
251
+ rescue StandardError => e
252
+ ::Oboe::API.log_exception('redis', e)
253
+ raise
254
+ ensure
255
+ ::Oboe::API.log_exit('redis', report_kvs)
256
+ end
257
+ else
258
+ call_pipeline_without_oboe(pipeline)
259
+ end
260
+ end
261
+
262
+ end
263
+ end
264
+ end
265
+ end
266
+
267
+ if Oboe::Config[:redis][:enabled]
268
+ if defined?(::Redis) and Gem::Version.new(::Redis::VERSION) >= Gem::Version.new('3.0.0')
269
+ Oboe.logger.info "[oboe/loading] Instrumenting redis" if Oboe::Config[:verbose]
270
+ ::Oboe::Util.send_include(::Redis::Client, ::Oboe::Inst::Redis::Client)
271
+ end
272
+ end
273
+
@@ -0,0 +1,193 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ require 'socket'
5
+ require 'json'
6
+
7
+ module Oboe
8
+ module Inst
9
+ module Resque
10
+
11
+ def self.included(base)
12
+ base.send :extend, ::Resque
13
+ end
14
+
15
+ def extract_trace_details(op, klass, args)
16
+ report_kvs = {}
17
+
18
+ begin
19
+ report_kvs[:Op] = op.to_s
20
+ report_kvs[:Class] = klass.to_s if klass
21
+
22
+ if Oboe::Config[:resque][:log_args]
23
+ kv_args = args.to_json
24
+
25
+ # Limit the argument json string to 1024 bytes
26
+ if kv_args.length > 1024
27
+ report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
28
+ else
29
+ report_kvs[:Args] = kv_args
30
+ end
31
+ end
32
+
33
+ report_kvs[:Backtrace] = Oboe::API.backtrace if Oboe::Config[:resque][:collect_backtraces]
34
+ rescue
35
+ end
36
+
37
+ report_kvs
38
+ end
39
+
40
+ def enqueue_with_oboe(klass, *args)
41
+ if Oboe.tracing?
42
+ report_kvs = extract_trace_details(:enqueue, klass, args)
43
+
44
+ Oboe::API.trace('resque-client', report_kvs, :enqueue) do
45
+ args.push({:parent_trace_id => Oboe::Context.toString}) if Oboe::Config[:resque][:link_workers]
46
+ enqueue_without_oboe(klass, *args)
47
+ end
48
+ else
49
+ enqueue_without_oboe(klass, *args)
50
+ end
51
+ end
52
+
53
+ def enqueue_to_with_oboe(queue, klass, *args)
54
+ if Oboe.tracing? and not Oboe.tracing_layer_op?(:enqueue)
55
+ report_kvs = extract_trace_details(:enqueue_to, klass, args)
56
+ report_kvs[:Queue] = queue.to_s if queue
57
+
58
+ Oboe::API.trace('resque-client', report_kvs) do
59
+ args.push({:parent_trace_id => Oboe::Context.toString}) if Oboe::Config[:resque][:link_workers]
60
+ enqueue_to_without_oboe(queue, klass, *args)
61
+ end
62
+ else
63
+ enqueue_to_without_oboe(queue, klass, *args)
64
+ end
65
+ end
66
+
67
+ def dequeue_with_oboe(klass, *args)
68
+ if Oboe.tracing?
69
+ report_kvs = extract_trace_details(:dequeue, klass, args)
70
+
71
+ Oboe::API.trace('resque-client', report_kvs) do
72
+ dequeue_without_oboe(klass, *args)
73
+ end
74
+ else
75
+ dequeue_without_oboe(klass, *args)
76
+ end
77
+ end
78
+ end
79
+
80
+ module ResqueWorker
81
+ def perform_with_oboe(job)
82
+ report_kvs = {}
83
+ last_arg = nil
84
+
85
+ begin
86
+ report_kvs[:Op] = :perform
87
+
88
+ # Set these keys for the ability to separate out
89
+ # background tasks into a separate app on the server-side UI
90
+ report_kvs[:Controller] = :Resque
91
+ report_kvs[:Action] = :perform
92
+
93
+ report_kvs['HTTP-Host'] = Socket.gethostname
94
+ report_kvs[:URL] = '/resque/' + job.queue
95
+ report_kvs[:Method] = 'NONE'
96
+ report_kvs[:Queue] = job.queue
97
+
98
+ report_kvs[:Class] = job.payload['class']
99
+
100
+ if Oboe::Config[:resque][:log_args]
101
+ kv_args = job.payload['args'].to_json
102
+
103
+ # Limit the argument json string to 1024 bytes
104
+ if kv_args.length > 1024
105
+ report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
106
+ else
107
+ report_kvs[:Args] = kv_args
108
+ end
109
+ end
110
+
111
+ last_arg = job.payload['args'].last
112
+ rescue
113
+ end
114
+
115
+ if last_arg.is_a?(Hash) and last_arg.has_key?('parent_trace_id')
116
+ begin
117
+ # Since the enqueue was traced, we force trace the actual job execution and reference
118
+ # the enqueue trace with ParentTraceID
119
+ report_kvs[:ParentTraceID] = last_arg['parent_trace_id']
120
+ job.payload['args'].pop
121
+
122
+ rescue
123
+ end
124
+
125
+ # Force this trace regardless of sampling rate so that child trace can be
126
+ # link to parent trace.
127
+ Oboe::API.start_trace('resque-worker', nil, report_kvs.merge('Force' => true)) do
128
+ perform_without_oboe(job)
129
+ end
130
+
131
+ else
132
+ Oboe::API.start_trace('resque-worker', nil, report_kvs) do
133
+ perform_without_oboe(job)
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ module ResqueJob
140
+ def fail_with_oboe(exception)
141
+ if Oboe.tracing?
142
+ Oboe::API.log_exception('resque', exception)
143
+ end
144
+ fail_without_oboe(exception)
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ if defined?(::Resque)
151
+ Oboe.logger.info "[oboe/loading] Instrumenting resque" if Oboe::Config[:verbose]
152
+
153
+ ::Resque.module_eval do
154
+ include Oboe::Inst::Resque
155
+
156
+ [ :enqueue, :enqueue_to, :dequeue ].each do |m|
157
+ if method_defined?(m)
158
+ module_eval "alias #{m}_without_oboe #{m}"
159
+ module_eval "alias #{m} #{m}_with_oboe"
160
+ elsif Oboe::Config[:verbose]
161
+ Oboe.logger.warn "[oboe/loading] Couldn't properly instrument Resque (#{m}). Partial traces may occur."
162
+ end
163
+ end
164
+ end
165
+
166
+ if defined?(::Resque::Worker)
167
+ ::Resque::Worker.class_eval do
168
+ include Oboe::Inst::ResqueWorker
169
+
170
+ if method_defined?(:perform)
171
+ alias perform_without_oboe perform
172
+ alias perform perform_with_oboe
173
+ elsif Oboe::Config[:verbose]
174
+ Oboe.logger.warn "[oboe/loading] Couldn't properly instrument ResqueWorker (perform). Partial traces may occur."
175
+ end
176
+ end
177
+ end
178
+
179
+ if defined?(::Resque::Job)
180
+ ::Resque::Job.class_eval do
181
+ include Oboe::Inst::ResqueJob
182
+
183
+ if method_defined?(:fail)
184
+ alias fail_without_oboe fail
185
+ alias fail fail_with_oboe
186
+ elsif Oboe::Config[:verbose]
187
+ Oboe.logger.warn "[oboe/loading] Couldn't properly instrument ResqueWorker (fail). Partial traces may occur."
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+