escalate 0.1.0.pre.2 → 0.2.0.pre.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a3e33eb654953f4c511b2207a89df47f6db4865c
4
- data.tar.gz: 4b245b1e402c24a933eae6ba6ac6eb9be362e5f1
2
+ SHA256:
3
+ metadata.gz: fc6bd15f68b37624979732a8c7b2c55d323c407c397c01ac59d8b8df54e90504
4
+ data.tar.gz: 144d6a67f62d9ca4ce7d740a26285dae283372450fd1149b74da59ab5411c982
5
5
  SHA512:
6
- metadata.gz: 28a1ecb9c22129c0b68c62ac6c5bd00eb5b41580bae1763dfdc9e0d9e732dfd22b7acc37ec84f353d4a3f7f35c18334ae92a78a5677c5e9e6453c4ccfb074767
7
- data.tar.gz: dc2271ab38903b2c8f874adc0b21f26c3851a759f5ed1db34482d447573d3d8f13d8b8d1b5565b9106b73bde766dee65260aeb6c645d402b9326371536d3dce0
6
+ metadata.gz: 1490795a292d531715525872a8bc06d1d27330222a24a436ad22ea62aa1d5fbc2e80b8a36b382cec86ef6281173bd5bddcbaffe9aa35c7f5bc641f6ac3611380
7
+ data.tar.gz: e2e7f3d6fd1be1e679bc6286c7fb892cef56fe64b57bbd55fedf649aa681c6e1d26f2f4f4aadbe8db3d0c327a378da65c46baee8fd20d137a6d6f1e2d40257d0
data/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [0.1.0] - Unreleased
7
+ ## [0.2.0] - Unreleased
8
+ ### Added
9
+ - Added support for `on_escalate(log_first: false)`. The `escalate` gem will log first before
10
+ escalating if either of these is true: there are no `on_escalate` blocks registered, or
11
+ there are some and at least one of them passed `log_first: false`.
8
12
 
13
+ ## [0.1.0] - 2021-02-03
14
+ ### Added
15
+ - Added `Escalate.mixin` interface for mixing in `Escalate` with your module for easy escalation of rescued exceptions
16
+ - Added `escalate` method for escalating rescued exceptions with default behavior of logging to `STDERR`
17
+ - Added `Escalate.on_escalate` for registering escalation callbacks like `Honeybadger` or `Sentry`
18
+
19
+ [0.2.0]: https://github.com/Invoca/escalate/compare/v0.1.0...v0.2.0
9
20
  [0.1.0]: https://github.com/Invoca/escalate/releases/tag/v0.1.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- escalate (0.1.0.pre.2)
4
+ escalate (0.2.0.pre.4)
5
5
  activesupport
6
6
 
7
7
  GEM
@@ -49,6 +49,7 @@ GEM
49
49
  thread_safe (~> 0.1)
50
50
 
51
51
  PLATFORMS
52
+ ruby
52
53
  x86_64-darwin-19
53
54
 
54
55
  DEPENDENCIES
data/README.md CHANGED
@@ -58,8 +58,44 @@ end
58
58
  When `SomeGem.escalate` above is triggered, it will use the logger returned by `SomeGem.logger` or
59
59
  default to a `STDERR` logger and do the following:
60
60
 
