right_agent 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/lib/right_agent.rb +1 -0
  3. data/lib/right_agent/actor.rb +0 -28
  4. data/lib/right_agent/actors/agent_manager.rb +20 -18
  5. data/lib/right_agent/agent.rb +69 -87
  6. data/lib/right_agent/agent_tag_manager.rb +1 -1
  7. data/lib/right_agent/clients/api_client.rb +0 -1
  8. data/lib/right_agent/clients/auth_client.rb +2 -6
  9. data/lib/right_agent/clients/balanced_http_client.rb +2 -2
  10. data/lib/right_agent/clients/base_retry_client.rb +12 -19
  11. data/lib/right_agent/clients/right_http_client.rb +1 -5
  12. data/lib/right_agent/clients/router_client.rb +8 -15
  13. data/lib/right_agent/command/command_parser.rb +3 -3
  14. data/lib/right_agent/command/command_runner.rb +1 -1
  15. data/lib/right_agent/connectivity_checker.rb +7 -11
  16. data/lib/right_agent/dispatcher.rb +7 -42
  17. data/lib/right_agent/enrollment_result.rb +2 -2
  18. data/lib/right_agent/error_tracker.rb +202 -0
  19. data/lib/right_agent/log.rb +0 -2
  20. data/lib/right_agent/packets.rb +1 -1
  21. data/lib/right_agent/pending_requests.rb +10 -4
  22. data/lib/right_agent/pid_file.rb +3 -3
  23. data/lib/right_agent/protocol_version_mixin.rb +3 -3
  24. data/lib/right_agent/scripts/agent_deployer.rb +13 -1
  25. data/lib/right_agent/sender.rb +14 -30
  26. data/lib/right_agent/serialize/secure_serializer.rb +4 -4
  27. data/right_agent.gemspec +2 -2
  28. data/spec/agent_spec.rb +5 -5
  29. data/spec/clients/auth_client_spec.rb +1 -1
  30. data/spec/clients/balanced_http_client_spec.rb +4 -2
  31. data/spec/clients/base_retry_client_spec.rb +5 -6
  32. data/spec/clients/router_client_spec.rb +1 -4
  33. data/spec/dispatcher_spec.rb +6 -55
  34. data/spec/error_tracker_spec.rb +293 -0
  35. data/spec/pending_requests_spec.rb +2 -2
  36. data/spec/sender_spec.rb +3 -3
  37. data/spec/spec_helper.rb +4 -2
  38. metadata +33 -66
@@ -20,8 +20,8 @@ module RightScale
20
20
  # Versions 5 and above use an identical format for the enrollment result
21
21
  SUPPORTED_VERSIONS = 5..AgentConfig.protocol_version
22
22
 
23
- class IntegrityFailure < Exception; end
24
- class VersionError < Exception; end
23
+ class IntegrityFailure < StandardError; end
24
+ class VersionError < StandardError; end
25
25
 
26
26
  attr_reader :r_s_version, :timestamp, :router_cert, :id_cert, :id_key
27
27
 
