tingyun_rpm 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -0
  3. data/lib/ting_yun/agent.rb +7 -1
  4. data/lib/ting_yun/agent/collector/error_collector.rb +103 -25
  5. data/lib/ting_yun/agent/collector/error_collector/error_trace_array.rb +2 -0
  6. data/lib/ting_yun/agent/collector/error_collector/noticed_error.rb +20 -13
  7. data/lib/ting_yun/agent/collector/transaction_sampler.rb +4 -1
  8. data/lib/ting_yun/agent/collector/transaction_sampler/class_method.rb +4 -4
  9. data/lib/ting_yun/agent/cross_app/cross_app_tracing.rb +1 -3
  10. data/lib/ting_yun/agent/instance_methods/container_data_manager.rb +6 -0
  11. data/lib/ting_yun/agent/method_tracer_helpers.rb +6 -4
  12. data/lib/ting_yun/agent/transaction.rb +15 -15
  13. data/lib/ting_yun/agent/transaction/apdex.rb +1 -1
  14. data/lib/ting_yun/agent/transaction/class_method.rb +14 -17
  15. data/lib/ting_yun/agent/transaction/exceptions.rb +19 -6
  16. data/lib/ting_yun/agent/transaction/instance_method.rb +8 -4
  17. data/lib/ting_yun/agent/transaction/trace.rb +23 -4
  18. data/lib/ting_yun/agent/transaction/trace_node.rb +26 -6
  19. data/lib/ting_yun/agent/transaction/traced_method_stack.rb +2 -2
  20. data/lib/ting_yun/agent/transaction/transaction_sample_builder.rb +17 -8
  21. data/lib/ting_yun/configuration/default_source.rb +22 -1
  22. data/lib/ting_yun/http/abstract_request.rb +23 -0
  23. data/lib/ting_yun/http/curb_wrappers.rb +76 -0
  24. data/lib/ting_yun/http/excon_wrappers.rb +81 -0
  25. data/lib/ting_yun/http/http_client_request.rb +2 -2
  26. data/lib/ting_yun/http/net_http_request.rb +2 -2
  27. data/lib/ting_yun/http/typhoeus_wrappers.rb +88 -0
  28. data/lib/ting_yun/instrumentation/bunny.rb +3 -3
  29. data/lib/ting_yun/instrumentation/curb.rb +191 -0
  30. data/lib/ting_yun/instrumentation/excon.rb +131 -0
  31. data/lib/ting_yun/instrumentation/grape.rb +4 -2
  32. data/lib/ting_yun/instrumentation/kafka.rb +3 -3
  33. data/lib/ting_yun/instrumentation/memcached.rb +1 -1
  34. data/lib/ting_yun/instrumentation/middleware_proxy.rb +17 -1
  35. data/lib/ting_yun/instrumentation/middleware_tracing.rb +1 -1
  36. data/lib/ting_yun/instrumentation/mongo_command_log_subscriber.rb +1 -0
  37. data/lib/ting_yun/instrumentation/net.rb +24 -24
  38. data/lib/ting_yun/instrumentation/rack.rb +10 -10
  39. data/lib/ting_yun/instrumentation/rails3/action_controller.rb +1 -1
  40. data/lib/ting_yun/instrumentation/rake.rb +8 -4
  41. data/lib/ting_yun/instrumentation/support/action_controller_subscriber.rb +1 -1
  42. data/lib/ting_yun/instrumentation/support/action_view_subscriber.rb +2 -2
  43. data/lib/ting_yun/instrumentation/support/active_record_subscriber.rb +2 -2
  44. data/lib/ting_yun/instrumentation/support/controller_instrumentation.rb +3 -3
  45. data/lib/ting_yun/instrumentation/support/external_error.rb +4 -4
  46. data/lib/ting_yun/instrumentation/support/external_helper.rb +6 -1
  47. data/lib/ting_yun/instrumentation/thrift.rb +1 -1
  48. data/lib/ting_yun/instrumentation/typhoeus.rb +75 -0
  49. data/lib/ting_yun/support/exception.rb +2 -0
  50. data/lib/ting_yun/support/http_clients/uri_util.rb +12 -7
  51. data/lib/ting_yun/ting_yun_service.rb +1 -1
  52. data/lib/ting_yun/ting_yun_service/upload_service.rb +15 -3
  53. data/lib/ting_yun/version.rb +2 -2
  54. metadata +9 -3
  55. data/lib/ting_yun/http/generic_request.rb +0 -8
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/http/abstract_request'
3
+
4
+ module TingYun
5
+ module Http
6
+
7
+
8
+ class CurbRequest
9
+ CURB = 'Curb'.freeze
10
+ LHOST = 'host'.freeze
11
+ UHOST = 'Host'.freeze
12
+
13
+ def initialize( curlobj )
14
+ @curlobj = curlobj
15
+ end
16
+
17
+ def type
18
+ CURB
19
+ end
20
+
21
+ def from
22
+ "curb%2Fhttp"
23
+ end
24
+
25
+ def host_from_header
26
+ self[LHOST] || self[UHOST]
27
+ end
28
+
29
+ def host
30
+ host_from_header || self.uri.host
31
+ end
32
+
33
+ def method
34
+ @curlobj._ty_http_verb
35
+ end
36
+
37
+ def []( key )
38
+ @curlobj.headers[ key ]
39
+ end
40
+
41
+ def []=( key, value )
42
+ @curlobj.headers[ key ] = value
43
+ end
44
+
45
+ def uri
46
+ @uri ||= TingYun::Agent::HTTPClients::URIUtil.parse_and_normalize_url(@curlobj.url)
47
+ end
48
+ end
49
+
50
+
51
+ class CurbResponse < AbstractRequest
52
+ def initialize(curlobj)
53
+ @headers = {}
54
+ @curlobj = curlobj
55
+ end
56
+
57
+ def [](key)
58
+ @headers[ key.downcase ]
59
+ end
60
+
61
+ def to_hash
62
+ @headers.dup
63
+ end
64
+
65
+ def append_header_data( data )
66
+ key, value = data.split( /:\s*/, 2 )
67
+ @headers[ key.downcase ] = value
68
+ @curlobj._ty_header_str ||= ''
69
+ @curlobj._ty_header_str << data
70
+ end
71
+
72
+ end
73
+
74
+
75
+ end
76
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/http/abstract_request'
3
+
4
+ module TingYun
5
+ module Http
6
+
7
+ class ExconHTTPResponse
8
+
9
+ def initialize(response)
10
+ @response = response
11
+ # Since HTTP headers are case-insensitive, we normalize all of them to
12
+ # upper case here, and then also in our [](key) implementation.
13
+ @normalized_headers = {}
14
+ headers = response.respond_to?(:headers) ? response.headers : response[:headers]
15
+ (headers || {}).each do |key, val|
16
+ @normalized_headers[key.upcase] = val
17
+ end
18
+ end
19
+
20
+
21
+ def [](key)
22
+ @normalized_headers[key.upcase]
23
+ end
24
+
25
+ def to_hash
26
+ @normalized_headers.dup
27
+ end
28
+ end
29
+
30
+ class ExconHTTPRequest < AbstractRequest
31
+ attr_reader :method
32
+
33
+ EXCON = "Excon".freeze
34
+ LHOST = 'host'.freeze
35
+ UHOST = 'Host'.freeze
36
+ COLON = ':'.freeze
37
+
38
+ def initialize(datum)
39
+ @datum = datum
40
+
41
+ @method = @datum[:method].to_s.upcase
42
+ @scheme = @datum[:scheme]
43
+ @port = @datum[:port]
44
+ @path = @datum[:path]
45
+ end
46
+
47
+ def type
48
+ EXCON
49
+ end
50
+
51
+ def from
52
+ "excon%2Fhttp"
53
+ end
54
+
55
+ def host_from_header
56
+ headers = @datum[:headers]
57
+ if hostname = (headers[LHOST] || headers[UHOST])
58
+ hostname.split(COLON).first
59
+ end
60
+ end
61
+
62
+ def host
63
+ host_from_header || @datum[:host]
64
+ end
65
+
66
+ def [](key)
67
+ @datum[:headers][key]
68
+ end
69
+
70
+ def []=(key, value)
71
+ @datum[:headers] ||= {}
72
+ @datum[:headers][key] = value
73
+ end
74
+
75
+ def uri
76
+ URI.parse("#{@scheme}://#{host}:#{@port}#{@path}")
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -1,7 +1,7 @@
1
- require 'ting_yun/http/generic_request'
1
+ require 'ting_yun/http/abstract_request'
2
2
  module TingYun
