axn 0.1.0.pre.alpha.2.5.2 → 0.1.0.pre.alpha.2.5.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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +4 -0
- data/docs/reference/configuration.md +16 -0
- data/docs/usage/writing.md +1 -1
- data/lib/action/core/configuration.rb +14 -5
- data/lib/action/core/context_facade.rb +1 -2
- data/lib/action/core/event_handlers.rb +2 -4
- data/lib/action/core/{swallow_exceptions.rb → handle_exceptions.rb} +2 -2
- data/lib/action/core/logging.rb +5 -5
- data/lib/action/core/top_level_around_hook.rb +25 -7
- data/lib/action/core/validation/validators/model_validator.rb +1 -2
- data/lib/action/core/validation/validators/validate_validator.rb +1 -1
- data/lib/axn/util.rb +24 -0
- data/lib/axn/version.rb +1 -1
- data/lib/axn.rb +3 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d62aa4b98c8f159761234817e6b2ded26e0fcafa46d07685049d827281e92235
|
4
|
+
data.tar.gz: d3ffb46353e17db427393049767a6a03fbf3d5b30e94e4011a47397644364c32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54a4ea06f021850cc1d4e1e9bf18a6ec20f495871f23efab20380cd2a8135c52df46099f03281944c4dbe4419c836a72309cfd719e769ae3fd7e48a2ad7683db
|
7
|
+
data.tar.gz: 474eea3af1b53ad4ae85096a2e39d4b141b01c8c4f239f710cd13de933046d92b7efc67333902c78ed29c882bda5ada0a44e9e2efeab05721681f5ded1633b41
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
## Unreleased
|
4
4
|
* N/A
|
5
5
|
|
6
|
+
## 0.1.0-alpha.2.5.3
|
7
|
+
* More aggressive logging of swallowed exceptions when not in production mode
|
8
|
+
* Make automatic pre/post logging more digestible
|
9
|
+
|
6
10
|
## 0.1.0-alpha.2.5.2
|
7
11
|
* [BREAKING] Removing `EnqueueAllInBackground` + `EnqueueAllWorker` - better + simply solved at application level
|
8
12
|
* [TEST] Expose spec helpers to consumers (add `require "axn/testing/spec_helpers"` to your `spec_helper.rb`)
|
@@ -36,6 +36,22 @@ For example, if you're using Honeybadger this could look something like:
|
|
36
36
|
end
|
37
37
|
```
|
38
38
|
|
39
|
+
**Note:** The `action:` and `context:` keyword arguments are *optional*—your proc can accept any combination of `e`, `action:`, and `context:`. Only the keyword arguments you explicitly declare will be passed to your handler. All of the following are valid:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# Only exception object
|
43
|
+
c.on_exception = proc { |e| ... }
|
44
|
+
|
45
|
+
# Exception and action
|
46
|
+
c.on_exception = proc { |e, action:| ... }
|
47
|
+
|
48
|
+
# Exception and context
|
49
|
+
c.on_exception = proc { |e, context:| ... }
|
50
|
+
|
51
|
+
# Exception, action, and context
|
52
|
+
c.on_exception = proc { |e, action:, context:| ... }
|
53
|
+
```
|
54
|
+
|
39
55
|
A couple notes:
|
40
56
|
|
41
57
|
* `context` will contain the arguments passed to the `action`, _but_ any marked as sensitive (e.g. `expects :foo, sensitive: true`) will be filtered out in the logs.
|
data/docs/usage/writing.md
CHANGED
@@ -155,4 +155,4 @@ after hook
|
|
155
155
|
A number of custom callback are available for you as well, if you want to take specific actions when a given Axn succeeds or fails. See the [Class Interface docs](/reference/class#callbacks) for details.
|
156
156
|
|
157
157
|
## Strategies
|
158
|
-
A number of [Strategies](/strategies), which are <abbr title="Don't Repeat Yourself">DRY</abbr>ed bits of commonly-used configuration, are available for your use as well.
|
158
|
+
A number of [Strategies](/strategies/index), which are <abbr title="Don't Repeat Yourself">DRY</abbr>ed bits of commonly-used configuration, are available for your use as well.
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module Action
|
4
4
|
class Configuration
|
5
|
-
include Action::Logging
|
6
5
|
attr_accessor :top_level_around_hook
|
7
6
|
attr_writer :logger, :env, :on_exception, :additional_includes, :default_log_level, :default_autolog_level
|
8
7
|
|
@@ -12,11 +11,21 @@ module Action
|
|
12
11
|
def additional_includes = @additional_includes ||= []
|
13
12
|
|
14
13
|
def on_exception(e, action:, context: {})
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
msg = "Handled exception (#{e.class.name}): #{e.message}"
|
15
|
+
msg = ("#" * 10) + " #{msg} " + ("#" * 10) unless Action.config.env.production?
|
16
|
+
action.log(msg)
|
17
|
+
|
18
|
+
return unless @on_exception
|
19
|
+
|
20
|
+
# Only pass the kwargs that the given block expects
|
21
|
+
kwargs = @on_exception.parameters.select { |type, _name| %i[key keyreq].include?(type) }.map(&:last)
|
22
|
+
kwarg_hash = {}
|
23
|
+
kwarg_hash[:action] = action if kwargs.include?(:action)
|
24
|
+
kwarg_hash[:context] = context if kwargs.include?(:context)
|
25
|
+
if kwarg_hash.any?
|
26
|
+
@on_exception.call(e, **kwarg_hash)
|
18
27
|
else
|
19
|
-
|
28
|
+
@on_exception.call(e)
|
20
29
|
end
|
21
30
|
end
|
22
31
|
|
@@ -75,8 +75,7 @@ module Action
|
|
75
75
|
action.instance_exec(&msg)
|
76
76
|
end
|
77
77
|
rescue StandardError => e
|
78
|
-
|
79
|
-
nil
|
78
|
+
Axn::Util.piping_error("determining message callable", action:, exception: e)
|
80
79
|
end
|
81
80
|
end
|
82
81
|
|
@@ -27,8 +27,7 @@ module Action
|
|
27
27
|
action.instance_exec(exception, &@handler)
|
28
28
|
true
|
29
29
|
rescue StandardError => e
|
30
|
-
|
31
|
-
nil
|
30
|
+
Axn::Util.piping_error("executing handler", action:, exception: e)
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
@@ -54,8 +53,7 @@ module Action
|
|
54
53
|
false
|
55
54
|
end
|
56
55
|
rescue StandardError => e
|
57
|
-
|
58
|
-
false
|
56
|
+
Axn::Util.piping_error("determining if handler applies to exception", action:, exception: e)
|
59
57
|
end
|
60
58
|
|
61
59
|
private attr_reader :matcher
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative "event_handlers"
|
4
4
|
|
5
5
|
module Action
|
6
|
-
module
|
6
|
+
module HandleExceptions
|
7
7
|
def self.included(base)
|
8
8
|
base.class_eval do
|
9
9
|
class_attribute :_success_msg, :_error_msg
|
@@ -56,7 +56,7 @@ module Action
|
|
56
56
|
rescue StandardError => e
|
57
57
|
# No action needed -- downstream #on_exception implementation should ideally log any internal failures, but
|
58
58
|
# we don't want exception *handling* failures to cascade and overwrite the original exception.
|
59
|
-
|
59
|
+
Axn::Util.piping_error("executing on_exception hooks", action: self, exception: e)
|
60
60
|
end
|
61
61
|
|
62
62
|
class << base
|
data/lib/action/core/logging.rb
CHANGED
@@ -16,20 +16,20 @@ module Action
|
|
16
16
|
module ClassMethods
|
17
17
|
def default_log_level = Action.config.default_log_level
|
18
18
|
|
19
|
-
def log(message, level: default_log_level)
|
19
|
+
def log(message, level: default_log_level, before: nil, after: nil)
|
20
20
|
msg = [_log_prefix, message].compact_blank.join(" ")
|
21
|
+
msg = [before, msg, after].compact_blank.join if before || after
|
21
22
|
|
22
23
|
Action.config.logger.send(level, msg)
|
23
24
|
end
|
24
25
|
|
25
26
|
LEVELS.each do |level|
|
26
|
-
define_method(level) do |message|
|
27
|
-
log(message, level:)
|
27
|
+
define_method(level) do |message, before: nil, after: nil|
|
28
|
+
log(message, level:, before:, after:)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
-
def _log_prefix = name == "Action::Configuration" ? nil : "[#{name || "Anonymous Class"}]"
|
32
|
+
def _log_prefix = "[#{name.presence || "Anonymous Class"}]"
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -24,8 +24,9 @@ module Action
|
|
24
24
|
self.class.default_autolog_level,
|
25
25
|
[
|
26
26
|
"About to execute",
|
27
|
-
|
27
|
+
_log_context(:inbound),
|
28
28
|
].compact.join(" with: "),
|
29
|
+
before: Action.config.env.production? ? nil : "\n------\n",
|
29
30
|
)
|
30
31
|
end
|
31
32
|
|
@@ -36,21 +37,38 @@ module Action
|
|
36
37
|
self.class.default_autolog_level,
|
37
38
|
[
|
38
39
|
"Execution completed (with outcome: #{outcome}) in #{elapsed_mils} milliseconds",
|
39
|
-
|
40
|
+
_log_context(:outbound),
|
40
41
|
].compact.join(". Set: "),
|
42
|
+
after: Action.config.env.production? ? nil : "\n------\n",
|
41
43
|
)
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
45
|
-
|
46
|
+
def _log_context(direction)
|
47
|
+
data = context_for_logging(direction)
|
48
|
+
return unless data.present?
|
46
49
|
|
47
|
-
max_length =
|
48
|
-
suffix = "
|
50
|
+
max_length = 150
|
51
|
+
suffix = "…<truncated>…"
|
49
52
|
|
50
|
-
data.
|
53
|
+
_log_object(data).tap do |str|
|
51
54
|
return str[0, max_length - suffix.length] + suffix if str.length > max_length
|
52
55
|
end
|
53
56
|
end
|
57
|
+
|
58
|
+
def _log_object(data)
|
59
|
+
case data
|
60
|
+
when Hash
|
61
|
+
# NOTE: slightly more manual in order to avoid quotes around ActiveRecord objects' <Class#id> formatting
|
62
|
+
"{#{data.map { |k, v| "#{k}: #{_log_object(v)}" }.join(", ")}}"
|
63
|
+
when Array
|
64
|
+
data.map { |v| _log_object(v) }
|
65
|
+
else
|
66
|
+
return data.to_unsafe_h if defined?(ActionController::Parameters) && data.is_a?(ActionController::Parameters)
|
67
|
+
return "<#{data.class.name}##{data.to_param.presence || "unpersisted"}>" if defined?(ActiveRecord::Base) && data.is_a?(ActiveRecord::Base)
|
68
|
+
|
69
|
+
data.inspect
|
70
|
+
end
|
71
|
+
end
|
54
72
|
end
|
55
73
|
|
56
74
|
module InstanceMethods
|
@@ -26,8 +26,7 @@ module Action
|
|
26
26
|
msg = id.blank? ? "not found (given a blank ID)" : "not found for class #{klass.name} and ID #{id}"
|
27
27
|
record.errors.add(attribute, msg)
|
28
28
|
rescue StandardError => e
|
29
|
-
|
30
|
-
|
29
|
+
Axn::Util.piping_error("applying model validation on field '#{attribute}'", exception: e)
|
31
30
|
record.errors.add(attribute, "error raised while trying to find a valid #{klass.name}")
|
32
31
|
end
|
33
32
|
end
|
@@ -9,7 +9,7 @@ module Action
|
|
9
9
|
msg = begin
|
10
10
|
options[:with].call(value)
|
11
11
|
rescue StandardError => e
|
12
|
-
|
12
|
+
Axn::Util.piping_error("applying custom validation on field '#{attribute}'", exception: e)
|
13
13
|
|
14
14
|
"failed validation: #{e.message}"
|
15
15
|
end
|
data/lib/axn/util.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Axn
|
4
|
+
module Util
|
5
|
+
def self.piping_error(desc, exception:, action: nil)
|
6
|
+
# Extract just filename/line number from backtrace
|
7
|
+
src = exception.backtrace.first.split.first.split("/").last.split(":")[0, 2].join(":")
|
8
|
+
|
9
|
+
message = if Action.config.env.production?
|
10
|
+
"Ignoring exception raised while #{desc}: #{exception.class.name} - #{exception.message} (from #{src})"
|
11
|
+
else
|
12
|
+
msg = "!! IGNORING EXCEPTION RAISED WHILE #{desc.upcase} !!\n\n" \
|
13
|
+
"\t* Exception: #{exception.class.name}\n" \
|
14
|
+
"\t* Message: #{exception.message}\n" \
|
15
|
+
"\t* From: #{src}"
|
16
|
+
"#{"⌵" * 30}\n\n#{msg}\n\n#{"^" * 30}"
|
17
|
+
end
|
18
|
+
|
19
|
+
(action || Action.config.logger).send(:warn, message)
|
20
|
+
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/axn/version.rb
CHANGED
data/lib/axn.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Axn; end
|
4
4
|
require_relative "axn/version"
|
5
|
+
require_relative "axn/util"
|
5
6
|
|
6
7
|
require "interactor"
|
7
8
|
require "active_support"
|
@@ -16,7 +17,7 @@ require_relative "action/core/configuration"
|
|
16
17
|
require_relative "action/core/top_level_around_hook"
|
17
18
|
require_relative "action/core/contract"
|
18
19
|
require_relative "action/core/contract_for_subfields"
|
19
|
-
require_relative "action/core/
|
20
|
+
require_relative "action/core/handle_exceptions"
|
20
21
|
require_relative "action/core/hoist_errors"
|
21
22
|
require_relative "action/core/use_strategy"
|
22
23
|
|
@@ -44,7 +45,7 @@ module Action
|
|
44
45
|
# can include those hook executions in any traces set from this hook.
|
45
46
|
include TopLevelAroundHook
|
46
47
|
|
47
|
-
include
|
48
|
+
include HandleExceptions
|
48
49
|
include Contract
|
49
50
|
include ContractForSubfields
|
50
51
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: axn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.pre.alpha.2.5.
|
4
|
+
version: 0.1.0.pre.alpha.2.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kali Donovan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -96,9 +96,9 @@ files:
|
|
96
96
|
- lib/action/core/contract_for_subfields.rb
|
97
97
|
- lib/action/core/event_handlers.rb
|
98
98
|
- lib/action/core/exceptions.rb
|
99
|
+
- lib/action/core/handle_exceptions.rb
|
99
100
|
- lib/action/core/hoist_errors.rb
|
100
101
|
- lib/action/core/logging.rb
|
101
|
-
- lib/action/core/swallow_exceptions.rb
|
102
102
|
- lib/action/core/top_level_around_hook.rb
|
103
103
|
- lib/action/core/use_strategy.rb
|
104
104
|
- lib/action/core/validation/fields.rb
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/axn.rb
|
114
114
|
- lib/axn/factory.rb
|
115
115
|
- lib/axn/testing/spec_helpers.rb
|
116
|
+
- lib/axn/util.rb
|
116
117
|
- lib/axn/version.rb
|
117
118
|
- package.json
|
118
119
|
- yarn.lock
|