@@ -0,0 +1,202 @@
1
+ # Copyright (c) 2014 RightScale, Inc, All Rights Reserved Worldwide.
2
+ #
3
+ # THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
4
+ # AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
5
+ # reproduction, modification, or disclosure of this program is
6
+ # strictly prohibited. Any use of this program by an authorized
7
+ # licensee is strictly subject to the terms and conditions,
8
+ # including confidentiality obligations, set forth in the applicable
9
+ # License Agreement between RightScale.com, Inc. and
10
+ # the licensee.
11
+
12
+ module RightScale
13
+
14
+ # Tracker for unexpected errors
15
+ # Logs them with appropriate trace information
16
+ # Accumulates statistics about exceptions
17
+ # Reports exceptions to external Errbit service via HydraulicBrake
18
+ class ErrorTracker
19
+
20
+ include RightSupport::Ruby::EasySingleton
21
+
22
+ # Container for exception statistics
23
+ attr_reader :exception_stats
24
+
25
+ # Initialize error tracker
26
+ #
27
+ # @param [Object] agent object using this tracker
28
+ # @param [String] agent_name uniquely identifying agent process on given server
29
+ #
30
+ # @option options [Integer, NilClass] :shard_id identifying shard of database in use
31
+ # @option options [Hash] :trace_level for restricting backtracing and Errbit reporting
32
+ # with exception class as key and :no_trace, :caller, or :trace as value; exceptions
33
+ # with :no_trace are not backtraced when logging nor are they recorded in stats
34
+ # or reported to Errbit
35
+ # @option options [String] :airbrake_endpoint URL for Airbrake for reporting exceptions
36
+ # to Errbit
37
+ # @option options [String] :airbrake_api_key for using the Airbrake API to access Errbit
38
+ #
39
+ # @return [TrueClass] always true
40
+ def init(agent, agent_name, options = {})
41
+ @agent = agent
42
+ @trace_level = options[:trace_level] || {}
43
+ notify_init(agent_name, options[:shard_id], options[:airbrake_endpoint], options[:airbrake_api_key])
44
+ reset_stats
45
+ true
46
+ end
47
+
48
+ # Log error and optionally track in stats
49
+ # Errbit notification is left to the callback configured in the stats tracker
50
+ #
51
+ # @param [String, Object] component reporting error; non-string is snake-cased
52
+ # @param [String] description of failure for use in logging
53
+ # @param [Exception, String] exception to be logged and tracked in stats;
54
+ # string errors are logged but not tracked in stats
55
+ # @param [Packet, Hash, NilClass] packet associated with exception
56
+ # @param [Symbol, NilClass] trace level override unless excluded by configured
57
+ # trace levels
58
+ #
59
+ # @return [Boolean] true if successfully logged, otherwise false
60
+ def log(component, description, exception = nil, packet = nil, trace = nil)
61
+ if exception.nil?
62
+ Log.error(description)
63
+ elsif exception.is_a?(String)
64
+ Log.error(description, exception)
65
+ else
66
+ trace = (@trace_level && @trace_level[exception.class]) || trace || :trace
67
+ Log.error(description, exception, trace)
68
+ track(component, exception, packet) if trace != :no_trace
69
+ end
70
+ true
71
+ rescue StandardError => e
72
+ Log.error("Failed to log error", e, :trace) rescue nil
73
+ false
74
+ end
75
+
76
+ # Track error in stats
77
+ #
78
+ # @param [String] component reporting error
79
+ # @param [Exception] exception to be tracked
80
+ # @param [Packet, Hash, NilClass] packet associated with exception
81
+ #
82
+ # @return [TrueClass] always true
83
+ def track(component, exception, packet = nil)
84
+ component = component.class.name.split("::").last.snake_case unless component.is_a?(String)
85
+ @exception_stats.track(component, exception, packet)
86
+ end
87
+
88
+ # Notify Errbit of error if notification enabled
89
+ #
90
+ # @param [Exception, String] exception raised
91
+ # @param [Packet, Hash] packet associated with exception
92
+ # @param [Object] agent object reporting error
93
+ # @param [String] component or service area where error occurred
94
+ #
95
+ # @return [TrueClass] always true
96
+ def notify(exception, packet = nil, agent = nil, component = nil)
97
+ if @notify_enabled
98
+ data = {
99
+ :error_message => exception.respond_to?(:message) ? exception.message : exception.to_s,
100
+ :backtrace => exception.respond_to?(:backtrace) ? exception.backtrace : caller,
101
+ :environment_name => ENV["RAILS_ENV"],
102
+ }
103
+ if agent
104
+ data[:cgi_data] = (@cgi_data || {}).merge(:agent_class => agent.class.name)
105
+ elsif @cgi_data
106
+ data[:cgi_data] = @cgi_data
107
+ end
108
+ data[:error_class] = exception.class.name if exception.is_a?(Exception)
109
+ data[:component] = component if component
110
+ if packet && packet.is_a?(Packet)
111
+ data[:action] = packet.type.split("/").last if packet.respond_to?(:type)
112
+ data[:parameters] = packet.payload if packet.respond_to?(:payload)
113
+ uuid = packet.token if packet.respond_to?(:token)
114
+ elsif packet.is_a?(Hash)
115
+ action = packet[:path] || packet["path"]
116
+ data[:action] = action.split("/").last if action
117
+ data[:parameters] = packet[:data] || packet["data"]
118
+ uuid = packet[:uuid] || packet["uuid"]
119
+ end
120
+ data[:session_data] = {:uuid => uuid} if uuid
121
+ HydraulicBrake.notify(data)
122
+ end
123
+ true
124
+ rescue Exception => e
125
+ Log.error("Failed to notify Errbit", e, :trace)
126
+ end
127
+
128
+ # Create proc for making callback to notifier
129
+ #
130
+ # @return [Proc] notifier callback
131
+ def notify_callback
132
+ Proc.new do |exception, packet, agent, component|
133
+ notify(exception, packet, agent, component)
134
+ end
135
+ end
136
+
137
+ # Get exception statistics
138
+ #
139
+ # @param reset [Boolean] Whether to reset the statistics after getting the current ones
140
+ #
141
+ # @return [Hash] current statistics
142
+ def stats(reset = false)
143
+ stats = {"exceptions" => @exception_stats.all}
144
+ reset_stats if reset
145
+ stats
146
+ end
147
+
148
+ protected
149
+
150
+ # Reset statistics
151
+ # Do not recreate exception stats since may be referenced externally
152
+ #
153
+ # @return [TrueClass] always true
154
+ def reset_stats
155
+ @exception_stats ||= RightSupport::Stats::Exceptions.new(@agent, notify_callback)
156
+ @exception_stats.reset
157
+ end
158
+
159
+ # Configure HydraulicBreak for exception notification
160
+ #
161
+ # @param [String] agent_name uniquely identifying agent process on given server
162
+ # @param [Integer, NilClass] shard_id identifying shard of database in use
163
+ # @param [String] endpoint URL for Airbrake for reporting exceptions to Errbit
164
+ # @param [String] api_key for using the Airbrake API to access Errbit
165
+ #
166
+ # @return [TrueClass] always true
167
+ #
168
+ # @raise [RuntimeError] hydraulic_brake gem missing
169
+ def notify_init(agent_name, shard_id, endpoint, api_key)
170
+ if endpoint && api_key
171
+ unless require_succeeds?("hydraulic_brake")
172
+ raise RuntimeError, "hydraulic_brake gem missing - required if airbrake options used in ErrorTracker"
173
+ end
174
+
175
+ @cgi_data = {
176
+ :shard_id => shard_id,
177
+ :process => $0,
178
+ :pid => Process.pid,
179
+ :agent_name => agent_name
180
+ }
181
+ @cgi_data[:shard_id] = shard_id if shard_id
182
+ @cgi_data[:sha] = CURRENT_SOURCE_SHA if defined?(CURRENT_SOURCE_SHA)
183
+
184
+ uri = URI.parse(endpoint)
185
+ HydraulicBrake.configure do |config|
186
+ config.secure = (uri.scheme == "https")
187
+ config.host = uri.host
188
+ config.port = uri.port
189
+ config.api_key = api_key
190
+ config.project_root = AgentConfig.root_dir
191
+ end
192
+ @notify_enabled = true
193
+ else
194
+ @cgi_data = {}
195
+ @notify_enabled = false
196
+ end
197
+ true
198
+ end
199
+
200
+ end # ErrorTracker
201
+
202
+ end # RightScale
@@ -410,8 +410,6 @@ module RightScale
410
410
  @logger = logger