61
- 1. Log an error containing the exception and any additional information about the current environment that is specified
62
- 2. Trigger any `escalation_callbacks` configured on the `Escalate` gem
61
+ 1. [optional] Log an error containing the exception, location_message, and context hash
62
+ 2. Trigger any `on_escalate_callbacks` configured on the `Escalate` gem
63
+
64
+ Step (1) is optional. It will happen if either of these is true:
65
+ - by default if no `on_escalate_callbacks` have been registered; or
66
+ - if any of the `on_escalate_callbacks` was registered with `on_escalate(log_first: true)`.
67
+
68
+ ### Registering an Escalate Callback
69
+
70
+ If you are using an error reporting service, you can register an `on_escalate` callback to escalate exceptions.
71
+ You have the option to handle logging yourself, or to let `escalate` log first, before calling your callback.
72
+
73
+ #### Leave the Logging to the Escalate Gem
74
+ Here is an example that uses the default `log_first: true` so that logging is handled by the `Escalate` gem first:
75
+ ```
76
+ Escalate.on_escalate do |exception, location_message, **context|
77
+ # send exception, location_message, **context to the error reporting service here
78
+ end
79
+ ```
80
+
81
+ #### Callback Uniqueness
82
+ Each callback may be named with the `name:` keyword argument.
83
+ If a callback with the same name has been registered before, it will be overwritten with the new one.
84
+ ```
85
+ Escalate.on_escalate(name: 'abc gem') do |exception, location_message, **context|
86
+ # send exception, location_message, **context to the error reporting service here
87
+ end
88
+ ```
89
+ If not given, the `name:` defaults to the `.source_location` property of the passed-in block.
90
+
91
+ #### Handle the Logging in the `on_escalate` Callback
92
+ Here is an example that handles logging itself with `log_first: false`:
93
+ ```
94
+ Escalate.on_escalate(log_first: false) do |exception, location_message, **context|
95
+ # log here first
96
+ # send exception, location_message, **context to the error reporting service here
97
+ end
98
+ ```
63
99
  ## Development
64
100
 
65
101
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/lib/escalate.rb CHANGED
@@ -9,37 +9,46 @@ require_relative "escalate/mixin"
9
9
  module Escalate
10
10
  class Error < StandardError; end
11
11
 
12
+ LOG_FIRST_INSTANCE_VARIABLE = :@_escalate_log_first
13
+
14
+ @on_escalate_callbacks = {}
15
+
12
16
  class << self
17
+ attr_reader :on_escalate_callbacks
18
+
13
19
  # Logs and escalated an exception
14
20
  #
15
21
  # @param [Exception] exception
16
- # The exception that was raised and needs to be escalated
22
+ # The exception that was rescued and needs to be escalated
17
23
  #
18
- # @param [String] message
19
- # An additional message about what was happening at the time of the exception
24
+ # @param [String] location_message
25
+ # An additional message giving an indication of where in the code this exception was rescued
20
26
  #
21
27
  # @param [Logger] logger
22
28
  # The logger object to use when logging the exception
23
29
  #
24
30
  # @param [Hash] context
25
31
  # Any additional context to be tied to the escalation
26
- def escalate(exception, message, logger, **context)
32
+ def escalate(exception, location_message, logger, **context)
27
33
  ensure_failsafe("Exception rescued while escalating #{exception.inspect}") do
28
- error_message = <<~EOS
29
- [Escalate] #{message} (#{context.inspect})
34
+ if on_escalate_callbacks.none? || on_escalate_callbacks.values.any? { |block| block.instance_variable_get(LOG_FIRST_INSTANCE_VARIABLE) }
35
+ logger_allows_added_context?(logger) or context_string = " (#{context.inspect})"
36
+ error_message = <<~EOS
37
+ [Escalate] #{location_message}#{context_string}
30
38
  #{exception.class.name}: #{exception.message}
31
39
  #{exception.backtrace.join("\n")}
32
- EOS
40
+ EOS
33
41
 
34
- if logger_allows_added_context?(logger)
35
- logger.error(error_message, **context)
36
- else
37
- logger.error(error_message)
42
+ if context_string
43
+ logger.error(error_message)
44
+ else
45
+ logger.error(error_message, **context)
46
+ end
38
47
  end
39
48
 
40
- on_escalate_blocks.each do |block|
49
+ on_escalate_callbacks.values.each do |block|
41
50
  ensure_failsafe("Exception rescued while escalating #{exception.inspect} to #{block.inspect}") do
42
- block.call(exception, message, **context)
51
+ block.call(exception, location_message, **context)
43
52
  end
44
53
  end
45
54
  end
@@ -57,16 +66,43 @@ module Escalate
57
66
 
58
67
  Module.new do
59
68
  def self.included(base)
