escalate 0.1.0.pre.1 → 0.2.0.pre.3
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 +5 -5
- data/CHANGELOG.md +12 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +3 -2
- data/README.md +34 -4
- data/escalate.gemspec +2 -3
- data/lib/escalate.rb +68 -28
- data/lib/escalate/mixin.rb +1 -17
- data/lib/escalate/version.rb +1 -1
- metadata +8 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 67b615521fd3e15a59bb8401486496175afa19be36a98c415d9eccf52dd0815f
|
4
|
+
data.tar.gz: 951d5afc0052cde73fca383e23dc38aa63e759fce7f4863b2093e9bf9b2463b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7979594ec79d527e123efb08114d602ab11446d8e822a9a716b582150d7e0f4b97840443974270177d861d874fbf4544f7e14eb8bd5e98e66acc86d49b51e19a
|
7
|
+
data.tar.gz: 2ab19d1367350559290fb9603e7af73934fcf1085121bf5a1cebe03059d450d19e53f76dc9947d92fac8a06f2a08fc0bb6ed12d0135a1e09617c87c6835dc158
|
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.
|
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
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
escalate (0.
|
4
|
+
escalate (0.2.0.pre.3)
|
5
5
|
activesupport
|
6
|
-
contextual_logger
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: https://rubygems.org/
|
@@ -50,9 +49,11 @@ GEM
|
|
50
49
|
thread_safe (~> 0.1)
|
51
50
|
|
52
51
|
PLATFORMS
|
52
|
+
ruby
|
53
53
|
x86_64-darwin-19
|
54
54
|
|
55
55
|
DEPENDENCIES
|
56
|
+
contextual_logger
|
56
57
|
escalate!
|
57
58
|
pry
|
58
59
|
pry-byebug
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# Escalate
|
2
2
|
|
3
|
-
A simple and lightweight gem to
|
3
|
+
A simple and lightweight gem to escalate rescued exceptions. This implementation
|
4
|
+
is an abstract interface that can be used on it's own, or attached to more concrete
|
5
|
+
implementations like Honeybadger, Airbrake, or Sentry in order to not just log
|
6
|
+
exceptions in an easy to parse way, but also escalate the appropriate information
|
7
|
+
to third party systems.
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
@@ -30,7 +34,7 @@ module SomeGem
|
|
30
34
|
end
|
31
35
|
```
|
32
36
|
|
33
|
-
This will expose the `Escalate#
|
37
|
+
This will expose the `Escalate#escalate` method within your gem to be used instead
|
34
38
|
of using `logger.error`.
|
35
39
|
|
36
40
|
```ruby
|
@@ -54,8 +58,34 @@ end
|
|
54
58
|
When `SomeGem.escalate` above is triggered, it will use the logger returned by `SomeGem.logger` or
|
55
59
|
default to a `STDERR` logger and do the following:
|
56
60
|
|
57
|
-
1. Log an error containing the exception and
|
58
|
-
2. Trigger any `
|
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
|
+
#### Handle the Logging in the `on_escalate` Callback
|
82
|
+
Here is an example that handles logging itself with `log_first: false`:
|
83
|
+
```
|
84
|
+
Escalate.on_escalate(log_first: false) do |exception, location_message, **context|
|
85
|
+
# log here first
|
86
|
+
# send exception, location_message, **context to the error reporting service here
|
87
|
+
end
|
88
|
+
```
|
59
89
|
## Development
|
60
90
|
|
61
91
|
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/escalate.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Invoca Development", "Octothorp"]
|
9
9
|
spec.email = ["development@invoca.com", "octothorp@invoca.com"]
|
10
10
|
|
11
|
-
spec.summary = "
|
12
|
-
spec.description = "
|
11
|
+
spec.summary = "A simple and lightweight gem to escalate rescued exceptions."
|
12
|
+
spec.description = "A simple and lightweight gem to escalate rescued exceptions."
|
13
13
|
spec.homepage = "https://github.com/invoca/escalate"
|
14
14
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
15
15
|
|
@@ -28,5 +28,4 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
30
|
spec.add_dependency "activesupport"
|
31
|
-
spec.add_dependency "contextual_logger"
|
32
31
|
end
|
data/lib/escalate.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "active_support"
|
4
4
|
require "active_support/core_ext"
|
5
|
-
require "contextual_logger"
|
6
5
|
|
7
6
|
require_relative "escalate/version"
|
8
7
|
require_relative "escalate/mixin"
|
@@ -10,43 +9,53 @@ require_relative "escalate/mixin"
|
|
10
9
|
module Escalate
|
11
10
|
class Error < StandardError; end
|
12
11
|
|
12
|
+
LOG_FIRST_INSTANCE_VARIABLE = :@_escalate_log_first
|
13
|
+
|
14
|
+
@on_escalate_callbacks = Set.new
|
15
|
+
|
13
16
|
class << self
|
17
|
+
attr_reader :on_escalate_callbacks
|
18
|
+
|
14
19
|
# Logs and escalated an exception
|
15
20
|
#
|
16
21
|
# @param [Exception] exception
|
17
|
-
# The exception that was
|
22
|
+
# The exception that was rescued and needs to be escalated
|
18
23
|
#
|
19
|
-
# @param [String]
|
20
|
-
# An additional message
|
24
|
+
# @param [String] location_message
|
25
|
+
# An additional message giving an indication of where in the code this exception was rescued
|
21
26
|
#
|
22
27
|
# @param [Logger] logger
|
23
28
|
# The logger object to use when logging the exception
|
24
29
|
#
|
25
30
|
# @param [Hash] context
|
26
31
|
# Any additional context to be tied to the escalation
|
27
|
-
def escalate(exception,
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
def escalate(exception, location_message, logger, **context)
|
33
|
+
ensure_failsafe("Exception rescued while escalating #{exception.inspect}") do
|
34
|
+
if on_escalate_callbacks.none? || on_escalate_callbacks.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}
|
38
|
+
#{exception.class.name}: #{exception.message}
|
39
|
+
#{exception.backtrace.join("\n")}
|
40
|
+
EOS
|
41
|
+
|
42
|
+
if context_string
|
43
|
+
logger.error(error_message)
|
44
|
+
else
|
45
|
+
logger.error(error_message, **context)
|
46
|
+
end
|
47
|
+
end
|
39
48
|
|
40
|
-
|
41
|
-
|
49
|
+
on_escalate_callbacks.each do |block|
|
50
|
+
ensure_failsafe("Exception rescued while escalating #{exception.inspect} to #{block.inspect}") do
|
51
|
+
block.call(exception, location_message, **context)
|
52
|
+
end
|
53
|
+
end
|
42
54
|
end
|
43
|
-
rescue Exception => ex
|
44
|
-
STDERR.puts("[ExEscalator] Exception rescued while escalating #{exception.inspect}:" \
|
45
|
-
"#{ex.class.name}: #{ex.message}")
|
46
55
|
end
|
47
56
|
|
48
57
|
# Returns a module to be mixed into a class or module exposing
|
49
|
-
# the
|
58
|
+
# the escalate method to be used for escalating and logging
|
50
59
|
# exceptions.
|
51
60
|
#
|
52
61
|
# @param [Proc] logger_block
|
@@ -57,22 +66,53 @@ module Escalate
|
|
57
66
|
|
58
67
|
Module.new do
|
59
68
|
def self.included(base)
|
60
|
-
base.extend
|
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 `
|
91
|
+
# Registers an escalation callback to be executed when `escalate`
|
67
92
|
# is invoked.
|
68
|
-
|
69
|
-
|
93
|
+
#
|
94
|
+
# @param [boolean] log_first: true
|
95
|
+
# whether escalate should log first before escalating, or leave the logging to the escalate block
|
96
|
+
def on_escalate(log_first: true, &block)
|
97
|
+
block.instance_variable_set(LOG_FIRST_INSTANCE_VARIABLE, log_first)
|
98
|
+
on_escalate_callbacks.add(block)
|
99
|
+
end
|
100
|
+
|
101
|
+
def clear_on_escalate_callbacks
|
102
|
+
on_escalate_callbacks.clear
|
70
103
|
end
|
71
104
|
|
72
105
|
private
|
73
106
|
|
74
|
-
def
|
75
|
-
|
107
|
+
def ensure_failsafe(message)
|
108
|
+
yield
|
109
|
+
rescue Exception => ex
|
110
|
+
STDERR.puts("[Escalator] #{message}: #{ex.class.name}: #{ex.message}")
|
111
|
+
end
|
112
|
+
|
113
|
+
def logger_allows_added_context?(logger)
|
114
|
+
defined?(ContextualLogger::LoggerMixin) &&
|
115
|
+
logger.is_a?(ContextualLogger::LoggerMixin)
|
76
116
|
end
|
77
117
|
end
|
78
118
|
end
|
data/lib/escalate/mixin.rb
CHANGED
@@ -4,24 +4,8 @@ module Escalate
|
|
4
4
|
module Mixin
|
5
5
|
class << self
|
6
6
|
def included(base)
|
7
|
-
raise 'instead of `include
|
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 ex_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
|
data/lib/escalate/version.rb
CHANGED
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.
|
4
|
+
version: 0.2.0.pre.3
|
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-
|
12
|
+
date: 2021-03-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -25,21 +25,7 @@ dependencies:
|
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
|
-
|
29
|
-
name: contextual_logger
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - ">="
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '0'
|
35
|
-
type: :runtime
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '0'
|
42
|
-
description: Simple gem for abstracting log escalations
|
28
|
+
description: A simple and lightweight gem to escalate rescued exceptions.
|
43
29
|
email:
|
44
30
|
- development@invoca.com
|
45
31
|
- octothorp@invoca.com
|
@@ -70,7 +56,7 @@ metadata:
|
|
70
56
|
allowed_push_host: https://rubygems.org
|
71
57
|
homepage_uri: https://github.com/invoca/escalate
|
72
58
|
changelog_uri: https://github.com/invoca/escalate/blob/main/CHANGELOG.md
|
73
|
-
post_install_message:
|
59
|
+
post_install_message:
|
74
60
|
rdoc_options: []
|
75
61
|
require_paths:
|
76
62
|
- lib
|
@@ -85,9 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
71
|
- !ruby/object:Gem::Version
|
86
72
|
version: 1.3.1
|
87
73
|
requirements: []
|
88
|
-
|
89
|
-
|
90
|
-
signing_key:
|
74
|
+
rubygems_version: 3.1.2
|
75
|
+
signing_key:
|
91
76
|
specification_version: 4
|
92
|
-
summary:
|
77
|
+
summary: A simple and lightweight gem to escalate rescued exceptions.
|
93
78
|
test_files: []
|