traceview 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.rb +7 -0
  34. data/lib/oboe/README +2 -0
  35. data/lib/oboe/backward_compatibility.rb +59 -0
  36. data/lib/oboe/inst/rack.rb +11 -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.rb +62 -0
  41. data/lib/traceview/api.rb +18 -0
  42. data/lib/traceview/api/layerinit.rb +51 -0
  43. data/lib/traceview/api/logging.rb +209 -0
  44. data/lib/traceview/api/memcache.rb +31 -0
  45. data/lib/traceview/api/profiling.rb +50 -0
  46. data/lib/traceview/api/tracing.rb +135 -0
  47. data/lib/traceview/api/util.rb +121 -0
  48. data/lib/traceview/base.rb +225 -0
  49. data/lib/traceview/config.rb +238 -0
  50. data/lib/traceview/frameworks/grape.rb +97 -0
  51. data/lib/traceview/frameworks/padrino.rb +64 -0
  52. data/lib/traceview/frameworks/padrino/templates.rb +58 -0
  53. data/lib/traceview/frameworks/rails.rb +145 -0
  54. data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  55. data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  56. data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  57. data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
  58. data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
  59. data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
  60. data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
  61. data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
  62. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  63. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  64. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  65. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  66. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
  67. data/lib/traceview/frameworks/sinatra.rb +95 -0
  68. data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
  69. data/lib/traceview/inst/cassandra.rb +279 -0
  70. data/lib/traceview/inst/dalli.rb +86 -0
  71. data/lib/traceview/inst/em-http-request.rb +99 -0
  72. data/lib/traceview/inst/excon.rb +111 -0
  73. data/lib/traceview/inst/faraday.rb +73 -0
  74. data/lib/traceview/inst/http.rb +87 -0
  75. data/lib/traceview/inst/httpclient.rb +173 -0
  76. data/lib/traceview/inst/memcache.rb +102 -0
  77. data/lib/traceview/inst/memcached.rb +94 -0
  78. data/lib/traceview/inst/mongo.rb +238 -0
  79. data/lib/traceview/inst/moped.rb +474 -0
  80. data/lib/traceview/inst/rack.rb +122 -0
  81. data/lib/traceview/inst/redis.rb +271 -0
  82. data/lib/traceview/inst/resque.rb +192 -0
  83. data/lib/traceview/inst/rest-client.rb +38 -0
  84. data/lib/traceview/inst/sequel.rb +162 -0
  85. data/lib/traceview/inst/typhoeus.rb +102 -0
  86. data/lib/traceview/instrumentation.rb +21 -0
  87. data/lib/traceview/loading.rb +94 -0
  88. data/lib/traceview/logger.rb +41 -0
  89. data/lib/traceview/method_profiling.rb +84 -0
  90. data/lib/traceview/ruby.rb +36 -0
  91. data/lib/traceview/support.rb +113 -0
  92. data/lib/traceview/thread_local.rb +26 -0
  93. data/lib/traceview/util.rb +250 -0
  94. data/lib/traceview/version.rb +16 -0
  95. data/lib/traceview/xtrace.rb +90 -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 +250 -0