3
3
  module Http
4
- class HttpClientRequest < GenericRequest
4
+ class HttpClientRequest < AbstractRequest
5
5
  attr_reader :method, :header
6
6
 
7
7
  def initialize(proxy, *args, &block)
@@ -1,7 +1,7 @@
1
- require 'ting_yun/http/generic_request'
1
+ require 'ting_yun/http/abstract_request'
2
2
  module TingYun
3
3
  module Http
4
- class NetHttpRequest < GenericRequest
4
+ class NetHttpRequest < AbstractRequest
5
5
  def initialize(connection, request)
6
6
  @connection = connection
7
7
  @request = request
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/http/abstract_request'
3
+
4
+ module TingYun
5
+ module Http
6
+
7
+ class TyphoeusHTTPResponse
8
+ def initialize(response)
9
+ @response = response
10
+ end
11
+
12
+ def [](key)
13
+ unless headers.nil?
14
+ result = headers[key]
15
+
16
+ # Typhoeus 0.5.3 has a bug where asking the headers hash for a
17
+ # non-existent header will return the hash itself, not what we want.
18
+ result == headers ? nil : result
19
+ end
20
+ end
21
+
22
+ def to_hash
23
+ hash = {}
24
+ headers.each do |(k,v)|
25
+ hash[k] = v
26
+ end
27
+ hash
28
+ end
29
+
30
+ private
31
+
32
+ def headers
33
+ @response.headers
34
+ end
35
+ end
36
+
37
+ class TyphoeusHTTPRequest < AbstractRequest
38
+ def initialize(request)
39
+ @request = request
40
+ @uri = case request.url
41
+ when ::URI then request.url
42
+ else TingYun::Agent::HTTPClients::URIUtil.parse_and_normalize_url(request.url)
43
+ end
44
+ end
45
+
46
+ TYPHOEUS = "Typhoeus".freeze
47
+
48
+ def type
49
+ TYPHOEUS
50
+ end
51
+ def from
52
+ "typhoeus%2Fhttp"
53
+ end
54
+
55
+ LHOST = 'host'.freeze
56
+ UHOST = 'Host'.freeze
57
+
58
+ def host_from_header
59
+ self[LHOST] || self[UHOST]
60
+ end
61
+
62
+ def host
63
+ host_from_header || @uri.host
64
+ end
65
+
66
+ GET = 'GET'.freeze
67
+
68
+ def method
69
+ (@request.options[:method] || GET).to_s.upcase
70
+ end
71
+
72
+ def [](key)
73
+ return nil unless @request.options && @request.options[:headers]
74
+ @request.options[:headers][key]
75
+ end
76
+
77
+ def []=(key, value)
78
+ @request.options[:headers] ||= {}
79
+ @request.options[:headers][key] = value
80
+ end
81
+
82
+ def uri
83
+ @uri
84
+ end
85
+ end
86
+ end
87
+
88
+ end
@@ -40,7 +40,7 @@ TingYun::Support::LibraryDetection.defer do
40
40
  metric_name << "Exchange%2F#{name}/Produce"