411
411
  end
412
412
 
413
- protected
414
-
415
413
  # Initialize logger
416
414
  #
417
415
  # === Parameters
@@ -107,7 +107,7 @@ module RightScale
107
107
  }.to_msgpack(*a)
108
108
  @size = msg.size
109
109
  # For ruby 1.9 size attribute moves from front to back of packet
110
- re = RUBY_VERSION < "1.9.0" ? /size\xC0/ : /size\xC0$/
110
+ re = RUBY_VERSION < "1.9.0" ? Regexp.new("size\xC0") : Regexp.new("size\xC0$", nil, "n")
111
111
  # For msgpack 0.5.1 the to_msgpack result is a MessagePack::Packer so need to convert to string
112
112
  msg = msg.to_s.sub!(re) { |m| "size" + @size.to_msgpack }
113
113
  msg
@@ -97,12 +97,15 @@ module RightScale
97
97
 
98
98
  # Get age of youngest pending request
99
99
  #
100
+ # === Parameters
101
+ # pending_requests(Hash):: Pending requests to be examined
102
+ #
100
103
  # === Return
101
104
  # age(Integer):: Age of youngest request
102
- def youngest_age
105
+ def self.youngest_age(pending_requests)
103
106
  now = Time.now
104
107
  age = nil
105
- self.each_value do |r|
108
+ pending_requests.each_value do |r|
106
109
  seconds = (now - r.receive_time).to_i
