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.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +5 -0
  4. data/.travis.yml +58 -0
  5. data/Appraisals +10 -0
  6. data/CHANGELOG.md +490 -0
  7. data/CONFIG.md +16 -0
  8. data/Gemfile +95 -0
  9. data/LICENSE +199 -0
  10. data/README.md +380 -0
  11. data/Rakefile +109 -0
  12. data/examples/DNT.md +35 -0
  13. data/examples/carrying_context.rb +225 -0
  14. data/examples/instrumenting_metal_controller.rb +8 -0
  15. data/examples/puma_on_heroku_config.rb +17 -0
  16. data/examples/tracing_async_threads.rb +125 -0
  17. data/examples/tracing_background_jobs.rb +52 -0
  18. data/examples/tracing_forked_processes.rb +100 -0
  19. data/examples/unicorn_on_heroku_config.rb +28 -0
  20. data/ext/oboe_metal/extconf.rb +61 -0
  21. data/ext/oboe_metal/noop/noop.c +7 -0
  22. data/ext/oboe_metal/src/bson/bson.h +221 -0
  23. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  24. data/ext/oboe_metal/src/oboe.h +275 -0
  25. data/ext/oboe_metal/src/oboe.hpp +352 -0
  26. data/ext/oboe_metal/src/oboe_wrap.cxx +3886 -0
  27. data/ext/oboe_metal/tests/test.rb +11 -0
  28. data/gemfiles/mongo.gemfile +33 -0
  29. data/gemfiles/moped.gemfile +33 -0
  30. data/get_version.rb +5 -0
  31. data/init.rb +4 -0
  32. data/lib/joboe_metal.rb +206 -0
  33. data/lib/oboe/README +2 -0
  34. data/lib/oboe/backward_compatibility.rb +59 -0
  35. data/lib/oboe/inst/rack.rb +11 -0
  36. data/lib/oboe.rb +7 -0
  37. data/lib/oboe_metal.rb +151 -0
  38. data/lib/rails/generators/traceview/install_generator.rb +76 -0
  39. data/lib/rails/generators/traceview/templates/traceview_initializer.rb +159 -0
  40. data/lib/traceview/api/layerinit.rb +51 -0
  41. data/lib/traceview/api/logging.rb +209 -0
  42. data/lib/traceview/api/memcache.rb +31 -0
  43. data/lib/traceview/api/profiling.rb +50 -0
  44. data/lib/traceview/api/tracing.rb +135 -0
  45. data/lib/traceview/api/util.rb +121 -0
  46. data/lib/traceview/api.rb +18 -0
  47. data/lib/traceview/base.rb +225 -0
  48. data/lib/traceview/config.rb +238 -0
  49. data/lib/traceview/frameworks/grape.rb +97 -0
  50. data/lib/traceview/frameworks/padrino/templates.rb +58 -0
  51. data/lib/traceview/frameworks/padrino.rb +64 -0
  52. data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  53. data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  54. data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  55. data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
  56. data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
  57. data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
  58. data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
  59. data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
  60. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  61. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  62. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  63. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  64. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
  65. data/lib/traceview/frameworks/rails.rb +145 -0
  66. data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
  67. data/lib/traceview/frameworks/sinatra.rb +95 -0
  68. data/lib/traceview/inst/cassandra.rb +279 -0
  69. data/lib/traceview/inst/dalli.rb +86 -0
  70. data/lib/traceview/inst/em-http-request.rb +99 -0
  71. data/lib/traceview/inst/excon.rb +111 -0
  72. data/lib/traceview/inst/faraday.rb +73 -0
  73. data/lib/traceview/inst/http.rb +87 -0
  74. data/lib/traceview/inst/httpclient.rb +173 -0
  75. data/lib/traceview/inst/memcache.rb +102 -0
  76. data/lib/traceview/inst/memcached.rb +94 -0
  77. data/lib/traceview/inst/mongo.rb +238 -0
  78. data/lib/traceview/inst/moped.rb +474 -0
  79. data/lib/traceview/inst/rack.rb +122 -0
  80. data/lib/traceview/inst/redis.rb +271 -0
  81. data/lib/traceview/inst/resque.rb +192 -0
  82. data/lib/traceview/inst/rest-client.rb +38 -0
  83. data/lib/traceview/inst/sequel.rb +162 -0
  84. data/lib/traceview/inst/typhoeus.rb +102 -0
  85. data/lib/traceview/instrumentation.rb +21 -0
  86. data/lib/traceview/loading.rb +94 -0
  87. data/lib/traceview/logger.rb +41 -0
  88. data/lib/traceview/method_profiling.rb +84 -0
  89. data/lib/traceview/ruby.rb +36 -0
  90. data/lib/traceview/support.rb +113 -0
  91. data/lib/traceview/thread_local.rb +26 -0
  92. data/lib/traceview/util.rb +250 -0
  93. data/lib/traceview/version.rb +16 -0
  94. data/lib/traceview/xtrace.rb +90 -0
  95. data/lib/traceview.rb +62 -0
  96. data/test/frameworks/apps/grape_nested.rb +30 -0
  97. data/test/frameworks/apps/grape_simple.rb +24 -0
  98. data/test/frameworks/apps/padrino_simple.rb +45 -0
  99. data/test/frameworks/apps/sinatra_simple.rb +24 -0
  100. data/test/frameworks/grape_test.rb +142 -0
  101. data/test/frameworks/padrino_test.rb +30 -0
  102. data/test/frameworks/sinatra_test.rb +30 -0
  103. data/test/instrumentation/cassandra_test.rb +380 -0
  104. data/test/instrumentation/dalli_test.rb +171 -0
  105. data/test/instrumentation/em_http_request_test.rb +86 -0
  106. data/test/instrumentation/excon_test.rb +207 -0
  107. data/test/instrumentation/faraday_test.rb +235 -0
  108. data/test/instrumentation/http_test.rb +140 -0
  109. data/test/instrumentation/httpclient_test.rb +296 -0
  110. data/test/instrumentation/memcache_test.rb +251 -0
  111. data/test/instrumentation/memcached_test.rb +226 -0
  112. data/test/instrumentation/mongo_test.rb +462 -0
  113. data/test/instrumentation/moped_test.rb +496 -0
  114. data/test/instrumentation/rack_test.rb +116 -0
  115. data/test/instrumentation/redis_hashes_test.rb +265 -0
  116. data/test/instrumentation/redis_keys_test.rb +318 -0
  117. data/test/instrumentation/redis_lists_test.rb +310 -0
  118. data/test/instrumentation/redis_misc_test.rb +160 -0
  119. data/test/instrumentation/redis_sets_test.rb +293 -0
  120. data/test/instrumentation/redis_sortedsets_test.rb +325 -0
  121. data/test/instrumentation/redis_strings_test.rb +333 -0
  122. data/test/instrumentation/resque_test.rb +62 -0
  123. data/test/instrumentation/rest-client_test.rb +294 -0
  124. data/test/instrumentation/sequel_mysql2_test.rb +326 -0
  125. data/test/instrumentation/sequel_mysql_test.rb +326 -0
  126. data/test/instrumentation/sequel_pg_test.rb +330 -0
  127. data/test/instrumentation/typhoeus_test.rb +285 -0
  128. data/test/minitest_helper.rb +187 -0
  129. data/test/profiling/method_test.rb +198 -0
  130. data/test/servers/rackapp_8101.rb +22 -0
  131. data/test/support/backcompat_test.rb +269 -0
  132. data/test/support/config_test.rb +128 -0
  133. data/test/support/dnt_test.rb +73 -0
  134. data/test/support/liboboe_settings_test.rb +104 -0
  135. data/test/support/xtrace_test.rb +35 -0
  136. data/traceview.gemspec +29 -0
  137. 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