41
41
  end
42
42
  summary_metrics = TingYun::Instrumentation::Support::ExternalHelper.metrics_for_message('RabbitMQ', "#{@channel.connection.host}:#{@channel.connection.port}", 'Produce')
43
- TingYun::Agent::Transaction.wrap(state, metric_name , :RabbitMQ, {}, summary_metrics) do
43
+ TingYun::Agent::MethodTracerHelpers.trace_execution_scoped(summary_metrics.unshift(metric_name), {}, nil, metric_name) do
44
44
  opts[:headers] = {} unless opts[:headers]
45
45
  opts[:headers]["TingyunID"] = create_tingyun_id("mq") if TingYun::Agent.config[:'nbs.transaction_tracer.enabled']
46
46
  TingYun::Agent.record_metric("#{metric_name}%2FByte",payload.bytesize) if payload
@@ -148,14 +148,14 @@ TingYun::Support::LibraryDetection.defer do
148
148
  state = TingYun::Agent::TransactionState.tl_get
149
149
  metric_name = "#{@connection.host}:#{@connection.port}%2FQueue%2F#{args[0]}/Consume"
150
150
  summary_metrics = TingYun::Instrumentation::Support::ExternalHelper.metrics_for_message('RabbitMQ', "#{connection.host}:#{connection.port}", 'Consume')