107
110
  age = seconds if age.nil? || seconds < age
108
111
  end
@@ -111,12 +114,15 @@ module RightScale
111
114
 
112
115
  # Get age of oldest pending request
113
116
  #
117
+ # === Parameters
118
+ # pending_requests(Hash):: Pending requests to be examined
119
+ #
114
120
  # === Return
115
121
  # age(Integer):: Age of oldest request
116
- def oldest_age
122
+ def self.oldest_age(pending_requests)
117
123
  now = Time.now
118
124
  age = nil
119
- self.each_value do |r|
125
+ pending_requests.each_value do |r|
120
126
  seconds = (now - r.receive_time).to_i
121
127
  age = seconds if age.nil? || seconds > age
122
128
  end
@@ -31,7 +31,7 @@ module RightScale
31
31
  # the command protocol
32
32
  class PidFile
33
33
 
34
- class AlreadyRunning < Exception; end
34
+ class AlreadyRunning < RuntimeError; end
35
35
 
36
36
  attr_reader :identity, :pid_file, :cookie_file
37
37
 
@@ -72,8 +72,8 @@ module RightScale
72
72
  FileUtils.mkdir_p(@pid_dir)
73
73
  open(@pid_file,'w') { |f| f.write(Process.pid) }
74
74
  File.chmod(0644, @pid_file)
75
- rescue Exception => e
76
- Log.error "Failed to create PID file: #{e.message}"
75
+ rescue StandardError => e
76
+ ErrorTracker.log(self, "Failed to create PID file", e, nil, :caller)
77
77
  raise
78
78
  end
79
79
  true
@@ -34,9 +34,9 @@ module RightScale
34
34
  # Packet::DEFAULT_VERSION, which is true of all with version >= 12)
35
35
  def can_put_version_in_packet?(version); version && version != 0 end
36
36
 
37
- # Test whether given version of agent uses /mapper/query_tags rather than the
38
- # deprecated TagQuery packet
39
- def can_use_mapper_query_tags?(version); version && version >= 8 end
37
+ # Test whether given version of agent uses /router/query_tags or /mapper/query_tags
38
+ # rather than the deprecated TagQuery packet
39
+ def can_use_router_query_tags?(version); version && version >= 8 end
40
40
 
41
41
  # Test whether given version of agent can handle a request that is being retried
42
42
  # as indicated by a retries count in the Request packet
@@ -45,6 +45,8 @@
45
45
  # --grace-timeout SEC Set number of seconds before graceful termination times out
46
46
  # --[no-]dup-check Set whether to check for and reject duplicate requests, .e.g., due to retries
47
47
  # --fiber-pool-size, -f N Set size of fiber pool
48
+ # --airbrake-endpoint URL Set URL for Airbrake endpoint for reporting exceptions to Errbit
49
+ # --airbrake-api-key KEY Set Airbrake API key for use in reporting exceptions to Errbit
48
50
  # --options, -o KEY=VAL Set options that act as final override for any persisted configuration settings
49
51
  # --monit Generate monit configuration file
50
52
  # --test Build test deployment using default test settings
@@ -205,6 +207,14 @@ module RightScale
205
207
  options[:heartbeat] = sec.to_i
206
208
  end
207
209
 
210
+ opts.on('--airbrake-endpoint URL') do |url|
211
+ options[:airbrake_endpoint] = url
212
+ end
213
+
214
+ opts.on('--airbrake-api-key KEY') do |key|
215
+ options[:airbrake_api_key] = key
216
+ end
217
+
208
218
  opts.on('-o', '--options OPT') do |e|
209
219
  fail("Invalid option definition #{e}' (use '=' to separate name and value)") unless e.include?('=')
210
220
  key, val = e.split(/=/)
@@ -277,7 +287,7 @@ module RightScale
277
287
  actors_dirs = AgentConfig.actors_dirs
278
288
  actors.each do |a|
279
289
  found = false
