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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bb743da8ea57e11a7bfa80d653548239e0b760ab
4
- data.tar.gz: 36555a0ba6f8bca3f821c5b0044739e26762cc23
2
+ SHA256:
3
+ metadata.gz: 67b615521fd3e15a59bb8401486496175afa19be36a98c415d9eccf52dd0815f
4
+ data.tar.gz: 951d5afc0052cde73fca383e23dc38aa63e759fce7f4863b2093e9bf9b2463b4
5
5
  SHA512:
6
- metadata.gz: 7c735aa3214359068d14e0fd981c64c62e14896d73965d467d5b28ebaa3d2bf300ae9037164d3a4a7e5a6b4a77439a8a5137dd5d3b7b51eda27cef0ec7a57a60
7
- data.tar.gz: a3899dc985f47f6e87d609b5fdf85443b9278ca100b40e5e41e4be641c8aa6116850dc80a4426f779c34e741b5b0893c9032e3c2b59974a9b802da0bcc8629bd
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.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 CHANGED
@@ -5,6 +5,8 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in escalate.gemspec
6
6
  gemspec
7
7
 
8
+ gem "contextual_logger"
9
+
8
10
  gem "pry"
9
11
  gem "pry-byebug"
10
12
 
data/Gemfile.lock CHANGED
@@ -1,9 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- escalate (0.1.0.pre.1)
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 help with escalating errors
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#ex_escalate` method within your gem to be used instead
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 any additional information about the current environment that is specified
58
- 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
+ #### 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 = "Simple gem for abstracting log escalations"
12
- spec.description = "Simple gem for abstracting log escalations"
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 raised and needs to be escalated
22
+ # The exception that was rescued and needs to be escalated
18
23
  #
19
- # @param [String] message
20
- # 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
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, message, logger, **context)
28
- error_message = <<~EOS
29
- [Escalate] #{message} (#{context.inspect})
30
- #{exception.class.name}: #{exception.message}
31
- #{exception.backtrace.join("\n")}
32
- EOS
33
-
34
- if logger.is_a?(ContextualLogger::LoggerMixin)
35
- logger.error(error_message, **context)
36
- else
37
- logger.error(error_message)
38
- end
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
- on_escalate_blocks.each do |block|
41
- block.call(exception, message, **context)
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 ex_escalate method to be used for escalating and logging
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 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 `ex_escalate`
91
+ # Registers an escalation callback to be executed when `escalate`
67
92
  # is invoked.
68
- def on_escalate(&block)
69
- on_escalate_blocks.add(block)
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 on_escalate_blocks
75
- @on_escalate_blocks ||= Set.new
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
@@ -4,24 +4,8 @@ module Escalate
4
4
  module Mixin
5
5
  class << self
6
6
  def included(base)
7
- raise 'instead of `include ExEscalator::Mixin`, you should `include ExEscalator.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 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Escalate
4
- VERSION = "0.1.0.pre.1"
4
+ VERSION = "0.2.0.pre.3"
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.1
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-02-01 00:00:00.000000000 Z
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
- - !ruby/object:Gem::Dependency
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
- rubyforge_project:
89
- rubygems_version: 2.6.13
90
- signing_key:
74
+ rubygems_version: 3.1.2
75
+ signing_key:
91
76
  specification_version: 4
92
- summary: Simple gem for abstracting log escalations
77
+ summary: A simple and lightweight gem to escalate rescued exceptions.
93
78
  test_files: []