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,86 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ module Inst
6
+ module Dalli
7
+ include TraceView::API::Memcache
8
+
9
+ def self.included(cls)
10
+ cls.class_eval do
11
+ TraceView.logger.info '[traceview/loading] Instrumenting memcache (dalli)' if TraceView::Config[:verbose]
12
+ if ::Dalli::Client.private_method_defined? :perform
13
+ alias perform_without_traceview perform
14
+ alias perform perform_with_traceview
15
+ else TraceView.logger.warn '[traceview/loading] Couldn\'t properly instrument Memcache (Dalli). Partial traces may occur.'
16
+ end
17
+
18
+ if ::Dalli::Client.method_defined? :get_multi
19
+ alias get_multi_without_traceview get_multi
20
+ alias get_multi get_multi_with_traceview
21
+ end
22
+ end
23
+ end
24
+
25
+ def perform_with_traceview(*all_args, &blk)
26
+ op, key, *args = *all_args
27
+
28
+ report_kvs = {}
29
+ report_kvs[:KVOp] = op
30
+ report_kvs[:KVKey] = key
31
+ if @servers.is_a?(Array) && !@servers.empty?
32
+ report_kvs[:RemoteHost] = @servers.join(", ")
33
+ end
34
+
35
+ if TraceView.tracing? && !TraceView.tracing_layer_op?(:get_multi)
36
+ TraceView::API.trace('memcache', report_kvs) do
37
+ result = perform_without_traceview(*all_args, &blk)
38
+
39
+ # Clear the hash for a potential info event
40
+ report_kvs.clear
41
+ report_kvs[:KVHit] = memcache_hit?(result) if op == :get && key.class == String
42
+ report_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:dalli][:collect_backtraces]
43
+
44
+ TraceView::API.log('memcache', 'info', report_kvs) unless report_kvs.empty?
45
+ result
46
+ end
47
+ else
48
+ perform_without_traceview(*all_args, &blk)
49
+ end
50
+ end
51
+
52
+ def get_multi_with_traceview(*keys)
53
+ return get_multi_without_traceview(keys) unless TraceView.tracing?
54
+
55
+ info_kvs = {}
56
+
57
+ begin
58
+ info_kvs[:KVKeyCount] = keys.flatten.length
59
+ info_kvs[:KVKeyCount] = (info_kvs[:KVKeyCount] - 1) if keys.last.is_a?(Hash) || keys.last.nil?
60
+ if @servers.is_a?(Array) && !@servers.empty?
61
+ info_kvs[:RemoteHost] = @servers.join(", ")
62
+ end
63
+ rescue
64
+ TraceView.logger.debug "[traceview/debug] Error collecting info keys: #{e.message}"
65
+ TraceView.logger.debug e.backtrace
66
+ end
67
+
68
+ TraceView::API.trace('memcache', { :KVOp => :get_multi }, :get_multi) do
69
+ values = get_multi_without_traceview(keys)
70
+
71
+ info_kvs[:KVHitCount] = values.length
72
+ info_kvs[:Backtrace] = TraceView::API.backtrace if TraceView::Config[:dalli][:collect_backtraces]
73
+ TraceView::API.log('memcache', 'info', info_kvs)
74
+
75
+ values
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ if defined?(Dalli) && TraceView::Config[:dalli][:enabled]
83
+ ::Dalli::Client.module_eval do
84
+ include TraceView::Inst::Dalli
85
+ end
86
+ end
@@ -0,0 +1,99 @@
1
+ module TraceView
2
+ module Inst
3
+ module EventMachine
4
+ module HttpConnection
5
+ def setup_request_with_traceview(*args, &block)
6
+ report_kvs = {}
7
+ context = TraceView::Context.toString
8
+ blacklisted = TraceView::API.blacklisted?(@uri)
9
+
10
+ begin
11
+ report_kvs['IsService'] = 1
12
+ report_kvs['RemoteURL'] = @uri
13
+ report_kvs['HTTPMethod'] = args[0]
14
+ report_kvs['Blacklisted'] = true if blacklisted
15
+
16
+ if TraceView::Config[:em_http_request][:collect_backtraces]
17
+ report_kvs[:Backtrace] = TraceView::API.backtrace
18
+ end
19
+ rescue => e
20
+ TraceView.logger.debug "[traceview/debug] em-http-request KV error: #{e.inspect}"
21
+ end
22
+
23
+ ::TraceView::API.log_entry('em-http-request', report_kvs)
24
+ client = setup_request_without_traceview(*args, &block)
25
+ client.req.headers['X-Trace'] = context unless blacklisted
26
+ client
27
+ end
28
+ end
29
+
30
+ module HttpClient
31
+ def parse_response_header_with_traceview(*args, &block)
32
+ report_kvs = {}
33
+ xtrace = nil
34
+ blacklisted = TraceView::API.blacklisted?(@uri)
35
+
36
+ begin
37
+ report_kvs[:HTTPStatus] = args[2]
38
+ report_kvs[:Async] = 1
39
+ rescue => e
40
+ TraceView.logger.debug "[traceview/debug] em-http-request KV error: #{e.inspect}"
41
+ end
42
+
43
+ parse_response_header_without_traceview(*args, &block)
44
+
45
+ unless blacklisted
46
+ headers = args[0]
47
+ context = TraceView::Context.toString
48
+ task_id = TraceView::XTrace.task_id(context)
49
+
50
+ if headers.is_a?(Hash) && headers.key?('X-Trace')
51
+ xtrace = headers['X-Trace']
52
+ end
53
+
54
+ if TraceView::XTrace.valid?(xtrace) && TraceView.tracing?
55
+
56
+ # Assure that we received back a valid X-Trace with the same task_id
57
+ if task_id == TraceView::XTrace.task_id(xtrace)
58
+ TraceView::Context.fromString(xtrace)
59
+ else
60
+ TraceView.logger.debug "Mismatched returned X-Trace ID : #{xtrace}"
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ ::TraceView::API.log_exit('em-http-request', report_kvs)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ if RUBY_VERSION >= '1.9'
74
+ if defined?(::EventMachine::HttpConnection) && defined?(::EventMachine::HttpClient) && TraceView::Config[:em_http_request][:enabled]
75
+ TraceView.logger.info '[traceview/loading] Instrumenting em-http-request' if TraceView::Config[:verbose]
76
+
77
+ class ::EventMachine::HttpConnection
78
+ include TraceView::Inst::EventMachine::HttpConnection
79
+
80
+ if method_defined?(:setup_request)
81
+ class_eval 'alias :setup_request_without_traceview :setup_request'
82
+ class_eval 'alias :setup_request :setup_request_with_traceview'
83
+ else
84
+ TraceView.logger.warn '[traceview/loading] Couldn\'t properly instrument em-http-request (:setup_request). Partial traces may occur.'
85
+ end
86
+ end
87
+
88
+ class ::EventMachine::HttpClient
89
+ include TraceView::Inst::EventMachine::HttpClient
90
+
91
+ if method_defined?(:parse_response_header)
92
+ class_eval 'alias :parse_response_header_without_traceview :parse_response_header'
93
+ class_eval 'alias :parse_response_header :parse_response_header_with_traceview'
94
+ else
95
+ TraceView.logger.warn '[traceview/loading] Couldn\'t properly instrument em-http-request (:parse_response_header). Partial traces may occur.'
96
+ end
97
+ end
98
+ end
99
+ end
@@ -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