280
- actors_dirs.each { |d| break if found = File.exist?(File.normalize_path(File.join(d, "#{a}.rb"))) }
290
+ actors_dirs.each { |d| break if (found = File.exist?(File.normalize_path(File.join(d, "#{a}.rb")))) }
281
291
  fail("Cannot find source for actor #{a.inspect} in #{actors_dirs.inspect}") unless found
282
292
  end
283
293
  true
@@ -318,6 +328,8 @@ module RightScale
318
328
  cfg[:http_proxy] = options[:http_proxy] if options[:http_proxy]
319
329
  cfg[:http_no_proxy] = options[:http_no_proxy] if options[:http_no_proxy]
320
330
  cfg[:fiber_pool_size] = options[:fiber_pool_size] if options[:fiber_pool_size]
331
+ cfg[:airbrake_endpoint] = options[:airbrake_endpoint] if options[:airbrake_endpoint]
332
+ cfg[:airbrake_api_key] = options[:airbrake_api_key] if options[:airbrake_api_key]
321
333
  cfg
322
334
  end
323
335
 
@@ -68,10 +68,6 @@ module RightScale
68
68
  #
69
69
  # === Parameters
70
70
  # agent(Agent):: Agent using this sender; uses its identity, client, and following options:
71
- # :exception_callback(Proc):: Callback with following parameters that is activated on exception events:
72
- # exception(Exception):: Exception
73
- # message(Packet):: Message being processed
74
- # agent(Agent):: Reference to agent
75
71
  # :offline_queueing(Boolean):: Whether to queue request if client currently disconnected,
76
72
  # also requires agent invocation of initialize_offline_queue and start_offline_queue methods below,
77
73
  # as well as enable_offline_mode and disable_offline_mode as client connection status changes
@@ -102,7 +98,7 @@ module RightScale
102
98
  @connectivity_checker = if @mode == :amqp
103
99
  # Only need connectivity checker for AMQP broker since RightHttpClient does its own checking
104
100
  # via periodic session renewal
105
- ConnectivityChecker.new(self, @options[:ping_interval] || 0, @ping_stats, @exception_stats)
101
+ ConnectivityChecker.new(self, @options[:ping_interval] || 0, @ping_stats)
106
102
  end
107
103
  @@instance = self
108
104
  end
@@ -418,7 +414,7 @@ module RightScale
418
414
  @offline_handler.terminate
419
415
  @connectivity_checker.terminate if @connectivity_checker
420
416
  pending = @pending_requests.kind(:send_request)
421
- [pending.size, pending.youngest_age]
417
+ [pending.size, PendingRequests.youngest_age(pending)]
422
418
  else
423
419
  [0, nil]
424
420
  end
@@ -448,9 +444,6 @@ module RightScale
448
444
  #
449
445
  # === Return
450
446
  # stats(Hash):: Current statistics:
451
- # "exceptions"(Hash|nil):: Exceptions raised per category, or nil if none
452
- # "total"(Integer):: Total exceptions for this category
453
- # "recent"(Array):: Most recent as a hash of "count", "type", "message", "when", and "where"
454
447
  # "non-deliveries"(Hash|nil):: Non-delivery activity stats with keys "total", "percent", "last",
455
448
  # and 'rate' with percentage breakdown per reason, or nil if none
456
449
  # "offlines"(Hash|nil):: Offline activity stats with keys "total", "last", and "duration",
@@ -482,11 +475,10 @@ module RightScale
482
475
  pending["pushes"] = @pending_requests.kind(:send_push).size
483
476
  requests = @pending_requests.kind(:send_request)
484
477
  if (pending["requests"] = requests.size) > 0
485
- pending["oldest age"] = requests.oldest_age
478
+ pending["oldest age"] = PendingRequests.oldest_age(requests)
486
479
  end
487
480
  end
