honeybadger 2.0.12 → 2.1.0.beta.1

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.
@@ -26,6 +26,15 @@ module Honeybadger
26
26
  Plugin.register do
27
27
  requirement { config[:'exceptions.local_variables'] }
28
28
  requirement { defined?(::BindingOfCaller) }
29
+ requirement do
30
+ if res = defined?(::BetterErrors)
31
+ logger.warn("The local variables feature is incompatible with the " \
32
+ "better_errors gem; to remove this warning, set " \
33
+ "exceptions.local_variables to false for environments " \
34
+ "which load better_errors.")
35
+ end
36
+ !res
37
+ end
29
38
  requirement { !::Exception.included_modules.include?(ExceptionExtension) }
30
39
 
31
40
  execution { ::Exception.send(:include, ExceptionExtension) }
@@ -1,4 +1,5 @@
1
1
  require 'honeybadger/plugin'
2
+ require 'honeybadger/trace'
2
3
 
3
4
  module Honeybadger
4
5
  module Plugins
@@ -18,7 +19,9 @@ module Honeybadger
18
19
  end
19
20
 
20
21
  ActiveSupport::Notifications.instrument("net_http.request", { :uri => uri, :method => request.method }) do
21
- request_without_honeybadger(*args, &block)
22
+ # Disable tracing during #request so that additional calls (i.e.
23
+ # when connection wasn't started) don't result in double counting.
24
+ Trace.ignore_events { request_without_honeybadger(*args, &block) }
22
25
  end
23
26
  end
24
27
  end
@@ -0,0 +1,63 @@
1
+ require 'honeybadger/plugin'
2
+ require 'honeybadger'
3
+
4
+ module Honeybadger
5
+ module Plugins
6
+ module Resque
7
+ module Extension
8
+ def around_perform_with_honeybadger(*args)
9
+ Honeybadger.flush do
10
+ begin
11
+ Honeybadger::Trace.instrument("#{self.name}#perform", { source: 'resque', class: self.name }) do
12
+ yield
13
+ end
14
+ rescue Exception => e
15
+ Honeybadger.notify(e, parameters: { job_arguments: args })
16
+ raise e
17
+ end
18
+ end
19
+ ensure
20
+ Honeybadger.context.clear!
21
+ end
22
+ end
23
+
24
+ module Installer
25
+ def self.included(base)
26
+ base.send(:alias_method, :payload_class_without_honeybadger, :payload_class)
27
+ base.send(:alias_method, :payload_class, :payload_class_with_honeybadger)
28
+ end
29
+
30
+ def payload_class_with_honeybadger
31
+ payload_class_without_honeybadger.tap do |klass|
32
+ unless klass.respond_to?(:around_perform_with_honeybadger)
33
+ klass.instance_eval do
34
+ extend(::Honeybadger::Plugins::Resque::Extension)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ Plugin.register do
42
+ requirement { defined?(::Resque::Job) }
43
+
44
+ requirement do
45
+ if resque_honeybadger = defined?(::Resque::Failure::Honeybadger)
46
+ logger.warn("Support for Resque has been moved " \
47
+ "to the honeybadger gem. Please remove " \
48
+ "resque-honeybadger from your " \
49
+ "Gemfile.")
50
+ end
51
+ !resque_honeybadger
52
+ end
53
+
54
+ execution do
55
+ ::Resque::Job.send(:include, Installer)
56
+ ::Resque.after_fork do |job|
57
+ Honeybadger::Agent.fork
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -17,15 +17,18 @@ module Honeybadger
17
17
  requirement { defined?(::Sidekiq) }
18
18
 
19
19
  execution do
20
- ::Sidekiq.configure_server do |config|
21
- config.server_middleware do |chain|
20
+ ::Sidekiq.configure_server do |sidekiq|
21
+ sidekiq.server_middleware do |chain|
22
22
  chain.add Middleware
23
23
  end
24
24
  end
25
25
 
26
26
  if defined?(::Sidekiq::VERSION) && ::Sidekiq::VERSION > '3'
27
- ::Sidekiq.configure_server do |config|
28
- config.error_handlers << Proc.new {|ex,context| Honeybadger.notify_or_ignore(ex, parameters: context) }
27
+ ::Sidekiq.configure_server do |sidekiq|
28
+ sidekiq.error_handlers << lambda {|ex, params|
29
+ return if params['retry'] && params['retry_count'].to_i < config[:'sidekiq.attempt_threshold'].to_i
30
+ Honeybadger.notify_or_ignore(ex, parameters: params)
31
+ }
29
32
  end
30
33
  end
31
34
  end
@@ -15,7 +15,31 @@ module Honeybadger
15
15
  end
16
16
 
17
17
  def self.instrument(key, payload = {}, &block)