60
- base.extend Escalate::Mixin
69
+ base.extend self
61
70
  base.escalate_logger_block = Thread.current[:escalate_logger_block] || -> { base.try(:logger) }
62
71
  end
72
+
73
+ attr_accessor :escalate_logger_block
74
+
75
+ def escalate(exception, location_message, **context)
76
+ Escalate.escalate(exception, location_message, escalate_logger, **context)
77
+ end
78
+
79
+ private
80
+
81
+ def escalate_logger
82
+ escalate_logger_block&.call || default_escalate_logger
83
+ end
84
+
85
+ def default_escalate_logger
86
+ @default_escalate_logger ||= Logger.new(STDERR)
87
+ end
63
88
  end
64
89
  end
65
90
 
66
- # Registers an escalation callback to be executed when `escalate`
67
- # is invoked.
68
- def on_escalate(&block)
69
- on_escalate_blocks.add(block)
91
+ # Registers an escalation callback to be executed when `escalate` is invoked.
92
+ #
93
+ # @param [boolean] log_first: true
94
+ # whether escalate should log first before escalating, or leave the logging to the escalate block
95
+ # @param [string | Array] name:
96
+ # unique name for this callback block
97
+ # any previously-registered block with the same name will be discarded
98
+ # if not provided, name defaults to `block.source_location`
99
+ def on_escalate(log_first: true, name: nil, &block)
100
+ block.instance_variable_set(LOG_FIRST_INSTANCE_VARIABLE, log_first)
101
+ on_escalate_callbacks[name || block.source_location] = block
102
+ end
103
+
104
+ def clear_on_escalate_callbacks
105
+ on_escalate_callbacks.clear
70
106
  end
71
107
 
72
108
  private
@@ -81,9 +117,5 @@ module Escalate
81
117
  defined?(ContextualLogger::LoggerMixin) &&
82
118
  logger.is_a?(ContextualLogger::LoggerMixin)
83
119
  end
84
-
85
- def on_escalate_blocks
86
- @on_escalate_blocks ||= Set.new
87
- end
88
120
  end
89
121
  end
@@ -4,24 +4,8 @@ module Escalate
4
4
  module Mixin
5
5
  class << self
6
6
  def included(base)
7
- raise 'instead of `include Escalator::Mixin`, you should `include Escalator.mixin`'
7
+ raise 'instead of `include Escalate::Mixin`, you should `include Escalate.mixin`'
8
8
  end
9
9
  end
10
-
11
- attr_accessor :escalate_logger_block
12
-
13
- def escalate(exception, message, **context)
14
- Escalate.escalate(exception, message, escalate_logger, **context)
15
- end
16
-
17
- private
18
-
19
- def escalate_logger
20
- escalate_logger_block.try(:call) || default_escalate_logger
21
- end
22
-
23
- def default_escalate_logger
24
- @default_escalate_logger ||= Logger.new(STDERR)
25
- end
26
10
  end
27
11
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Escalate
4
- VERSION = "0.1.0.pre.2"
4
+ VERSION = "0.2.0.pre.4"
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: escalate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.2
4
+ version: 0.2.0.pre.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca Development
8
8
  - Octothorp
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-02-02 00:00:00.000000000 Z
12
+ date: 2021-03-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -56,7 +56,7 @@ metadata:
56
56
  allowed_push_host: https://rubygems.org
57
57
  homepage_uri: https://github.com/invoca/escalate
58
58
  changelog_uri: https://github.com/invoca/escalate/blob/main/CHANGELOG.md
59
- post_install_message:
59
+ post_install_message:
60
60
  rdoc_options: []
61
61
  require_paths:
62
62
  - lib
@@ -71,9 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  - !ruby/object:Gem::Version
72
72
  version: 1.3.1
73
73
  requirements: []
74
- rubyforge_project:
75
- rubygems_version: 2.6.13
76
- signing_key:
74
+ rubygems_version: 3.1.2
75
+ signing_key:
77
76
  specification_version: 4
78
77
  summary: A simple and lightweight gem to escalate rescued exceptions.
79
78
  test_files: []