488
481
  stats = {
489
- "exceptions" => @exception_stats.stats,
490
482
  "non-deliveries" => @non_delivery_stats.all,
491
483
  "offlines" => offlines,
492
484
  "pings" => @ping_stats.all,
@@ -520,7 +512,6 @@ module RightScale
520
512
  @offline_stats = RightSupport::Stats::Activity.new(measure_rate = false)
521
513
  @request_kind_stats = RightSupport::Stats::Activity.new(measure_rate = false)
522
514
  @send_failure_stats = RightSupport::Stats::Activity.new
523
- @exception_stats = RightSupport::Stats::Exceptions.new(@agent, @options[:exception_callback])
524
515
  true
525
516
  end
526
517
 
@@ -614,9 +605,8 @@ module RightScale
614
605
  EM_S.next_tick do
615
606
  begin
616
607
  http_send_once(kind, target, packet, received_at, &callback)
617
- rescue Exception => e
618
- Log.error("Failed sending or handling response for #{packet.trace} #{packet.type}", e, :trace)
619
- @exception_stats.track("request", e)
608
+ rescue StandardError => e
609
+ ErrorTracker.log(self, "Failed sending or handling response for #{packet.trace} #{packet.type}", e)
620
610
  end
621
611
  end
622
612
  else
@@ -668,8 +658,7 @@ module RightScale
668
658
  result = error_result(e.inspect)
669
659
  else
670
660
  agent_type = AgentIdentity.parse(@identity).agent_type
671
- Log.error("Failed to send #{packet.trace} #{packet.type}", e, :trace)
672
- @exception_stats.track("request", e)
661
+ ErrorTracker.log(self, "Failed to send #{packet.trace} #{packet.type}", e)
673
662
  result = error_result("#{agent_type.capitalize} agent internal error")
674
663
  end
675
664
  end
@@ -739,21 +728,17 @@ module RightScale
739
728
  # TemporarilyOffline:: If cannot send request because RightNet client currently disconnected
740
729
  # and offline queueing is disabled
741
730
  def amqp_send_once(packet, ids = nil)
742
- name =
743
731
  exchange = {:type => :fanout, :name => @request_queue, :options => {:durable => true, :no_declare => @secure}}
744
732
  @agent.client.publish(exchange, packet, :persistent => packet.persistent, :mandatory => true,
745
733
  :log_filter => [:tags, :target, :tries, :persistent], :brokers => ids)
746
734
  rescue RightAMQP::HABrokerClient::NoConnectedBrokers => e
747
- msg = "Failed to publish request #{packet.trace} #{packet.type}"
748
- Log.error(msg, e)
735
+ ErrorTracker.log(self, error = "Failed to publish request #{packet.trace} #{packet.type}", e, packet)
749
736
  @send_failure_stats.update("NoConnectedBrokers")
750
- raise TemporarilyOffline.new(msg + " (#{e.class}: #{e.message})")
751
- rescue Exception => e
752
- msg = "Failed to publish request #{packet.trace} #{packet.type}"
753
- Log.error(msg, e, :trace)
737
+ raise TemporarilyOffline.new(error + " (#{e.class}: #{e.message})")
738
+ rescue StandardError => e
739
+ ErrorTracker.log(self, error = "Failed to publish request #{packet.trace} #{packet.type}", e, packet)
754
740
  @send_failure_stats.update(e.class.name)
755
- @exception_stats.track("publish", e, packet)
756
- raise SendFailure.new(msg + " (#{e.class}: #{e.message})")
741
+ raise SendFailure.new(error + " (#{e.class}: #{e.message})")
757
742
  end
758
743
 
759
744
  # Send request via AMQP with one or more retries if do not receive a response in time
@@ -802,14 +787,13 @@ module RightScale
802
787
  @connectivity_checker.check(check_broker_ids.first) if check_broker_ids.any? && count == 1
803
788
  end
804
789
  rescue TemporarilyOffline => e
805
- Log.error("Failed retry for #{packet.trace} #{packet.type} because temporarily offline")
790
+ ErrorTracker.log(self, "Failed retry for #{packet.trace} #{packet.type} because temporarily offline")
806
791
  rescue SendFailure => e
807
- Log.error("Failed retry for #{packet.trace} #{packet.type} because of send failure")
792
+ ErrorTracker.log(self, "Failed retry for #{packet.trace} #{packet.type} because of send failure")
808
793
  rescue Exception => e
809
794
  # Not sending a response here because something more basic is broken in the retry
810
795
  # mechanism and don't want an error response to preempt a delayed actual response
811
- Log.error("Failed retry for #{packet.trace} #{packet.type} without responding", e, :trace)
812
- @exception_stats.track("retry", e, packet)
796
+ ErrorTracker.log(self, "Failed retry for #{packet.trace} #{packet.type} without responding", e, packet)
813
797
  end
814
798
  end
815
799
  end