honeybadger 2.0.12 → 2.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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