18
- new(SecureRandom.uuid).instrument(key, payload, &block)
18
+ current = self.current
19
+ self.create(SecureRandom.uuid).instrument(key, payload, &block)
20
+ ensure
21
+ Thread.current[:__hb_trace] = current
22
+ end
23
+
24
+ # Internal: Disables event tracing for executed code block.
25
+ #
26
+ # block - The code which should not be traced.
27
+ #
28
+ # Returns the return value from the block.
29
+ def self.ignore_events
30
+ return yield if ignoring_events?
31
+
32
+ begin
33
+ Thread.current[:__hb_ignore_trace_events] = true
34
+ yield
35
+ ensure
36
+ Thread.current[:__hb_ignore_trace_events] = false
37
+ end
38
+ end
39
+
40
+ # Internal: Is event tracing currently disabled?
41
+ def self.ignoring_events?
42
+ !!Thread.current[:__hb_ignore_trace_events]
19
43
  end
20
44
 
21
45
  def initialize(id)
@@ -27,28 +51,28 @@ module Honeybadger
27
51
  end
28
52
 
29
53
  def add(event)
54
+ return if ignoring_events?
30
55
  ce = clean_event(event)
31
56
  @events << ce.to_a if ce.render?
32
57
  end
33
58
 
34
59
  def add_query(event)
35
- if event.duration < 6
36
- ce = clean_event(event)
37
- return unless ce.render?
38
- query = ce.to_s
39
- if @fast_queries[query]
40
- @fast_queries[query][:duration] += ce.event.duration
41
- @fast_queries[query][:count] += 1
42
- else
43
- @fast_queries[query] = { :duration => ce.event.duration, :count => 1 }
44
- end
60
+ return if ignoring_events?
61
+ return add(event) unless event.duration < 6
62
+
63
+ ce = clean_event(event)
64
+ return unless ce.render?
65
+ query = ce.to_s
66
+ if @fast_queries[query]
67
+ @fast_queries[query][:duration] += ce.event.duration
68
+ @fast_queries[query][:count] += 1
45
69
  else
46
- add(event)
70
+ @fast_queries[query] = { :duration => ce.event.duration, :count => 1 }
47
71
  end
48
72
  end
49
73
 
50
- def complete(event)
51
- @meta = clean_event(event).to_h
74
+ def complete(event, payload = {})
75
+ @meta = clean_event(event).to_h.merge(payload)
52
76
  @duration = event.duration
53
77
  @key = "#{event.payload[:controller]}##{event.payload[:action]}"
54
78
  Thread.current[:__hb_trace] = nil
@@ -72,8 +96,16 @@ module Honeybadger
72
96
  @meta.merge({ :events => @events, :key => @key, :fast_queries => @fast_queries.map {|k,v| [ k, v[:duration], v[:count] ] } })
73
97
  end
74
98
 
99
+ # Private helpers: use at your own risk.
100
+
101
+ attr_reader :meta
102
+
75
103
  protected
76
104
 
105
+ def ignoring_events?
106
+ self.class.ignoring_events?
107
+ end
108
+
77
109
  def clean_event(event)
78
110
  TraceCleaner.create(event)
79
111
  end
@@ -0,0 +1,36 @@
1
+ require 'honeybadger/util/sanitizer'
2
+
3
+ module Honeybadger
4
+ module Util
5
+ # Internal: Constructs/sanitizes request data for notices and traces.
6
+ module RequestPayload
7
+ # Internal: default values to use for request data.
8
+ DEFAULTS = {
9
+ url: nil,
10
+ component: nil,
11
+ action: nil,
12
+ params: {}.freeze,
13
+ session: {}.freeze,
14
+ cgi_data: {}.freeze
15
+ }.freeze
16
+
17
+ # Internal: allowed keys.
18
+ KEYS = DEFAULTS.keys.freeze
19
+
20
+ def self.build(opts = {})
21
+ sanitizer = opts.fetch(:sanitizer) { Sanitizer.new }
22
+
23
+ payload = DEFAULTS.dup
24
+ KEYS.each do |key|
25
+ next unless opts[key]
26
+ payload[key] = sanitizer.sanitize(opts[key])
27
+ end
28
+
29
+ payload[:session] = opts[:session][:data] if opts[:session] && opts[:session][:data]
30
+ payload[:url] = sanitizer.filter_url(payload[:url]) if payload[:url]
31
+
32
+ payload
33
+ end
34
+ end
35
+ end
36
+ end
@@ -5,6 +5,10 @@ module Honeybadger
5
5
 
6
6
  FILTERED_REPLACEMENT = '[FILTERED]'.freeze
7
7
 
8
+ TRUNCATION_REPLACEMENT = '[TRUNCATED]'.freeze
9
+
10
+ MAX_STRING_SIZE = 2048
11
+
8
12
  def initialize(opts = {})
9
13
  @max_depth = opts.fetch(:max_depth, 20)
10
14
 
@@ -92,7 +96,7 @@ module Honeybadger
92
96
  )
93
97
  end
94
98
 
95
- def sanitize_string(data)
99
+ def valid_encoding(data)
96
100
  return data if valid_encoding?(data)
97
101
 
98
102
  if data.encoding == Encoding::UTF_8
@@ -101,6 +105,12 @@ module Honeybadger
101
105
  data.encode(Encoding::UTF_8, ENCODE_OPTS)
