traceview 3.0.0-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 +10 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +58 -0
- data/Appraisals +10 -0
- data/CHANGELOG.md +490 -0
- data/CONFIG.md +16 -0
- data/Gemfile +95 -0
- data/LICENSE +199 -0
- data/README.md +380 -0
- data/Rakefile +109 -0
- data/examples/DNT.md +35 -0
- data/examples/carrying_context.rb +225 -0
- data/examples/instrumenting_metal_controller.rb +8 -0
- data/examples/puma_on_heroku_config.rb +17 -0
- data/examples/tracing_async_threads.rb +125 -0
- data/examples/tracing_background_jobs.rb +52 -0
- data/examples/tracing_forked_processes.rb +100 -0
- data/examples/unicorn_on_heroku_config.rb +28 -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/joboe_metal.rb +206 -0
- data/lib/oboe/README +2 -0
- data/lib/oboe/backward_compatibility.rb +59 -0
- data/lib/oboe/inst/rack.rb +11 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +151 -0
- data/lib/rails/generators/traceview/install_generator.rb +76 -0
- data/lib/rails/generators/traceview/templates/traceview_initializer.rb +159 -0
- data/lib/traceview/api/layerinit.rb +51 -0
- data/lib/traceview/api/logging.rb +209 -0
- data/lib/traceview/api/memcache.rb +31 -0
- data/lib/traceview/api/profiling.rb +50 -0
- data/lib/traceview/api/tracing.rb +135 -0
- data/lib/traceview/api/util.rb +121 -0
- data/lib/traceview/api.rb +18 -0
- data/lib/traceview/base.rb +225 -0
- data/lib/traceview/config.rb +238 -0
- data/lib/traceview/frameworks/grape.rb +97 -0
- data/lib/traceview/frameworks/padrino/templates.rb +58 -0
- data/lib/traceview/frameworks/padrino.rb +64 -0
- data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
- data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
- data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
- data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
- data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
- data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
- data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
- data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
- data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
- data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
- data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
- data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
- data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
- data/lib/traceview/frameworks/rails.rb +145 -0
- data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
- data/lib/traceview/frameworks/sinatra.rb +95 -0
- data/lib/traceview/inst/cassandra.rb +279 -0
- data/lib/traceview/inst/dalli.rb +86 -0
- data/lib/traceview/inst/em-http-request.rb +99 -0
- data/lib/traceview/inst/excon.rb +111 -0
- data/lib/traceview/inst/faraday.rb +73 -0
- data/lib/traceview/inst/http.rb +87 -0
- data/lib/traceview/inst/httpclient.rb +173 -0
- data/lib/traceview/inst/memcache.rb +102 -0
- data/lib/traceview/inst/memcached.rb +94 -0
- data/lib/traceview/inst/mongo.rb +238 -0
- data/lib/traceview/inst/moped.rb +474 -0
- data/lib/traceview/inst/rack.rb +122 -0
- data/lib/traceview/inst/redis.rb +271 -0
- data/lib/traceview/inst/resque.rb +192 -0
- data/lib/traceview/inst/rest-client.rb +38 -0
- data/lib/traceview/inst/sequel.rb +162 -0
- data/lib/traceview/inst/typhoeus.rb +102 -0
- data/lib/traceview/instrumentation.rb +21 -0
- data/lib/traceview/loading.rb +94 -0
- data/lib/traceview/logger.rb +41 -0
- data/lib/traceview/method_profiling.rb +84 -0
- data/lib/traceview/ruby.rb +36 -0
- data/lib/traceview/support.rb +113 -0
- data/lib/traceview/thread_local.rb +26 -0
- data/lib/traceview/util.rb +250 -0
- data/lib/traceview/version.rb +16 -0
- data/lib/traceview/xtrace.rb +90 -0
- data/lib/traceview.rb +62 -0
- data/test/frameworks/apps/grape_nested.rb +30 -0
- data/test/frameworks/apps/grape_simple.rb +24 -0
- data/test/frameworks/apps/padrino_simple.rb +45 -0
- data/test/frameworks/apps/sinatra_simple.rb +24 -0
- data/test/frameworks/grape_test.rb +142 -0
- data/test/frameworks/padrino_test.rb +30 -0
- data/test/frameworks/sinatra_test.rb +30 -0
- data/test/instrumentation/cassandra_test.rb +380 -0
- data/test/instrumentation/dalli_test.rb +171 -0
- data/test/instrumentation/em_http_request_test.rb +86 -0
- data/test/instrumentation/excon_test.rb +207 -0
- data/test/instrumentation/faraday_test.rb +235 -0
- data/test/instrumentation/http_test.rb +140 -0
- data/test/instrumentation/httpclient_test.rb +296 -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 +496 -0
- data/test/instrumentation/rack_test.rb +116 -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/instrumentation/rest-client_test.rb +294 -0
- data/test/instrumentation/sequel_mysql2_test.rb +326 -0
- data/test/instrumentation/sequel_mysql_test.rb +326 -0
- data/test/instrumentation/sequel_pg_test.rb +330 -0
- data/test/instrumentation/typhoeus_test.rb +285 -0
- data/test/minitest_helper.rb +187 -0
- data/test/profiling/method_test.rb +198 -0
- data/test/servers/rackapp_8101.rb +22 -0
- data/test/support/backcompat_test.rb +269 -0
- data/test/support/config_test.rb +128 -0
- data/test/support/dnt_test.rb +73 -0
- data/test/support/liboboe_settings_test.rb +104 -0
- data/test/support/xtrace_test.rb +35 -0
- data/traceview.gemspec +29 -0
- metadata +248 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Copyright (c) 2014 AppNeta, Inc.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module TraceView
|
|
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
|
+
::TraceView::Util.method_alias(klass, :call, ::Redis::Client)
|
|
63
|
+
::TraceView::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) || (command[1].is_a?(Array) && 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.key?(:ex)
|
|
102
|
+
kvs[:px] = options[:px] if options.key?(:px)
|
|
103
|
+
kvs[:nx] = options[:nx] if options.key?(:nx)
|
|
104
|
+
kvs[:xx] = options[:xx] if options.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] = TraceView::API.backtrace if TraceView::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
|
+
TraceView.logger.debug "Error collecting redis KVs: #{e.message}"
|
|
165
|
+
TraceView.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] = TraceView::API.backtrace if TraceView::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
|
+
TraceView.logger.debug "[traceview/debug] Error extracting pipelined commands: #{e.message}"
|
|
203
|
+
TraceView.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_traceview(command, &block)
|
|
214
|
+
if TraceView.tracing?
|
|
215
|
+
::TraceView::API.log_entry('redis', {})
|
|
216
|
+
|
|
217
|
+
begin
|
|
218
|
+
r = call_without_traceview(command, &block)
|
|
219
|
+
report_kvs = extract_trace_details(command, r)
|
|
220
|
+
r
|
|
221
|
+
rescue StandardError => e
|
|
222
|
+
::TraceView::API.log_exception('redis', e)
|
|
223
|
+
raise
|
|
224
|
+
ensure
|
|
225
|
+
::TraceView::API.log_exit('redis', report_kvs)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
else
|
|
229
|
+
call_without_traceview(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_traceview(pipeline)
|
|
238
|
+
if TraceView.tracing?
|
|
239
|
+
# Fall back to the raw tracing API so we can pass KVs
|
|
240
|
+
# back on exit (a limitation of the TraceView::API.trace
|
|
241
|
+
# block method) This removes the need for an info
|
|
242
|
+
# event to send additonal KVs
|
|
243
|
+
::TraceView::API.log_entry('redis', {})
|
|
244
|
+
|
|
245
|
+
report_kvs = extract_pipeline_details(pipeline)
|
|
246
|
+
|
|
247
|
+
begin
|
|
248
|
+
call_pipeline_without_traceview(pipeline)
|
|
249
|
+
rescue StandardError => e
|
|
250
|
+
::TraceView::API.log_exception('redis', e)
|
|
251
|
+
raise
|
|
252
|
+
ensure
|
|
253
|
+
::TraceView::API.log_exit('redis', report_kvs)
|
|
254
|
+
end
|
|
255
|
+
else
|
|
256
|
+
call_pipeline_without_traceview(pipeline)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
if TraceView::Config[:redis][:enabled]
|
|
266
|
+
if defined?(::Redis) && Gem::Version.new(::Redis::VERSION) >= Gem::Version.new('3.0.0')
|
|
267
|
+
TraceView.logger.info '[traceview/loading] Instrumenting redis' if TraceView::Config[:verbose]
|
|
268
|
+
::TraceView::Util.send_include(::Redis::Client, ::TraceView::Inst::Redis::Client)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Copyright (c) 2013 AppNeta, Inc.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
require 'socket'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
module TraceView
|
|
8
|
+
module Inst
|
|
9
|
+
module Resque
|
|
10
|
+
def self.included(base)
|
|
11
|
+
base.send :extend, ::Resque
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def extract_trace_details(op, klass, args)
|
|
15
|
+
report_kvs = {}
|
|
16
|
+
|
|
17
|
+
begin
|
|
18
|
+
report_kvs[:Op] = op.to_s
|
|
19
|
+
report_kvs[:Class] = klass.to_s if klass
|
|
20
|
+
|
|
21
|
+
if TraceView::Config[:resque][:log_args]
|
|
22
|
+
kv_args = args.to_json
|
|
23
|
+
|
|
24
|
+
# Limit the argument json string to 1024 bytes
|
|
25
|
+
if kv_args.length > 1024
|
|
26
|
+
report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
|
|
27
|
+
else
|
|
28
|
+
report_kvs[:Args] = kv_args
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
report_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:resque][:collect_backtraces]
|
|
33
|
+
rescue
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
report_kvs
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def enqueue_with_traceview(klass, *args)
|
|
40
|
+
if TraceView.tracing?
|
|
41
|
+
report_kvs = extract_trace_details(:enqueue, klass, args)
|
|
42
|
+
|
|
43
|
+
TraceView::API.trace('resque-client', report_kvs, :enqueue) do
|
|
44
|
+
args.push(:parent_trace_id => TraceView::Context.toString) if TraceView::Config[:resque][:link_workers]
|
|
45
|
+
enqueue_without_traceview(klass, *args)
|
|
46
|
+
end
|
|
47
|
+
else
|
|
48
|
+
enqueue_without_traceview(klass, *args)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def enqueue_to_with_traceview(queue, klass, *args)
|
|
53
|
+
if TraceView.tracing? && !TraceView.tracing_layer_op?(:enqueue)
|
|
54
|
+
report_kvs = extract_trace_details(:enqueue_to, klass, args)
|
|
55
|
+
report_kvs[:Queue] = queue.to_s if queue
|
|
56
|
+
|
|
57
|
+
TraceView::API.trace('resque-client', report_kvs) do
|
|
58
|
+
args.push(:parent_trace_id => TraceView::Context.toString) if TraceView::Config[:resque][:link_workers]
|
|
59
|
+
enqueue_to_without_traceview(queue, klass, *args)
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
enqueue_to_without_traceview(queue, klass, *args)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def dequeue_with_traceview(klass, *args)
|
|
67
|
+
if TraceView.tracing?
|
|
68
|
+
report_kvs = extract_trace_details(:dequeue, klass, args)
|
|
69
|
+
|
|
70
|
+
TraceView::API.trace('resque-client', report_kvs) do
|
|
71
|
+
dequeue_without_traceview(klass, *args)
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
dequeue_without_traceview(klass, *args)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module ResqueWorker
|
|
80
|
+
def perform_with_traceview(job)
|
|
81
|
+
report_kvs = {}
|
|
82
|
+
last_arg = nil
|
|
83
|
+
|
|
84
|
+
begin
|
|
85
|
+
report_kvs[:Op] = :perform
|
|
86
|
+
|
|
87
|
+
# Set these keys for the ability to separate out
|
|
88
|
+
# background tasks into a separate app on the server-side UI
|
|
89
|
+
report_kvs[:Controller] = :Resque
|
|
90
|
+
report_kvs[:Action] = :perform
|
|
91
|
+
|
|
92
|
+
report_kvs['HTTP-Host'] = Socket.gethostname
|
|
93
|
+
report_kvs[:URL] = '/resque/' + job.queue
|
|
94
|
+
report_kvs[:Method] = 'NONE'
|
|
95
|
+
report_kvs[:Queue] = job.queue
|
|
96
|
+
|
|
97
|
+
report_kvs[:Class] = job.payload['class']
|
|
98
|
+
|
|
99
|
+
if TraceView::Config[:resque][:log_args]
|
|
100
|
+
kv_args = job.payload['args'].to_json
|
|
101
|
+
|
|
102
|
+
# Limit the argument json string to 1024 bytes
|
|
103
|
+
if kv_args.length > 1024
|
|
104
|
+
report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
|
|
105
|
+
else
|
|
106
|
+
report_kvs[:Args] = kv_args
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
last_arg = job.payload['args'].last
|
|
111
|
+
rescue
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
if last_arg.is_a?(Hash) && last_arg.key?('parent_trace_id')
|
|
115
|
+
begin
|
|
116
|
+
# Since the enqueue was traced, we force trace the actual job execution and reference
|
|
117
|
+
# the enqueue trace with ParentTraceID
|
|
118
|
+
report_kvs[:ParentTraceID] = last_arg['parent_trace_id']
|
|
119
|
+
job.payload['args'].pop
|
|
120
|
+
|
|
121
|
+
rescue
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Force this trace regardless of sampling rate so that child trace can be
|
|
125
|
+
# link to parent trace.
|
|
126
|
+
TraceView::API.start_trace('resque-worker', nil, report_kvs.merge('Force' => true)) do
|
|
127
|
+
perform_without_traceview(job)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
else
|
|
131
|
+
TraceView::API.start_trace('resque-worker', nil, report_kvs) do
|
|
132
|
+
perform_without_traceview(job)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
module ResqueJob
|
|
139
|
+
def fail_with_traceview(exception)
|
|
140
|
+
if TraceView.tracing?
|
|
141
|
+
TraceView::API.log_exception('resque', exception)
|
|
142
|
+
end
|
|
143
|
+
fail_without_traceview(exception)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
if defined?(::Resque)
|
|
150
|
+
TraceView.logger.info '[traceview/loading] Instrumenting resque' if TraceView::Config[:verbose]
|
|
151
|
+
|
|
152
|
+
::Resque.module_eval do
|
|
153
|
+
include TraceView::Inst::Resque
|
|
154
|
+
|
|
155
|
+
[:enqueue, :enqueue_to, :dequeue].each do |m|
|
|
156
|
+
if method_defined?(m)
|
|
157
|
+
module_eval "alias #{m}_without_traceview #{m}"
|
|
158
|
+
module_eval "alias #{m} #{m}_with_traceview"
|
|
159
|
+
elsif TraceView::Config[:verbose]
|
|
160
|
+
TraceView.logger.warn "[traceview/loading] Couldn't properly instrument Resque (#{m}). Partial traces may occur."
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
if defined?(::Resque::Worker)
|
|
166
|
+
::Resque::Worker.class_eval do
|
|
167
|
+
include TraceView::Inst::ResqueWorker
|
|
168
|
+
|
|
169
|
+
if method_defined?(:perform)
|
|
170
|
+
alias perform_without_traceview perform
|
|
171
|
+
alias perform perform_with_traceview
|
|
172
|
+
elsif TraceView::Config[:verbose]
|
|
173
|
+
TraceView.logger.warn '[traceview/loading] Couldn\'t properly instrument ResqueWorker (perform). Partial traces may occur.'
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
if defined?(::Resque::Job)
|
|
179
|
+
::Resque::Job.class_eval do
|
|
180
|
+
include TraceView::Inst::ResqueJob
|
|
181
|
+
|
|
182
|
+
if method_defined?(:fail)
|
|
183
|
+
alias fail_without_traceview fail
|
|
184
|
+
alias fail fail_with_traceview
|
|
185
|
+
elsif TraceView::Config[:verbose]
|
|
186
|
+
TraceView.logger.warn '[traceview/loading] Couldn\'t properly instrument ResqueWorker (fail). Partial traces may occur.'
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Copyright (c) 2015 AppNeta, Inc.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module TraceView
|
|
5
|
+
module Inst
|
|
6
|
+
module RestClientRequest
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
::TraceView::Util.method_alias(klass, :execute, ::RestClient::Request)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# execute_with_traceview
|
|
13
|
+
#
|
|
14
|
+
# The wrapper method for RestClient::Request.execute
|
|
15
|
+
#
|
|
16
|
+
def execute_with_traceview & block
|
|
17
|
+
kvs = {}
|
|
18
|
+
kvs['Backtrace'] = TraceView::API.backtrace if TraceView::Config[:rest_client][:collect_backtraces]
|
|
19
|
+
TraceView::API.log_entry("rest-client", kvs)
|
|
20
|
+
|
|
21
|
+
# The core rest-client call
|
|
22
|
+
execute_without_traceview(&block)
|
|
23
|
+
rescue => e
|
|
24
|
+
TraceView::API.log_exception('rest-client', e)
|
|
25
|
+
raise e
|
|
26
|
+
ensure
|
|
27
|
+
TraceView::API.log_exit("rest-client")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if TraceView::Config[:rest_client][:enabled]
|
|
34
|
+
if defined?(::RestClient)
|
|
35
|
+
TraceView.logger.info '[traceview/loading] Instrumenting rest-client' if TraceView::Config[:verbose]
|
|
36
|
+
::TraceView::Util.send_include(::RestClient::Request, ::TraceView::Inst::RestClientRequest)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Copyright (c) 2015 AppNeta, Inc.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module TraceView
|
|
5
|
+
module Inst
|
|
6
|
+
module Sequel
|
|
7
|
+
def extract_trace_details(sql, opts)
|
|
8
|
+
kvs = {}
|
|
9
|
+
|
|
10
|
+
if TraceView::Config[:sanitize_sql]
|
|
11
|
+
# Sanitize SQL and don't report binds
|
|
12
|
+
if sql.is_a?(Symbol)
|
|
13
|
+
kvs[:Query] = sql
|
|
14
|
+
else
|
|
15
|
+
kvs[:Query] = sql.gsub(/('[\s\S][^\']*\'|\d*\.\d*)/, '?')
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
# Report raw SQL and any binds if they exist
|
|
19
|
+
kvs[:Query] = sql.to_s
|
|
20
|
+
kvs[:QueryArgs] = opts[:arguments] if opts.is_a?(Hash) and opts.key?(:arguments)
|
|
21
|
+
end
|
|
22
|
+
kvs[:IsPreparedStatement] = true if sql.is_a?(Symbol)
|
|
23
|
+
|
|
24
|
+
kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:sequel][:collect_backtraces]
|
|
25
|
+
|
|
26
|
+
if ::Sequel::VERSION < '3.41.0' && !(self.class.to_s =~ /Dataset$/)
|
|
27
|
+
db_opts = @opts
|
|
28
|
+
elsif @pool
|
|
29
|
+
db_opts = @pool.db.opts
|
|
30
|
+
else
|
|
31
|
+
db_opts = @db.opts
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
kvs[:Database] = db_opts[:database]
|
|
35
|
+
kvs[:RemoteHost] = db_opts[:host]
|
|
36
|
+
kvs[:RemotePort] = db_opts[:port] if db_opts.key?(:port)
|
|
37
|
+
kvs[:Flavor] = db_opts[:adapter]
|
|
38
|
+
rescue => e
|
|
39
|
+
TraceView.logger.debug "[traceview/debug Error capturing Sequel KVs: #{e.message}" if TraceView::Config[:verbose]
|
|
40
|
+
ensure
|
|
41
|
+
return kvs
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module SequelDatabase
|
|
46
|
+
def self.included(klass)
|
|
47
|
+
::TraceView::Util.method_alias(klass, :run, ::Sequel::Database)
|
|
48
|
+
::TraceView::Util.method_alias(klass, :execute_ddl, ::Sequel::Database)
|
|
49
|
+
::TraceView::Util.method_alias(klass, :execute_dui, ::Sequel::Database)
|
|
50
|
+
::TraceView::Util.method_alias(klass, :execute_insert, ::Sequel::Database)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def run_with_traceview(sql, opts=::Sequel::OPTS)
|
|
54
|
+
kvs = extract_trace_details(sql, opts)
|
|
55
|
+
|
|
56
|
+
TraceView::API.log_entry('sequel', kvs)
|
|
57
|
+
|
|
58
|
+
run_without_traceview(sql, opts)
|
|
59
|
+
rescue => e
|
|
60
|
+
TraceView::API.log_exception('sequel', e)
|
|
61
|
+
raise e
|
|
62
|
+
ensure
|
|
63
|
+
TraceView::API.log_exit('sequel')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def exec_with_traceview(method, sql, opts=::Sequel::OPTS, &block)
|
|
67
|
+
kvs = extract_trace_details(sql, opts)
|
|
68
|
+
|
|
69
|
+
TraceView::API.log_entry('sequel', kvs)
|
|
70
|
+
|
|
71
|
+
send(method, sql, opts, &block)
|
|
72
|
+
rescue => e
|
|
73
|
+
TraceView::API.log_exception('sequel', e)
|
|
74
|
+
raise e
|
|
75
|
+
ensure
|
|
76
|
+
TraceView::API.log_exit('sequel')
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def execute_ddl_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
80
|
+
# If we're already tracing a sequel operation, then this call likely came
|
|
81
|
+
# from Sequel::Dataset. In this case, just pass it on.
|
|
82
|
+
return execute_ddl_without_traceview(sql, opts, &block) if TraceView.tracing_layer?('sequel')
|
|
83
|
+
|
|
84
|
+
exec_with_traceview(:execute_ddl_without_traceview, sql, opts, &block)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def execute_dui_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
88
|
+
# If we're already tracing a sequel operation, then this call likely came
|
|
89
|
+
# from Sequel::Dataset. In this case, just pass it on.
|
|
90
|
+
return execute_dui_without_traceview(sql, opts, &block) if TraceView.tracing_layer?('sequel')
|
|
91
|
+
|
|
92
|
+
exec_with_traceview(:execute_dui_without_traceview, sql, opts, &block)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def execute_insert_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
96
|
+
# If we're already tracing a sequel operation, then this call likely came
|
|
97
|
+
# from Sequel::Dataset. In this case, just pass it on.
|
|
98
|
+
return execute_insert_without_traceview(sql, opts, &block) if TraceView.tracing_layer?('sequel')
|
|
99
|
+
|
|
100
|
+
exec_with_traceview(:execute_insert_without_traceview, sql, opts, &block)
|
|
101
|
+
end
|
|
102
|
+
end # module SequelDatabase
|
|
103
|
+
|
|
104
|
+
module SequelDataset
|
|
105
|
+
|
|
106
|
+
def self.included(klass)
|
|
107
|
+
::TraceView::Util.method_alias(klass, :execute, ::Sequel::Dataset)
|
|
108
|
+
::TraceView::Util.method_alias(klass, :execute_ddl, ::Sequel::Dataset)
|
|
109
|
+
::TraceView::Util.method_alias(klass, :execute_dui, ::Sequel::Dataset)
|
|
110
|
+
::TraceView::Util.method_alias(klass, :execute_insert, ::Sequel::Dataset)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def exec_with_traceview(method, sql, opts=::Sequel::OPTS, &block)
|
|
114
|
+
kvs = extract_trace_details(sql, opts)
|
|
115
|
+
|
|
116
|
+
TraceView::API.log_entry('sequel', kvs)
|
|
117
|
+
|
|
118
|
+
send(method, sql, opts, &block)
|
|
119
|
+
rescue => e
|
|
120
|
+
TraceView::API.log_exception('sequel', e)
|
|
121
|
+
raise e
|
|
122
|
+
ensure
|
|
123
|
+
TraceView::API.log_exit('sequel')
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def execute_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
127
|
+
exec_with_traceview(:execute_without_traceview, sql, opts, &block)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def execute_ddl_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
131
|
+
exec_with_traceview(:execute_ddl_without_traceview, sql, opts, &block)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def execute_dui_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
135
|
+
exec_with_traceview(:execute_dui_without_traceview, sql, opts, &block)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def execute_insert_with_traceview(sql, opts=::Sequel::OPTS, &block)
|
|
139
|
+
exec_with_traceview(:execute_insert_without_traceview, sql, opts, &block)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end # module SequelDataset
|
|
143
|
+
end # module Inst
|
|
144
|
+
end # module TraceView
|
|
145
|
+
|
|
146
|
+
if TraceView::Config[:sequel][:enabled]
|
|
147
|
+
if defined?(::Sequel) && ::Sequel::VERSION < "4.0.0"
|
|
148
|
+
# For versions before 4.0.0, Sequel::OPTS wasn't defined.
|
|
149
|
+
# Define it as an empty hash for backwards compatibility.
|
|
150
|
+
module ::Sequel
|
|
151
|
+
OPTS = {}
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if defined?(::Sequel)
|
|
156
|
+
TraceView.logger.info '[traceview/loading] Instrumenting sequel' if TraceView::Config[:verbose]
|
|
157
|
+
::TraceView::Util.send_include(::Sequel::Database, ::TraceView::Inst::Sequel)
|
|
158
|
+
::TraceView::Util.send_include(::Sequel::Database, ::TraceView::Inst::SequelDatabase)
|
|
159
|
+
::TraceView::Util.send_include(::Sequel::Dataset, ::TraceView::Inst::Sequel)
|
|
160
|
+
::TraceView::Util.send_include(::Sequel::Dataset, ::TraceView::Inst::SequelDataset)
|
|
161
|
+
end
|
|
162
|
+
end
|