escalate 0.1.0.pre.1 → 0.2.0.pre.3
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|