151
- TingYun::Agent::Transaction.wrap(state, "Message RabbitMQ/#{metric_name}" , :RabbitMQ, {}, summary_metrics) do
151
+ TingYun::Agent::MethodTracerHelpers.trace_execution_scoped(summary_metrics, {}, nil, "Message RabbitMQ/#{metric_name}") do
152
152
  basic_get_without_tingyun(*args)
153
153
  end
154
154
  rescue =>e
155
155
  TingYun::Agent.logger.error("Failed to Bunny basic_get_with_tingyun : ", e)
156
156
  basic_get_without_tingyun(*args)
157
157
  ensure
158
- TingYun::Agent::Transaction.stop(state, Time.now, summary_metrics)
158
+ TingYun::Agent::Transaction.stop(state, Time.now.to_f, summary_metrics)
159
159
  end
160
160
  end
161
161
 
@@ -0,0 +1,191 @@
1
+ TingYun::Support::LibraryDetection.defer do
2
+ named :curb
3
+
4
+ CURB_MIN_VERSION = Gem::Version.new("0.8.1")
5
+
6
+ depends_on do
7
+ defined?(::Curl) && defined?(::Curl::CURB_VERSION) &&
8
+ Gem::Version.new(::Curl::CURB_VERSION) >= CURB_MIN_VERSION
9
+ end
10
+
11
+ executes do
12
+ ::TingYun::Agent.logger.info 'Installing Curb instrumentation'
13
+ require 'ting_yun/agent/cross_app/cross_app_tracing'
14
+ require 'ting_yun/agent/method_tracer_helpers'
15
+ require 'ting_yun/http/curb_wrappers'
16
+ end
17
+
18
+
19
+
20
+ executes do
21
+ class Curl::Easy
22
+
23
+ attr_accessor :_ty_instrumented,
24
+ :_ty_http_verb,
25
+ :_ty_header_str,
26
+ :_ty_original_on_header,
27
+ :_ty_original_on_complete,
28
+ :_ty_serial
29
+
30
+ # We have to hook these three methods separately, as they don't use
31
+ # Curl::Easy#http
32
+ def http_head_with_tingyun(*args, &blk)
33
+ self._ty_http_verb = :HEAD
34
+ http_head_without_tingyun(*args, &blk)
35
+ end
36
+ alias_method :http_head_without_tingyun, :http_head
37
+ alias_method :http_head, :http_head_with_tingyun
38
+
39
+ def http_post_with_tingyun(*args, &blk)
40
+ self._ty_http_verb = :POST
41
+ http_post_without_tingyun(*args, &blk)
42
+ end
43
+ alias_method :http_post_without_tingyun, :http_post
44
+ alias_method :http_post, :http_post_with_tingyun
45
+
46
+ def http_put_with_tingyun(*args, &blk)
47
+ self._ty_http_verb = :PUT
48
+ http_put_without_tingyun(*args, &blk)
49
+ end
50
+ alias_method :http_put_without_tingyun, :http_put
51
+ alias_method :http_put, :http_put_with_tingyun
52
+
53
+
54
+ # Hook the #http method to set the verb.
55
+ def http_with_tingyun( verb )
56
+ self._ty_http_verb = verb.to_s.upcase
57
+ http_without_tingyun( verb )
58
+ end
59
+
60
+ alias_method :http_without_tingyun, :http
61
+ alias_method :http, :http_with_tingyun
62
+
63
+
64
+ # Hook the #perform method to mark the request as non-parallel.
65
+ def perform_with_tingyun
66
+ self._ty_serial = true
67
+ perform_without_tingyun
68
+ end
69
+
70
+ alias_method :perform_without_tingyun, :perform
71
+ alias_method :perform, :perform_with_tingyun
72
+
73
+ # We override this method in order to ensure access to header_str even
74
+ # though we use an on_header callback
75
+ def header_str_with_tingyun
76
+ if self._ty_serial
77
+ self._ty_header_str
78
+ else
79
+ # Since we didn't install a header callback for a non-serial request,
80
+ # just fall back to the original implementation.
81
+ header_str_without_tingyun
82
+ end
83
+ end
84
+
85
+ alias_method :header_str_without_tingyun, :header_str
86
+ alias_method :header_str, :header_str_with_tingyun
87
+ end # class Curl::Easy
88
+
89
+ class Curl::Multi
90
+
91
+
92
+ # Add CAT with callbacks if the request is serial
93
+ def add_with_tingyun(curl) #THREAD_LOCAL_ACCESS
94
+ if curl.respond_to?(:_ty_serial) && curl._ty_serial
95
+ hook_pending_request(curl) if TingYun::Agent.tl_is_execution_traced?
96
+ end
97
+
98
+ return add_without_tingyun( curl )
99
+ end
100
+
101
+ alias_method :add_without_tingyun, :add
102
+ alias_method :add, :add_with_tingyun
103
+
104
+
105
+ # Trace as an External/Multiple call if the first request isn't serial.
106
+ def perform_with_tingyun(&blk)
107
+ return perform_without_tingyun if
108
+ self.requests.first &&
109
+ self.requests.first.respond_to?(:_ty_serial) &&
110
+ self.requests.first._ty_serial
111
+
112
+ TingYun::Agent::MethodTracerHelpers.trace_execution_scoped("External/Multiple/Curb::Multi/perform") do
113
+ perform_without_tingyun(&blk)
114
+ end
115
+ end
116
+
117
+ alias_method :perform_without_tingyun, :perform
118
+ alias_method :perform, :perform_with_tingyun
119
+
120
+
121
+ # Instrument the specified +request+ (a Curl::Easy object) and set up cross-application
122
+ # tracing if it's enabled.
123
+ def hook_pending_request(request) #THREAD_LOCAL_ACCESS
124
+ wrapped_request, wrapped_response = wrap_request(request)
125
+ state = TingYun::Agent::TransactionState.tl_get
126
+ t0 = Time.now.to_f
127
+ node = TingYun::Agent::CrossAppTracing.start_trace(state, t0, wrapped_request)
128
+
129
+ unless request._ty_instrumented
130
+ install_header_callback( request, wrapped_response )
131
+ install_completion_callback( request, t0, node, wrapped_request, wrapped_response )
132
+ request._ty_instrumented = true
133
+ end
134
+ rescue => err
135
+ TingYun::Agent.logger.error("Untrapped exception", err)
136
+ end
137
+
138
+
139
+ # Create request and response adapter objects for the specified +request+
140
+ def wrap_request(request)
141
+ return TingYun::Http::CurbRequest.new(request),
142
+ TingYun::Http::CurbResponse.new(request)
143
+ end
144
+
145
+
146
+
147
+ # Install a callback that will record the response headers to enable
148
+ # CAT linking
149
+ def install_header_callback( request, wrapped_response )
150
+ original_callback = request.on_header
151
+ request._ty_original_on_header = original_callback
152
+ request._ty_header_str = ''
153
+ request.on_header do |header_data|
154
+ wrapped_response.append_header_data( header_data )
155
+
156
+ if original_callback
157
+ original_callback.call( header_data )
158
+ else
159
+ header_data.length
160
+ end
161
+ end
162
+ end
163
+
164
+ # Install a callback that will finish the trace.
165
+ def install_completion_callback( request, t0, segment, wrapped_request, wrapped_response )
166
+ original_callback = request.on_complete
167
+ request._ty_original_on_complete = original_callback
168
+ request.on_complete do |finished_request|
169
+ begin
170
+ TingYun::Agent::CrossAppTracing.finish_trace(TingYun::Agent::TransactionState.tl_get,t0, segment, wrapped_request, wrapped_response )
171
+ ensure
172
+ # Make sure the existing completion callback is run, and restore the
173
+ # on_complete callback to how it was before.
174
+ original_callback.call( finished_request ) if original_callback
175
+ remove_instrumentation_callbacks( request )
176
+ end
177
+ end
178
+ end
179
+
180
+ def remove_instrumentation_callbacks( request )
181
+ request.on_complete(&request._ty_original_on_complete)
182
+ request.on_header(&request._ty_original_on_header)
183
+ request._ty_instrumented = false
184
+ end
185
+
186
+ end # class Curl::Multi
187
+
188
+ end
189
+
190
+
191
+ end