102
106
  end
103
107
  end
108
+
109
+ def sanitize_string(data)
110
+ data = valid_encoding(data)
111
+ return data unless data.respond_to?(:size) && data.size > MAX_STRING_SIZE
112
+ data[0...MAX_STRING_SIZE] + TRUNCATION_REPLACEMENT
113
+ end
104
114
  end
105
115
  end
106
116
  end
@@ -12,8 +12,8 @@ module Honeybadger
12
12
  # From https://github.com/bloopletech/webstats/blob/master/server/data_providers/mem_info.rb
13
13
  def memory
14
14
  out = {}
15
- if HAS_MEM
16
- out[:total], out[:free], out[:buffers], out[:cached] = IO.readlines("/proc/meminfo")[0..4].map { |l| l =~ /^.*?\: +(.*?) kB$/; ($1.to_i / 1024.0).to_f }
15
+ if HAS_MEM && (meminfo = run_meminfo)
16
+ out[:total], out[:free], out[:buffers], out[:cached] = meminfo[0..4].map { |l| l =~ /^.*?\: +(.*?) kB$/; ($1.to_i / 1024.0).to_f }
17
17
  out[:free_total] = out[:free] + out[:buffers] + out[:cached]
18
18
  end
19
19
  out
@@ -22,9 +22,28 @@ module Honeybadger
22
22
  # From https://github.com/bloopletech/webstats/blob/master/server/data_providers/cpu_info.rb
23
23
  def load
24
24
  out = {}
25
- out[:one], out[:five], out[:fifteen] = IO.read("/proc/loadavg").split(' ', 4).map(&:to_f) if HAS_LOAD
25
+ if HAS_LOAD && (loadavg = run_loadavg)
26
+ out[:one], out[:five], out[:fifteen] = loadavg.split(' ', 4).map(&:to_f)
27
+ end
26
28
  out
27
29
  end
30
+
31
+ private
32
+
33
+ def run_meminfo
34
+ run { IO.readlines("/proc/meminfo") }
35
+ end
36
+
37
+ def run_loadavg
38
+ run { IO.read("/proc/loadavg") }
39
+ end
40
+
41
+ def run
42
+ yield
43
+ rescue Errno::ENFILE
44
+ # Catch issues like 'Too many open files in system'
45
+ nil
46
+ end
28
47
  end
29
48
  end
30
49
  end
@@ -1,4 +1,4 @@
1
1
  module Honeybadger
2
2
  # Public: The current String Honeybadger version.
3
- VERSION = '2.0.12'.freeze
3
+ VERSION = '2.1.0.beta.1'.freeze
4
4
  end
@@ -35,7 +35,7 @@ namespace :honeybadger do
35
35
  end
36
36
 
37
37
  within release_path do
38
- execute executable, options
38
+ execute executable, options, raise_on_non_zero_exit: false
39
39
  end
40
40
 
41
41
  info 'Honeybadger notification complete.'
@@ -31,7 +31,7 @@ module Honeybadger
31
31
  logger.info 'DRY RUN: Notification not actually run.'
32
32
  else
33
33
  result = ''
34
- run(notify_options, :once => true, :pty => false) { |ch, stream, data| result << data }
34
+ run("#{ notify_options }; true", :once => true, :pty => false) { |ch, stream, data| result << data }
35
35
  end
36
36
  logger.info 'Honeybadger Notification Complete.'
37
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeybadger
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.12
4
+ version: 2.1.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Honeybadger Industries LLC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-27 00:00:00.000000000 Z
11
+ date: 2015-05-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Make managing application errors a more pleasant experience.
14
14
  email:
@@ -60,6 +60,7 @@ files:
60
60
  - lib/honeybadger/plugins/net_http.rb
61
61
  - lib/honeybadger/plugins/passenger.rb
62
62
  - lib/honeybadger/plugins/rails.rb
63
+ - lib/honeybadger/plugins/resque.rb
63
64
  - lib/honeybadger/plugins/sidekiq.rb
64
65
  - lib/honeybadger/plugins/thor.rb
65
66
  - lib/honeybadger/plugins/unicorn.rb
@@ -73,6 +74,7 @@ files:
73
74
  - lib/honeybadger/templates/feedback_form.erb
74
75
  - lib/honeybadger/trace.rb
75
76
  - lib/honeybadger/util/http.rb
77
+ - lib/honeybadger/util/request_payload.rb
76
78
  - lib/honeybadger/util/sanitizer.rb
77
79
  - lib/honeybadger/util/stats.rb
78
80
  - lib/honeybadger/version.rb
@@ -139,9 +141,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
139
141
  version: 1.9.3
140
142
  required_rubygems_version: !ruby/object:Gem::Requirement
141
143
  requirements:
142
- - - ">="
144
+ - - ">"
143
145
  - !ruby/object:Gem::Version
144
- version: '0'
146
+ version: 1.3.1
145
147
  requirements: []
146
148
  rubyforge_project:
147
149
  rubygems_version: 2.4.5