traceview 3.0.0

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.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