@@ -0,0 +1,111 @@
1
+ # Copyright (c) 2015 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ module Inst
6
+ module ExconConnection
7
+ def self.included(klass)
8
+ ::TraceView::Util.method_alias(klass, :request, ::Excon::Connection)
9
+ ::TraceView::Util.method_alias(klass, :requests, ::Excon::Connection)
10
+ end
11
+
12
+ def traceview_collect(params)
13
+ kvs = {}
14
+ kvs['IsService'] = 1
15
+ kvs['RemoteProtocol'] = ::TraceView::Util.upcase(@data[:scheme])
16
+ kvs['RemoteHost'] = @data[:host]
17
+
18
+ # Conditionally log query args
19
+ if TraceView::Config[:excon][:log_args] && (@data[:query] && @data[:query].length)
20
+ kvs['ServiceArg'] = @data[:path] + '?' + @data[:query]
21
+ else
22
+ kvs['ServiceArg'] = @data[:path]
23
+ end
24
+
25
+ # In the case of HTTP pipelining, params could be an array of
26
+ # request hashes.
27
+ if params.is_a?(Array)
28
+ methods = []
29
+ params.each do |p|
30
+ methods << ::TraceView::Util.upcase(p[:method])
31
+ end
32
+ kvs['HTTPMethods'] = methods.join(', ')[0..1024]
33
+ kvs['Pipeline'] = true
34
+ else
35
+ kvs['HTTPMethod'] = ::TraceView::Util.upcase(params[:method])
36
+ end
37
+ kvs['Backtrace'] = TraceView::API.backtrace if TraceView::Config[:excon][:collect_backtraces]
38
+ kvs
39
+ rescue => e
40
+ TraceView.logger.debug "[traceview/debug] Error capturing excon KVs: #{e.message}"
41
+ TraceView.logger.debug e.backtrace.join('\n') if ::TraceView::Config[:verbose]
42
+ end
43
+
44
+ def requests_with_traceview(pipeline_params)
45
+ responses = nil
46
+ TraceView::API.trace('excon', traceview_collect(pipeline_params)) do
47
+ responses = requests_without_traceview(pipeline_params)
48
+ end
49
+ responses
50
+ end
51
+
52
+ def request_with_traceview(params={}, &block)
53
+ # If we're not tracing, just do a fast return.
54
+ # If making HTTP pipeline requests (ordered batched)
55
+ # then just return as we're tracing from parent
56
+ # <tt>requests</tt>
57
+ if !TraceView.tracing? || params[:pipeline]
58
+ return request_without_traceview(params, &block)
59
+ end
60
+
61
+ begin
62
+ response_context = nil
63
+
64
+ # Avoid cross host tracing for blacklisted domains
65
+ blacklisted = TraceView::API.blacklisted?(@data[:hostname])
66
+
67
+ req_context = TraceView::Context.toString()
68
+ @data[:headers]['X-Trace'] = req_context unless blacklisted
69
+
70
+ kvs = traceview_collect(params)
71
+ kvs['Blacklisted'] = true if blacklisted
72
+
73
+ TraceView::API.log_entry('excon', kvs)
74
+ kvs.clear
75
+
76
+ # The core excon call
77
+ response = request_without_traceview(params, &block)
78
+
79
+ # excon only passes back a hash (datum) for HTTP pipelining...
80
+ # In that case, we should never arrive here but for the OCD, double check
81
+ # the datatype before trying to extract pertinent info
82
+ if response.is_a?(Excon::Response)
83
+ response_context = response.headers['X-Trace']
84
+ kvs['HTTPStatus'] = response.status
85
+
86
+ # If we get a redirect, report the location header
87
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?("Location")
88
+ kvs["Location"] = response.headers["Location"]
89
+ end
90
+
91
+ if response_context && !blacklisted
92
+ TraceView::XTrace.continue_service_context(req_context, response_context)
93
+ end
94
+ end
95
+
96
+ response
97
+ rescue => e
98
+ TraceView::API.log_exception('excon', e)
99
+ raise e
100
+ ensure
101
+ TraceView::API.log_exit('excon', kvs) unless params[:pipeline]
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ if TraceView::Config[:excon][:enabled] && defined?(::Excon)
109
+ ::TraceView.logger.info '[traceview/loading] Instrumenting excon' if TraceView::Config[:verbose]
110
+ ::TraceView::Util.send_include(::Excon::Connection, ::TraceView::Inst::ExconConnection)
111
+ end
@@ -0,0 +1,73 @@
1
+ module TraceView
2
+ module Inst
3
+ module FaradayConnection
4
+ def self.included(klass)
5
+ ::TraceView::Util.method_alias(klass, :run_request, ::Faraday::Connection)
6
+ end
7
+
8
+ def run_request_with_traceview(method, url, body, headers, &block)
9
+ # Only send service KVs if we're not using the Net::HTTP adapter
10
+ # Otherwise, the Net::HTTP instrumentation will send the service KVs
11
+ handle_service = !@builder.handlers.include?(Faraday::Adapter::NetHttp) &&
12
+ !@builder.handlers.include?(Faraday::Adapter::Excon)
13
+ TraceView::API.log_entry('faraday')
14
+
15
+ result = run_request_without_traceview(method, url, body, headers, &block)
16
+
17
+ kvs = {}
18
+ kvs['Middleware'] = @builder.handlers
19
+ kvs['Backtrace'] = TraceView::API.backtrace if TraceView::Config[:faraday][:collect_backtraces]
20
+
21
+ if handle_service
22
+ blacklisted = TraceView::API.blacklisted?(@url_prefix.to_s)
23
+ context = TraceView::Context.toString
24
+ task_id = TraceView::XTrace.task_id(context)
25
+
26
+ # Avoid cross host tracing for blacklisted domains
27
+ # Conditionally add the X-Trace header to the outgoing request
28
+ @headers['X-Trace'] = context unless blacklisted
29
+
30
+ kvs['IsService'] = 1
31
+ kvs['RemoteProtocol'] = (@url_prefix.scheme == 'https') ? 'HTTPS' : 'HTTP'
32
+ kvs['RemoteHost'] = @url_prefix.host
33
+ kvs['RemotePort'] = @url_prefix.port
34
+ kvs['ServiceArg'] = url
35
+ kvs['HTTPMethod'] = method
36
+ kvs[:HTTPStatus] = result.status
37
+ kvs['Blacklisted'] = true if blacklisted
38
+
39
+ # Re-attach net::http edge unless it's blacklisted or if we don't have a
40
+ # valid X-Trace header
41
+ unless blacklisted
42
+ xtrace = result.headers['X-Trace']
43
+
44
+ if TraceView::XTrace.valid?(xtrace) && TraceView.tracing?
45
+
46
+ # Assure that we received back a valid X-Trace with the same task_id
47
+ if task_id == TraceView::XTrace.task_id(xtrace)
48
+ TraceView::Context.fromString(xtrace)
49
+ else
50
+ TraceView.logger.debug "Mismatched returned X-Trace ID: #{xtrace}"
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ TraceView::API.log('faraday', 'info', kvs)
57
+ result
58
+ rescue => e
59
+ TraceView::API.log_exception('faraday', e)
60
+ raise e
61
+ ensure
62
+ TraceView::API.log_exit('faraday')
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ if TraceView::Config[:faraday][:enabled]
69
+ if defined?(::Faraday)
70
+ TraceView.logger.info '[traceview/loading] Instrumenting faraday' if TraceView::Config[:verbose]
71
+ ::TraceView::Util.send_include(::Faraday::Connection, ::TraceView::Inst::FaradayConnection)
72
+ end
73
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ require 'net/http'
5
+
6
+ if TraceView::Config[:nethttp][:enabled]
7
+
8
+ Net::HTTP.class_eval do
9
+ def request_with_traceview(*args, &block)
10
+ # If we're not tracing, just do a fast return. Since
11
+ # net/http.request calls itself, only trace
12
+ # once the http session has been started.
13
+ if !TraceView.tracing? || !started?
14
+ return request_without_traceview(*args, &block)
15
+ end
16
+
17
+ # Avoid cross host tracing for blacklisted domains
18
+ blacklisted = TraceView::API.blacklisted?(addr_port)
19
+
20
+ TraceView::API.trace('net-http') do
21
+ opts = {}
22
+ context = TraceView::Context.toString()
23
+ task_id = TraceView::XTrace.task_id(context)
24
+
25
+ # Collect KVs to report in the info event
26
+ if args.length && args[0]
27
+ req = args[0]
28
+
29
+ opts['IsService'] = 1
30
+ opts['RemoteProtocol'] = use_ssl? ? 'HTTPS' : 'HTTP'
31
+ opts['RemoteHost'] = addr_port
32
+
33
+ # Conditionally log query params
34
+ if TraceView::Config[:nethttp][:log_args]
35
+ opts['ServiceArg'] = req.path
36
+ else
37
+ opts['ServiceArg'] = req.path.split('?').first
38
+ end
39
+
40
+ opts['HTTPMethod'] = req.method
41
+ opts['Blacklisted'] = true if blacklisted
42
+ opts['Backtrace'] = TraceView::API.backtrace if TraceView::Config[:nethttp][:collect_backtraces]
43
+
44
+ req['X-Trace'] = context unless blacklisted
45
+ end
46
+
47
+ begin
48
+ # The actual net::http call
49
+ resp = request_without_traceview(*args, &block)
50
+
51
+ # Re-attach net::http edge unless blacklisted and is a valid X-Trace ID
52
+ unless blacklisted
53
+ xtrace = resp.get_fields('X-Trace')
54
+ xtrace = xtrace[0] if xtrace && xtrace.is_a?(Array)
55
+
56
+ if TraceView::XTrace.valid?(xtrace)
57
+
58
+ # Assure that we received back a valid X-Trace with the same task_id
59
+ if task_id == TraceView::XTrace.task_id(xtrace)
60
+ TraceView::Context.fromString(xtrace)
61
+ else
62
+ TraceView.logger.debug "Mismatched returned X-Trace ID : #{xtrace}"
63
+ end
64
+ end
65
+ end
66
+
67
+ opts['HTTPStatus'] = resp.code
68
+
69
+ # If we get a redirect, report the location header
70
+ if ((300..308).to_a.include? resp.code.to_i) && resp.header["Location"]
71
+ opts["Location"] = resp.header["Location"]
72
+ end
73
+
74
+ next resp
75
+ ensure
76
+ # Log the info event with the KVs in opts
77
+ TraceView::API.log('net-http', 'info', opts)
78
+ end
79
+ end
80
+ end
81
+
82
+ alias request_without_traceview request
83
+ alias request request_with_traceview
84
+
85
+ TraceView.logger.info '[traceview/loading] Instrumenting net/http' if TraceView::Config[:verbose]
86
+ end
87
+ end
@@ -0,0 +1,173 @@
1
+ # Copyright (c) 2015 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ module Inst
6
+ module HTTPClient
7
+ def self.included(klass)
8
+ ::TraceView::Util.method_alias(klass, :do_request, ::HTTPClient)
9
+ ::TraceView::Util.method_alias(klass, :do_request_async, ::HTTPClient)
10
+ ::TraceView::Util.method_alias(klass, :do_get_stream, ::HTTPClient)
11
+ end
12
+
13
+ def traceview_collect(method, uri, query = nil)
14
+ kvs = {}
15
+ kvs['IsService'] = 1
16
+
17
+ # Conditionally log URL query params
18
+ # Because of the hook points, the query arg can come in under <tt>query</tt>
19
+ # or as a part of <tt>uri</tt> (not both). Here we handle both cases.
20
+ if TraceView::Config[:httpclient][:log_args]
21
+ if query
22
+ kvs['RemoteURL'] = uri.to_s + '?' + TraceView::Util.to_query(query)
23
+ else
24
+ kvs['RemoteURL'] = uri.to_s
25
+ end
26
+ else
27
+ kvs['RemoteURL'] = uri.to_s.split('?').first
28
+ end
29
+
30
+ kvs['HTTPMethod'] = ::TraceView::Util.upcase(method)
31
+ kvs['Backtrace'] = TraceView::API.backtrace if TraceView::Config[:httpclient][:collect_backtraces]
32
+ kvs
33
+ rescue => e
34
+ TraceView.logger.debug "[traceview/debug] Error capturing httpclient KVs: #{e.message}"
35
+ TraceView.logger.debug e.backtrace.join('\n') if ::TraceView::Config[:verbose]
36
+ end
37
+
38
+ def do_request_with_traceview(method, uri, query, body, header, &block)
39
+ # If we're not tracing, just do a fast return.
40
+ if !TraceView.tracing?
41
+ return request_without_traceview(method, uri, query, body, header, &block)
42
+ end
43
+
44
+ begin
45
+ response_context = nil
46
+
47
+ # Avoid cross host tracing for blacklisted domains
48
+ blacklisted = TraceView::API.blacklisted?(uri.hostname)
49
+
50
+ kvs = traceview_collect(method, uri, query)
51
+ kvs['Blacklisted'] = true if blacklisted
52
+
53
+ TraceView::API.log_entry('httpclient', kvs)
54
+ kvs.clear
55
+
56
+ req_context = TraceView::Context.toString()
57
+
58
+ # Be aware of various ways to call/use httpclient
59
+ if header.is_a?(Array)
60
+ header.push ["X-Trace", req_context]
61
+ elsif header.is_a?(Hash)
62
+ header['X-Trace'] = req_context unless blacklisted
63
+ end
64
+
65
+ # The core httpclient call
66
+ response = do_request_without_traceview(method, uri, query, body, header, &block)
67
+
68
+ response_context = response.headers['X-Trace']
69
+ kvs['HTTPStatus'] = response.status_code
70
+
71
+ # If we get a redirect, report the location header
72
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?("Location")
73
+ kvs["Location"] = response.headers["Location"]
74
+ end
75
+
76
+ if response_context && !blacklisted
77
+ TraceView::XTrace.continue_service_context(req_context, response_context)
78
+ end
79
+
80
+ response
81
+ rescue => e
82
+ TraceView::API.log_exception('httpclient', e)
83
+ raise e
84
+ ensure
85
+ TraceView::API.log_exit('httpclient', kvs)
86
+ end
87
+ end
88
+
89
+ def do_request_async_with_traceview(method, uri, query, body, header)
90
+ if TraceView.tracing?
91
+ # Since async is done by calling Thread.new { .. }, we somehow
92
+ # have to pass the tracing context into that new thread. Here
93
+ # we stowaway the context in the request headers to be picked up
94
+ # (and removed from req headers) in do_get_stream.
95
+ if header.is_a?(Array)
96
+ header.push ["traceview.context", TraceView::Context.toString]
97
+ elsif header.is_a?(Hash)
98
+ header['traceview.context'] = TraceView::Context.toString
99
+ end
100
+ end
101
+
102
+ do_request_async_without_traceview(method, uri, query, body, header)
103
+ end
104
+
105
+ def do_get_stream_with_traceview(req, proxy, conn)
106
+ unless req.headers.key?("traceview.context")
107
+ return do_get_stream_without_traceview(req, proxy, conn)
108
+ end
109
+
110
+ # Pickup context and delete the headers stowaway
111
+ TraceView::Context.fromString req.headers["traceview.context"]
112
+ req.header.delete "traceview.context"
113
+
114
+ begin
115
+ response = nil
116
+ response_context = nil
117
+ uri = req.http_header.request_uri
118
+ method = req.http_header.request_method
119
+
120
+ # Avoid cross host tracing for blacklisted domains
121
+ blacklisted = TraceView::API.blacklisted?(uri.hostname)
122
+
123
+ kvs = traceview_collect(method, uri)
124
+ kvs['Blacklisted'] = true if blacklisted
125
+ kvs['Async'] = 1
126
+
127
+ TraceView::API.log_entry('httpclient', kvs)
128
+ kvs.clear
129
+
130
+ req_context = TraceView::Context.toString()
131
+ req.header.add('X-Trace', req_context)
132
+
133
+ # The core httpclient call
134
+ result = do_get_stream_without_traceview(req, proxy, conn)
135
+
136
+ # Older HTTPClient < 2.6.0 returns HTTPClient::Connection
137
+ if result.is_a?(::HTTP::Message)
138
+ response = result
139
+ else
140
+ response = conn.pop
141
+ end
142
+
143
+ response_context = response.headers['X-Trace']
144
+ kvs['HTTPStatus'] = response.status_code
145
+
146
+ # If we get a redirect, report the location header
147
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?("Location")
148
+ kvs["Location"] = response.headers["Location"]
149
+ end
150
+
151
+ if response_context && !blacklisted
152
+ TraceView::XTrace.continue_service_context(req_context, response_context)
153
+ end
154
+
155
+ # Older HTTPClient < 2.6.0 returns HTTPClient::Connection
156
+ conn.push response if result.is_a?(::HTTPClient::Connection)
157
+ result
158
+ rescue => e
159
+ TraceView::API.log_exception('httpclient', e)
160
+ raise e
161
+ ensure
162
+ # TraceView::API.log_exit('httpclient', kvs.merge('Async' => 1))
163
+ TraceView::API.log_exit('httpclient', kvs)
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ if TraceView::Config[:httpclient][:enabled] && defined?(::HTTPClient)
171
+ ::TraceView.logger.info '[traceview/loading] Instrumenting httpclient' if TraceView::Config[:verbose]
172
+ ::TraceView::Util.send_include(::HTTPClient, ::TraceView::Inst::HTTPClient)
173
+ end
@@ -0,0 +1,102 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ module Inst
6
+ module MemCache
7
+ include TraceView::API::Memcache
8
+
9
+ def self.included(cls)
10
+ TraceView.logger.info '[traceview/loading] Instrumenting memcache' if TraceView::Config[:verbose]
11
+
12
+ cls.class_eval do
13
+ MEMCACHE_OPS.reject { |m| !method_defined?(m) }.each do |m|
14
+
15
+ define_method("#{m}_with_traceview") do |*args|
16
+ report_kvs = { :KVOp => m }
17
+ report_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:memcache][:collect_backtraces]
18
+
19
+ if TraceView.tracing?
20
+ TraceView::API.trace('memcache', report_kvs) do
21
+ send("#{m}_without_traceview", *args)
22
+ end
23
+ else
24
+ send("#{m}_without_traceview", *args)
25
+ end
26
+ end
27
+
28
+ class_eval "alias #{m}_without_traceview #{m}"
29
+ class_eval "alias #{m} #{m}_with_traceview"
30
+ end
31
+ end
32
+
33
+ [:request_setup, :cache_get, :get_multi].each do |m|
34
+ if ::MemCache.method_defined? :request_setup
35
+ cls.class_eval "alias #{m}_without_traceview #{m}"
36
+ cls.class_eval "alias #{m} #{m}_with_traceview"
37
+ elsif TraceView::Config[:verbose]
38
+ TraceView.logger.warn "[traceview/loading] Couldn't properly instrument Memcache: #{m}"
39
+ end
40
+ end
41
+ end
42
+
43
+ def get_multi_with_traceview(*args)
44
+ return get_multi_without_traceview(args) unless TraceView.tracing?
45
+
46
+ info_kvs = {}
47
+
48
+ begin
49
+ info_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:memcache][:collect_backtraces]
50
+
51
+ if args.last.is_a?(Hash) || args.last.nil?
52
+ info_kvs[:KVKeyCount] = args.flatten.length - 1
53
+ else
54
+ info_kvs[:KVKeyCount] = args.flatten.length
55
+ end
56
+ rescue StandardError => e
57
+ TraceView.logger.debug "[traceview/debug] Error collecting info keys: #{e.message}"
58
+ TraceView.logger.debug e.backtrace
59
+ end
60
+
61
+ TraceView::API.trace('memcache', { :KVOp => :get_multi }, :get_multi) do
62
+ values = get_multi_without_traceview(args)
63
+
64
+ info_kvs[:KVHitCount] = values.length
65
+ TraceView::API.log('memcache', 'info', info_kvs)
66
+
67
+ values
68
+ end
69
+ end
70
+
71
+ def request_setup_with_traceview(*args)
72
+ if TraceView.tracing? && !TraceView.tracing_layer_op?(:get_multi)
73
+ server, cache_key = request_setup_without_traceview(*args)
74
+
75
+ info_kvs = { :KVKey => cache_key, :RemoteHost => server.host }
76
+ info_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:memcache][:collect_backtraces]
77
+ TraceView::API.log('memcache', 'info', info_kvs)
78
+
79
+ [server, cache_key]
80
+ else
81
+ request_setup_without_traceview(*args)
82
+ end
83
+ end
84
+
85
+ def cache_get_with_traceview(server, cache_key)
86
+ result = cache_get_without_traceview(server, cache_key)
87
+
88
+ info_kvs = { :KVHit => memcache_hit?(result) }
89
+ info_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:memcache][:collect_backtraces]
90
+ TraceView::API.log('memcache', 'info', info_kvs)
91
+
92
+ result
93
+ end
94
+ end # module MemCache
95
+ end # module Inst
96
+ end # module TraceView
97
+
98
+ if defined?(::MemCache) && TraceView::Config[:memcache][:enabled]
99
+ ::MemCache.class_eval do
100
+ include TraceView::Inst::MemCache
101
+ end
102
+ end