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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +51 -0
- data/Appraisals +10 -0
- data/CHANGELOG.md +223 -0
- data/Gemfile +49 -0
- data/LICENSE +199 -0
- data/README.md +380 -0
- data/Rakefile +106 -0
- data/ext/oboe_metal/extconf.rb +61 -0
- data/ext/oboe_metal/noop/noop.c +7 -0
- data/ext/oboe_metal/src/bson/bson.h +221 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/oboe.h +275 -0
- data/ext/oboe_metal/src/oboe.hpp +352 -0
- data/ext/oboe_metal/src/oboe_wrap.cxx +3886 -0
- data/ext/oboe_metal/tests/test.rb +11 -0
- data/gemfiles/mongo.gemfile +33 -0
- data/gemfiles/moped.gemfile +33 -0
- data/get_version.rb +5 -0
- data/init.rb +4 -0
- data/lib/base.rb +99 -0
- data/lib/joboe_metal.rb +185 -0
- data/lib/method_profiling.rb +70 -0
- data/lib/oboe.rb +50 -0
- data/lib/oboe/api.rb +14 -0
- data/lib/oboe/api/layerinit.rb +99 -0
- data/lib/oboe/api/logging.rb +129 -0
- data/lib/oboe/api/memcache.rb +29 -0
- data/lib/oboe/api/profiling.rb +50 -0
- data/lib/oboe/api/tracing.rb +134 -0
- data/lib/oboe/api/util.rb +117 -0
- data/lib/oboe/config.rb +140 -0
- data/lib/oboe/frameworks/grape.rb +74 -0
- data/lib/oboe/frameworks/padrino.rb +66 -0
- data/lib/oboe/frameworks/padrino/templates.rb +59 -0
- data/lib/oboe/frameworks/rails.rb +139 -0
- data/lib/oboe/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
- data/lib/oboe/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
- data/lib/oboe/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
- data/lib/oboe/frameworks/rails/inst/action_controller.rb +123 -0
- data/lib/oboe/frameworks/rails/inst/action_view.rb +56 -0
- data/lib/oboe/frameworks/rails/inst/action_view_2x.rb +54 -0
- data/lib/oboe/frameworks/rails/inst/action_view_30.rb +48 -0
- data/lib/oboe/frameworks/rails/inst/active_record.rb +24 -0
- data/lib/oboe/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
- data/lib/oboe/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
- data/lib/oboe/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
- data/lib/oboe/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
- data/lib/oboe/frameworks/rails/inst/connection_adapters/utils.rb +118 -0
- data/lib/oboe/frameworks/sinatra.rb +96 -0
- data/lib/oboe/frameworks/sinatra/templates.rb +56 -0
- data/lib/oboe/inst/cassandra.rb +281 -0
- data/lib/oboe/inst/dalli.rb +75 -0
- data/lib/oboe/inst/http.rb +72 -0
- data/lib/oboe/inst/memcache.rb +105 -0
- data/lib/oboe/inst/memcached.rb +96 -0
- data/lib/oboe/inst/mongo.rb +240 -0
- data/lib/oboe/inst/moped.rb +474 -0
- data/lib/oboe/inst/rack.rb +81 -0
- data/lib/oboe/inst/redis.rb +273 -0
- data/lib/oboe/inst/resque.rb +193 -0
- data/lib/oboe/instrumentation.rb +18 -0
- data/lib/oboe/loading.rb +98 -0
- data/lib/oboe/logger.rb +41 -0
- data/lib/oboe/ruby.rb +11 -0
- data/lib/oboe/util.rb +129 -0
- data/lib/oboe/version.rb +13 -0
- data/lib/oboe/xtrace.rb +52 -0
- data/lib/oboe_metal.rb +140 -0
- data/lib/rails/generators/oboe/install_generator.rb +76 -0
- data/lib/rails/generators/oboe/templates/oboe_initializer.rb +94 -0
- data/oboe.gemspec +29 -0
- data/release.sh +65 -0
- data/test/frameworks/apps/grape_simple.rb +10 -0
- data/test/frameworks/apps/padrino_simple.rb +41 -0
- data/test/frameworks/apps/sinatra_simple.rb +20 -0
- data/test/frameworks/grape_test.rb +27 -0
- data/test/frameworks/padrino_test.rb +25 -0
- data/test/frameworks/sinatra_test.rb +25 -0
- data/test/instrumentation/cassandra_test.rb +381 -0
- data/test/instrumentation/dalli_test.rb +164 -0
- data/test/instrumentation/http_test.rb +97 -0
- data/test/instrumentation/memcache_test.rb +251 -0
- data/test/instrumentation/memcached_test.rb +226 -0
- data/test/instrumentation/mongo_test.rb +462 -0
- data/test/instrumentation/moped_test.rb +473 -0
- data/test/instrumentation/rack_test.rb +73 -0
- data/test/instrumentation/redis_hashes_test.rb +265 -0
- data/test/instrumentation/redis_keys_test.rb +318 -0
- data/test/instrumentation/redis_lists_test.rb +310 -0
- data/test/instrumentation/redis_misc_test.rb +160 -0
- data/test/instrumentation/redis_sets_test.rb +293 -0
- data/test/instrumentation/redis_sortedsets_test.rb +325 -0
- data/test/instrumentation/redis_strings_test.rb +333 -0
- data/test/instrumentation/resque_test.rb +62 -0
- data/test/minitest_helper.rb +148 -0
- data/test/profiling/method_test.rb +198 -0
- data/test/support/config_test.rb +39 -0
- data/test/support/liboboe_settings_test.rb +46 -0
- data/test/support/xtrace_test.rb +35 -0
- 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
|
+
|