action_reporter 1.5.2 → 2.0.0
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/CHANGELOG.md +84 -42
- data/README.md +110 -35
- data/action_reporter.gemspec +10 -4
- data/lib/action_reporter/base.rb +13 -5
- data/lib/action_reporter/current.rb +59 -0
- data/lib/action_reporter/error.rb +6 -0
- data/lib/action_reporter/plugin_discovery.rb +143 -0
- data/lib/action_reporter/sentry_reporter.rb +10 -0
- data/lib/action_reporter/version.rb +3 -0
- data/lib/action_reporter.rb +179 -25
- metadata +66 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 966d8f43c69d090e7c05c60571b9514f70a78dc1f16406c50610c9003e02a9e5
|
|
4
|
+
data.tar.gz: b04f3e1ecc0a98d68b58169c25df6ad0a3ebbd23bc486b090cf8706b4e6b5b35
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ccd9608cf52f7eb887102e12011b3f889cb7d06c171ddc46aa06c0a7ac69d9330dd7a377b12da3c3b17e71254bd940fe1f69f9f590401fcc3e02c6a29129f9f
|
|
7
|
+
data.tar.gz: 4f389d9305525cd87a2eb9b0b8f09765867e2195060c88b6fd942199bfcd5f4e118f9b896011b027f62cf55ed6a7965641455226ad479c0dbf32d48c457771b2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,77 +1,119 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CHANGELOG
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 2.0.0 (2025-11-05)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- Add performance benchmarks to measure CPU, memory, and response-time impact
|
|
6
|
+
- Benchmarks wall-time overhead for context + notify + reset operations
|
|
7
|
+
- Tests with 0 to 10 reporters to show scaling behavior
|
|
8
|
+
- Shows overhead per reporter (~1.5ms per reporter on average)
|
|
9
|
+
- Helps estimate response-time impact based on number of enabled reporters
|
|
10
|
+
- BREAKING: Complete rewrite of plugin discovery system
|
|
11
|
+
- New lazy-loaded plugin discovery that auto-discovers reporters from filesystem
|
|
12
|
+
- Introduced `ActionReporter::PluginDiscovery` module for managing reporter discovery
|
|
13
|
+
- `AVAILABLE_REPORTERS` constant maintained for backward compatibility but `available_reporters` method is now preferred
|
|
14
|
+
- Plugin discovery does not block application boot - all discovery is lazy-loaded
|
|
15
|
+
- BREAKING: Thread safety changes - context attributes are now thread-safe
|
|
16
|
+
- Replace module-level instance variables with thread-local storage using `ActionReporter::Current`
|
|
17
|
+
- Context attributes (`current_user`, `current_request_uuid`, `current_remote_addr`) are now thread-safe
|
|
18
|
+
- Prevents data leakage and race conditions in multi-threaded environments
|
|
19
|
+
- Maintains API compatibility but behavior is now thread-safe
|
|
20
|
+
- Add custom reporter registration support
|
|
21
|
+
- New `ActionReporter.register_reporter(name, class_name:, require_path:)` method
|
|
22
|
+
- Allows third-party gems and applications to register custom reporters (e.g., Datadog, New Relic)
|
|
23
|
+
- Registered reporters automatically appear in `available_reporters`
|
|
24
|
+
- Supports both file-based and inline-defined reporters
|
|
25
|
+
- Add `ActionReporter.available_reporters` method to get all available reporters (discovered + registered)
|
|
26
|
+
- Add thread-safe plugin discovery with Mutex-based caching
|
|
27
|
+
- Add comprehensive error handling to all reporter methods
|
|
28
|
+
- Reporter failures no longer break the entire reporting chain
|
|
29
|
+
- Errors are logged but don't prevent other reporters from executing
|
|
30
|
+
- Added `ActionReporter.logger` for configurable error logging (defaults to `Rails.logger` if available)
|
|
31
|
+
- Added `ActionReporter.error_handler` for custom error handling callbacks
|
|
32
|
+
- Fix `reset_context` method to properly reset instance attributes (`@current_user`, `@current_request_uuid`, `@current_remote_addr`)
|
|
33
|
+
- Improve error handling in plugin discovery - gracefully handles missing files, invalid classes, and load errors
|
|
34
|
+
- Add `ActionReporter::PluginDiscovery.reset!` method for testing purposes
|
|
35
|
+
- Add thread safety tests
|
|
36
|
+
- Add error handling tests with fault isolation verification
|
|
37
|
+
- Add comprehensive plugin discovery tests
|
|
38
|
+
- Add custom reporter registration tests
|
|
39
|
+
- Achieve 100% test coverage (297/297 lines)
|
|
6
40
|
|
|
7
|
-
|
|
41
|
+
## 1.5.2 (2024-12-13)
|
|
8
42
|
|
|
9
|
-
|
|
43
|
+
- Add Audited context support
|
|
10
44
|
|
|
11
|
-
|
|
12
|
-
* Add `current_request_uuid` and `current_remote_addr` getters and setters
|
|
13
|
-
* Memoize `current_user`, `current_request_uuid`, and `current_remote_addr`
|
|
45
|
+
## 1.5.1 (2024-10-29)
|
|
14
46
|
|
|
15
|
-
|
|
47
|
+
- Fix Audited current user setter to use `audited_user`
|
|
16
48
|
|
|
17
|
-
|
|
49
|
+
## 1.5.0 (2024-10-29)
|
|
18
50
|
|
|
19
|
-
|
|
51
|
+
- BREAKING: Rename `audited_user` to `current_user`
|
|
52
|
+
- Add `current_request_uuid` and `current_remote_addr` getters and setters
|
|
53
|
+
- Memoize `current_user`, `current_request_uuid`, and `current_remote_addr`
|
|
20
54
|
|
|
21
|
-
|
|
55
|
+
## 1.4.1 (2024-02-02)
|
|
22
56
|
|
|
23
|
-
|
|
57
|
+
- Add paper_trail support
|
|
24
58
|
|
|
25
|
-
|
|
59
|
+
## 1.4.0 (2023-08-30)
|
|
26
60
|
|
|
27
|
-
|
|
61
|
+
- Set minimum ruby version requirement to 2.5.0
|
|
28
62
|
|
|
29
|
-
|
|
30
|
-
* Update dependencies to latest
|
|
63
|
+
## 1.3.2 (2023-08-29)
|
|
31
64
|
|
|
32
|
-
|
|
65
|
+
## 1.3.1 (2023-08-29)
|
|
33
66
|
|
|
34
|
-
|
|
35
|
-
* Implemented ActionReporter::Error class
|
|
36
|
-
* Improved test coverage
|
|
67
|
+
- Update gem configuration
|
|
37
68
|
|
|
38
|
-
|
|
69
|
+
## 1.3.0 (2023-08-15)
|
|
39
70
|
|
|
40
|
-
|
|
71
|
+
- Update ruby version to 3.2.2
|
|
72
|
+
- Update dependencies to latest
|
|
41
73
|
|
|
42
|
-
|
|
74
|
+
## 1.2.0 (2023-04-20)
|
|
43
75
|
|
|
44
|
-
|
|
76
|
+
- Major fixes for class resolvers
|
|
77
|
+
- Implemented ActionReporter::Error class
|
|
78
|
+
- Improved test coverage
|
|
45
79
|
|
|
46
|
-
|
|
80
|
+
## 1.1.1 (2023-04-18)
|
|
47
81
|
|
|
48
|
-
|
|
82
|
+
- Update check-in logic
|
|
49
83
|
|
|
50
|
-
|
|
84
|
+
## 1.1.0 (2023-04-18)
|
|
51
85
|
|
|
52
|
-
|
|
86
|
+
- Add reporter check-in method
|
|
53
87
|
|
|
54
|
-
|
|
88
|
+
## 1.0.7 (2023-04-18)
|
|
55
89
|
|
|
56
|
-
|
|
90
|
+
- Moving Sentry context under `context` key
|
|
57
91
|
|
|
58
|
-
|
|
92
|
+
## 1.0.6 (2023-04-18)
|
|
59
93
|
|
|
60
|
-
|
|
94
|
+
- Possible fix for Sentry context setting
|
|
61
95
|
|
|
62
|
-
|
|
96
|
+
## 1.0.5 (2023-04-18)
|
|
63
97
|
|
|
64
|
-
|
|
98
|
+
- Fix Sentry reporting and context setting
|
|
65
99
|
|
|
66
|
-
|
|
100
|
+
## 1.0.4 (2023-04-18)
|
|
67
101
|
|
|
68
|
-
|
|
102
|
+
- Move `transform_context` to individual reporter classes
|
|
69
103
|
|
|
70
|
-
|
|
104
|
+
## 1.0.3 (2023-04-18)
|
|
71
105
|
|
|
72
|
-
|
|
73
|
-
* Update README notes
|
|
106
|
+
- Fix scoutapm notice method
|
|
74
107
|
|
|
75
|
-
|
|
108
|
+
## 1.0.2 (2023-04-18)
|
|
76
109
|
|
|
77
|
-
|
|
110
|
+
- Add ruby version support for versions lower than 3.2.0
|
|
111
|
+
|
|
112
|
+
## 1.0.1 (2023-04-18)
|
|
113
|
+
|
|
114
|
+
- Fix scoutapm reset_context method
|
|
115
|
+
- Update README notes
|
|
116
|
+
|
|
117
|
+
## 1.0.0 (2023-04-18)
|
|
118
|
+
|
|
119
|
+
- Initial version
|
data/README.md
CHANGED
|
@@ -2,89 +2,163 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/action_reporter) [](https://github.com/amkisko/action_reporter.rb/actions/workflows/test.yml) [](https://codecov.io/gh/amkisko/action_reporter.rb)
|
|
4
4
|
|
|
5
|
-
[](https://app.codacy.com/gh/amkisko/action_reporter.rb/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [](https://app.codacy.com/gh/amkisko/action_reporter.rb/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)
|
|
6
|
-
|
|
7
5
|
Ruby wrapper for multiple reporting services.
|
|
8
6
|
|
|
9
|
-
Supported services:
|
|
10
|
-
- Rails logger
|
|
11
|
-
- Audited
|
|
12
|
-
- PaperTrail
|
|
13
|
-
- Sentry
|
|
14
|
-
- Honeybadger
|
|
15
|
-
- scoutapm
|
|
7
|
+
Supported services: Rails logger, gem audited, gem PaperTrail, Sentry, Honeybadger, scoutapm.
|
|
16
8
|
|
|
17
9
|
Sponsored by [Kisko Labs](https://www.kiskolabs.com).
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+
<a href="https://www.kiskolabs.com">
|
|
12
|
+
<img src="kisko.svg" width="200" alt="Sponsored by Kisko Labs" />
|
|
13
|
+
</a>
|
|
20
14
|
|
|
21
|
-
Using Bundler:
|
|
22
|
-
```sh
|
|
23
|
-
bundle add action_reporter
|
|
24
|
-
```
|
|
25
15
|
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
gem install action_reporter
|
|
29
|
-
```
|
|
16
|
+
## Installation
|
|
30
17
|
|
|
31
|
-
|
|
18
|
+
Add to your Gemfile:
|
|
32
19
|
|
|
33
20
|
```ruby
|
|
34
|
-
gem
|
|
21
|
+
gem "action_reporter"
|
|
35
22
|
```
|
|
36
23
|
|
|
24
|
+
Run `bundle install` or `gem install action_reporter`.
|
|
25
|
+
|
|
26
|
+
|
|
37
27
|
## Usage
|
|
38
28
|
|
|
39
|
-
|
|
29
|
+
Create `config/initializers/action_reporter.rb`:
|
|
40
30
|
|
|
41
31
|
```ruby
|
|
42
32
|
ActionReporter.enabled_reporters = [
|
|
43
|
-
ActionReporter::RailsReporter.new,
|
|
33
|
+
(ActionReporter::RailsReporter.new if Rails.env.development?),
|
|
44
34
|
# ActionReporter::AuditedReporter.new,
|
|
45
35
|
# ActionReporter::PaperTrailReporter.new,
|
|
46
36
|
# ActionReporter::SentryReporter.new,
|
|
47
37
|
# ActionReporter::HoneybadgerReporter.new,
|
|
48
38
|
# ActionReporter::ScoutApmReporter.new
|
|
49
|
-
]
|
|
39
|
+
].compact
|
|
50
40
|
```
|
|
51
41
|
|
|
52
|
-
|
|
42
|
+
Set context and report errors:
|
|
53
43
|
|
|
54
44
|
```ruby
|
|
55
45
|
ActionReporter.current_user = current_user
|
|
56
|
-
ActionReporter.current_request_uuid = request.env[
|
|
57
|
-
ActionReporter.current_remote_addr = request.
|
|
46
|
+
ActionReporter.current_request_uuid = request.env["action_dispatch.request_id"]
|
|
47
|
+
ActionReporter.current_remote_addr = request.remote_ip
|
|
48
|
+
|
|
58
49
|
ActionReporter.context(entry_id: entry.id)
|
|
59
|
-
ActionReporter.notify(
|
|
50
|
+
ActionReporter.notify("Something went wrong", context: { record: record })
|
|
51
|
+
ActionReporter.reset_context
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Transaction support
|
|
55
|
+
|
|
56
|
+
ActionReporter supports transaction tracking with automatic context preservation:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
# Attribute-style setters
|
|
60
|
+
ActionReporter.transaction_id = "txn-123"
|
|
61
|
+
ActionReporter.transaction_name = "GET /api/users"
|
|
62
|
+
|
|
63
|
+
# Block-based (preserves previous values)
|
|
64
|
+
ActionReporter.transaction(name: "GET /api/users", id: "txn-123") do
|
|
65
|
+
# Your code here
|
|
66
|
+
end
|
|
60
67
|
```
|
|
61
68
|
|
|
62
|
-
##
|
|
69
|
+
## Custom Reporters
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
Create custom reporters by inheriting from `ActionReporter::Base`:
|
|
65
72
|
|
|
66
73
|
```ruby
|
|
67
74
|
module ActionReporter
|
|
68
|
-
class
|
|
75
|
+
class CustomReporter < Base
|
|
69
76
|
def notify(error, context: {})
|
|
70
|
-
|
|
71
|
-
|
|
77
|
+
new_context = transform_context(context)
|
|
78
|
+
# Send to your service
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def context(args)
|
|
82
|
+
new_context = transform_context(args)
|
|
83
|
+
# Set context in your service
|
|
72
84
|
end
|
|
73
85
|
end
|
|
74
86
|
end
|
|
87
|
+
|
|
88
|
+
ActionReporter.enabled_reporters = [ActionReporter::CustomReporter.new]
|
|
75
89
|
```
|
|
76
90
|
|
|
91
|
+
See `doc/CUSTOM_REPORTERS.md` for detailed documentation.
|
|
92
|
+
|
|
93
|
+
## Advanced Integration
|
|
94
|
+
|
|
95
|
+
ActionReporter can be extended with custom methods and integrated with `ActiveSupport::CurrentAttributes` for automatic context propagation:
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
module ActionReporter
|
|
99
|
+
def self.set_transaction_id(transaction_id)
|
|
100
|
+
context(transaction_id: transaction_id)
|
|
101
|
+
Sentry.set_tags(transactionId: transaction_id) if defined?(Sentry)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class Current < ActiveSupport::CurrentAttributes
|
|
106
|
+
attribute :user, :reporter_transaction_id
|
|
107
|
+
|
|
108
|
+
def user=(user)
|
|
109
|
+
super
|
|
110
|
+
ActionReporter.current_user = user
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def reporter_transaction_id=(transaction_id)
|
|
114
|
+
super
|
|
115
|
+
ActionReporter.transaction_id = transaction_id
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## API
|
|
121
|
+
|
|
122
|
+
- `ActionReporter.enabled_reporters = [...]` - Configure enabled reporters
|
|
123
|
+
- `ActionReporter.current_user = user` - Set current user (thread-safe)
|
|
124
|
+
- `ActionReporter.current_request_uuid = uuid` - Set request UUID
|
|
125
|
+
- `ActionReporter.current_remote_addr = addr` - Set remote address
|
|
126
|
+
- `ActionReporter.context(**args)` - Set context for all reporters
|
|
127
|
+
- `ActionReporter.notify(error, context: {})` - Report errors/messages
|
|
128
|
+
- `ActionReporter.reset_context` - Reset all context
|
|
129
|
+
- `ActionReporter.transaction_id = id` - Set transaction ID
|
|
130
|
+
- `ActionReporter.transaction_name = name` - Set transaction name
|
|
131
|
+
- `ActionReporter.transaction(name:, id:, **context, &block)` - Block-based transaction with context preservation
|
|
132
|
+
- `ActionReporter.check_in(identifier)` - Heartbeat/check-in
|
|
133
|
+
- `ActionReporter.logger = logger` - Configure error logger
|
|
134
|
+
- `ActionReporter.error_handler = proc` - Configure error handler callback
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
bundle install
|
|
141
|
+
bundle exec appraisal install
|
|
142
|
+
bundle exec rspec
|
|
143
|
+
bin/appraisals
|
|
144
|
+
bundle exec standardrb --fix
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
|
|
77
148
|
## Contributing
|
|
78
149
|
|
|
79
150
|
Bug reports and pull requests are welcome on GitHub at https://github.com/amkisko/action_reporter.rb
|
|
80
151
|
|
|
81
152
|
Contribution policy:
|
|
153
|
+
- New features are not necessarily added to the gem
|
|
154
|
+
- Pull request should have test coverage for affected parts
|
|
155
|
+
- Pull request should have changelog entry
|
|
156
|
+
|
|
157
|
+
Review policy:
|
|
82
158
|
- It might take up to 2 calendar weeks to review and merge critical fixes
|
|
83
159
|
- It might take up to 6 calendar months to review and merge pull request
|
|
84
160
|
- It might take up to 1 calendar year to review an issue
|
|
85
|
-
|
|
86
|
-
- Pull request should have test coverage for affected parts
|
|
87
|
-
- Pull request should have changelog entry
|
|
161
|
+
|
|
88
162
|
|
|
89
163
|
## Publishing
|
|
90
164
|
|
|
@@ -94,6 +168,7 @@ gem build action_reporter.gemspec
|
|
|
94
168
|
gem push action_reporter-*.gem
|
|
95
169
|
```
|
|
96
170
|
|
|
171
|
+
|
|
97
172
|
## License
|
|
98
173
|
|
|
99
174
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/action_reporter.gemspec
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
require_relative "lib/action_reporter/version"
|
|
2
|
+
|
|
1
3
|
Gem::Specification.new do |gem|
|
|
2
4
|
gem.name = "action_reporter"
|
|
3
|
-
gem.version =
|
|
5
|
+
gem.version = ActionReporter::VERSION
|
|
4
6
|
|
|
5
7
|
gem.license = "MIT"
|
|
6
8
|
|
|
@@ -9,7 +11,7 @@ Gem::Specification.new do |gem|
|
|
|
9
11
|
repository_url = "https://github.com/amkisko/action_reporter.rb"
|
|
10
12
|
|
|
11
13
|
gem.authors = ["Andrei Makarov"]
|
|
12
|
-
gem.email = ["
|
|
14
|
+
gem.email = ["contact@kiskolabs.com"]
|
|
13
15
|
gem.homepage = repository_url
|
|
14
16
|
gem.description = "Ruby wrapper for multiple reporting services"
|
|
15
17
|
gem.summary = "See description"
|
|
@@ -37,10 +39,14 @@ Gem::Specification.new do |gem|
|
|
|
37
39
|
gem.add_development_dependency "scout_apm", "~> 5"
|
|
38
40
|
gem.add_development_dependency "paper_trail", "~> 15"
|
|
39
41
|
|
|
40
|
-
gem.add_development_dependency "
|
|
42
|
+
gem.add_development_dependency "bundler", "~> 2"
|
|
43
|
+
gem.add_development_dependency "rspec", "~> 3.12"
|
|
41
44
|
gem.add_development_dependency "rspec_junit_formatter", "~> 0.6"
|
|
42
45
|
gem.add_development_dependency "webmock", "~> 3"
|
|
43
46
|
gem.add_development_dependency "pry", "~> 0.14"
|
|
44
47
|
gem.add_development_dependency "simplecov", "~> 0.21"
|
|
45
|
-
gem.add_development_dependency "simplecov-cobertura", "~>
|
|
48
|
+
gem.add_development_dependency "simplecov-cobertura", "~> 3"
|
|
49
|
+
gem.add_development_dependency "standard", "~> 1.0"
|
|
50
|
+
gem.add_development_dependency "appraisal", "~> 2.4"
|
|
51
|
+
gem.add_development_dependency "rbs", "~> 3.0"
|
|
46
52
|
end
|
data/lib/action_reporter/base.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require_relative
|
|
1
|
+
require_relative "error"
|
|
2
2
|
|
|
3
3
|
module ActionReporter
|
|
4
4
|
class Base
|
|
@@ -7,13 +7,15 @@ module ActionReporter
|
|
|
7
7
|
define_method(method_name) do
|
|
8
8
|
raise ActionReporter::Error.new("#{class_name} is not defined") unless Object.const_defined?(class_name)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# Use instance variable instead of class variable for thread safety
|
|
11
|
+
# Each class gets its own cache, avoiding cross-class contamination
|
|
12
|
+
@class_cache ||= {}
|
|
13
|
+
@class_cache[class_name] ||= begin
|
|
12
14
|
if gem_spec
|
|
13
15
|
gem_name, version = gem_spec.scan(/([^(\s]+)\s*(?:\(([^)]+)\))?/).first
|
|
14
16
|
latest_spec = Gem.loaded_specs[gem_name]
|
|
15
17
|
version_satisfied = latest_spec && Gem::Requirement.new(version).satisfied_by?(latest_spec.version)
|
|
16
|
-
raise ActionReporter::
|
|
18
|
+
raise ActionReporter::ConfigurationError.new("#{gem_spec} is not loaded") if !version_satisfied
|
|
17
19
|
end
|
|
18
20
|
Object.const_get(class_name)
|
|
19
21
|
end
|
|
@@ -36,7 +38,7 @@ module ActionReporter
|
|
|
36
38
|
elsif identifier.respond_to?(:to_s)
|
|
37
39
|
identifier.to_s
|
|
38
40
|
else
|
|
39
|
-
raise
|
|
41
|
+
raise ActionReporter::Error.new("Unknown check-in identifier: #{identifier.inspect}")
|
|
40
42
|
end
|
|
41
43
|
end
|
|
42
44
|
|
|
@@ -48,5 +50,11 @@ module ActionReporter
|
|
|
48
50
|
|
|
49
51
|
def reset_context
|
|
50
52
|
end
|
|
53
|
+
|
|
54
|
+
def transaction_id=(transaction_id)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def transaction_name=(transaction_name)
|
|
58
|
+
end
|
|
51
59
|
end
|
|
52
60
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require_relative "error"
|
|
2
|
+
|
|
3
|
+
module ActionReporter
|
|
4
|
+
# Thread-safe storage for ActionReporter context attributes
|
|
5
|
+
# Uses Thread.current for maximum compatibility and thread safety
|
|
6
|
+
# Note: ActiveSupport::CurrentAttributes is request-scoped (not thread-scoped),
|
|
7
|
+
# so we use Thread.current for proper thread isolation
|
|
8
|
+
class Current
|
|
9
|
+
class << self
|
|
10
|
+
def current_user
|
|
11
|
+
Thread.current[:action_reporter_current_user]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def current_user=(user)
|
|
15
|
+
Thread.current[:action_reporter_current_user] = user
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def current_request_uuid
|
|
19
|
+
Thread.current[:action_reporter_current_request_uuid]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def current_request_uuid=(uuid)
|
|
23
|
+
Thread.current[:action_reporter_current_request_uuid] = uuid
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def current_remote_addr
|
|
27
|
+
Thread.current[:action_reporter_current_remote_addr]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def current_remote_addr=(addr)
|
|
31
|
+
Thread.current[:action_reporter_current_remote_addr] = addr
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def transaction_id
|
|
35
|
+
Thread.current[:action_reporter_transaction_id]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def transaction_id=(transaction_id)
|
|
39
|
+
Thread.current[:action_reporter_transaction_id] = transaction_id
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def transaction_name
|
|
43
|
+
Thread.current[:action_reporter_transaction_name]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def transaction_name=(transaction_name)
|
|
47
|
+
Thread.current[:action_reporter_transaction_name] = transaction_name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def reset
|
|
51
|
+
Thread.current[:action_reporter_current_user] = nil
|
|
52
|
+
Thread.current[:action_reporter_current_request_uuid] = nil
|
|
53
|
+
Thread.current[:action_reporter_current_remote_addr] = nil
|
|
54
|
+
Thread.current[:action_reporter_transaction_id] = nil
|
|
55
|
+
Thread.current[:action_reporter_transaction_name] = nil
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
module ActionReporter
|
|
2
2
|
class Error < StandardError; end
|
|
3
|
+
|
|
4
|
+
# Raised when there's a configuration issue (e.g., missing gem, invalid setup)
|
|
5
|
+
class ConfigurationError < Error; end
|
|
6
|
+
|
|
7
|
+
# Raised when a reporter encounters an error during operation
|
|
8
|
+
class ReporterError < Error; end
|
|
3
9
|
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module ActionReporter
|
|
4
|
+
# Plugin discovery mechanism for auto-discovering reporters
|
|
5
|
+
# This is lazy-loaded to avoid blocking application boot
|
|
6
|
+
module PluginDiscovery
|
|
7
|
+
class << self
|
|
8
|
+
# Initialize class instance variables
|
|
9
|
+
@registered_reporters = {}
|
|
10
|
+
@discovered_reporters = nil
|
|
11
|
+
@discovery_lock = Mutex.new
|
|
12
|
+
|
|
13
|
+
# Accessors for class instance variables
|
|
14
|
+
def registered_reporters
|
|
15
|
+
@registered_reporters ||= {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_reader :discovered_reporters
|
|
19
|
+
|
|
20
|
+
attr_writer :discovered_reporters
|
|
21
|
+
|
|
22
|
+
def discovery_lock
|
|
23
|
+
@discovery_lock ||= Mutex.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Register a reporter manually (useful for custom reporters)
|
|
27
|
+
# @param name [Symbol] Reporter name
|
|
28
|
+
# @param class_name [String] Fully qualified class name
|
|
29
|
+
# @param require_path [String] Path to require (e.g., "action_reporter/custom_reporter")
|
|
30
|
+
def register(name, class_name:, require_path:)
|
|
31
|
+
registered_reporters[name] = {
|
|
32
|
+
class_name: class_name,
|
|
33
|
+
require_path: require_path
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Discover reporters from the filesystem (lazy-loaded, cached)
|
|
38
|
+
# Only discovers files matching *_reporter.rb pattern in action_reporter/ directory
|
|
39
|
+
# @return [Array<Class>] Array of reporter classes
|
|
40
|
+
def discover
|
|
41
|
+
return discovered_reporters if discovered_reporters
|
|
42
|
+
|
|
43
|
+
discovery_lock.synchronize do
|
|
44
|
+
return discovered_reporters if discovered_reporters
|
|
45
|
+
|
|
46
|
+
self.discovered_reporters = []
|
|
47
|
+
# __dir__ is lib/action_reporter/, so we're already in the right directory
|
|
48
|
+
base_path = __dir__
|
|
49
|
+
|
|
50
|
+
# Discover built-in reporters
|
|
51
|
+
Dir.glob(File.join(base_path, "*_reporter.rb")).each do |file|
|
|
52
|
+
reporter_class = discover_reporter_from_file(file)
|
|
53
|
+
discovered_reporters << reporter_class if reporter_class
|
|
54
|
+
rescue => e
|
|
55
|
+
# Silently skip files that can't be loaded (non-blocking)
|
|
56
|
+
warn "ActionReporter: Failed to discover reporter from #{file}: #{e.message}" if logger
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
self.discovered_reporters = discovered_reporters.freeze
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Get all available reporters (discovered + registered)
|
|
64
|
+
# @return [Array<Class>] Array of reporter classes
|
|
65
|
+
def available_reporters
|
|
66
|
+
reporters = discover.dup
|
|
67
|
+
|
|
68
|
+
# Add registered reporters (lazy-loaded)
|
|
69
|
+
registered_reporters.each_value do |config|
|
|
70
|
+
reporter_class = load_registered_reporter(config)
|
|
71
|
+
reporters << reporter_class if reporter_class
|
|
72
|
+
rescue => e
|
|
73
|
+
# Silently skip registered reporters that can't be loaded (non-blocking)
|
|
74
|
+
warn "ActionReporter: Failed to load registered reporter #{config[:class_name]}: #{e.message}" if logger
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
reporters.uniq.freeze
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Reset discovery cache (useful for testing)
|
|
81
|
+
def reset!
|
|
82
|
+
discovery_lock.synchronize do
|
|
83
|
+
self.discovered_reporters = nil
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def discover_reporter_from_file(file_path)
|
|
90
|
+
base_name = File.basename(file_path, ".rb")
|
|
91
|
+
|
|
92
|
+
# Convert snake_case to PascalCase
|
|
93
|
+
# e.g., "scout_apm_reporter" -> "ScoutApmReporter"
|
|
94
|
+
# e.g., "rails_reporter" -> "RailsReporter"
|
|
95
|
+
class_name = base_name
|
|
96
|
+
.split("_")
|
|
97
|
+
.map(&:capitalize)
|
|
98
|
+
.join
|
|
99
|
+
|
|
100
|
+
full_class_name = "ActionReporter::#{class_name}"
|
|
101
|
+
|
|
102
|
+
# Check if class is already defined (files are pre-required at boot)
|
|
103
|
+
return nil unless Object.const_defined?(full_class_name)
|
|
104
|
+
|
|
105
|
+
klass = Object.const_get(full_class_name)
|
|
106
|
+
return nil unless klass < Base
|
|
107
|
+
|
|
108
|
+
klass
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def load_registered_reporter(config)
|
|
112
|
+
# Check if class is already defined (e.g., in tests or already loaded)
|
|
113
|
+
return nil unless Object.const_defined?(config[:class_name])
|
|
114
|
+
|
|
115
|
+
klass = Object.const_get(config[:class_name])
|
|
116
|
+
return nil unless klass < Base
|
|
117
|
+
|
|
118
|
+
# Only require if class is not already available and require_path is provided
|
|
119
|
+
# This allows classes defined inline (e.g., in tests) to work without requiring files
|
|
120
|
+
if config[:require_path] && !required?(config[:require_path])
|
|
121
|
+
begin
|
|
122
|
+
require config[:require_path]
|
|
123
|
+
rescue LoadError => e
|
|
124
|
+
# If file doesn't exist but class is already defined, that's okay
|
|
125
|
+
# (e.g., class defined inline in tests or already loaded)
|
|
126
|
+
warn "ActionReporter: Could not require #{config[:require_path]}: #{e.message}" if logger
|
|
127
|
+
# Continue - class might already be defined
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
klass
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def required?(path)
|
|
135
|
+
$LOADED_FEATURES.any? { |feature| feature.include?(path) }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def logger
|
|
139
|
+
ActionReporter.logger
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -25,5 +25,15 @@ module ActionReporter
|
|
|
25
25
|
def current_user=(user)
|
|
26
26
|
sentry_class.set_user(user_global_id: user&.to_global_id&.to_s)
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
def transaction_id=(transaction_id)
|
|
30
|
+
sentry_class.set_tags(transactionId: transaction_id)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def transaction_name=(transaction_name)
|
|
34
|
+
sentry_class.configure_scope do |scope|
|
|
35
|
+
scope.set_transaction_name(transaction_name)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
28
38
|
end
|
|
29
39
|
end
|
data/lib/action_reporter.rb
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
require "action_reporter/version"
|
|
2
|
+
require "action_reporter/utils"
|
|
3
|
+
require "action_reporter/base"
|
|
4
|
+
require "action_reporter/current"
|
|
5
|
+
require "action_reporter/plugin_discovery"
|
|
6
|
+
|
|
7
|
+
# Core reporters are still required for backward compatibility
|
|
8
|
+
# But discovery mechanism allows for lazy loading and custom reporters
|
|
9
|
+
require "action_reporter/rails_reporter"
|
|
10
|
+
require "action_reporter/honeybadger_reporter"
|
|
11
|
+
require "action_reporter/sentry_reporter"
|
|
12
|
+
require "action_reporter/scout_apm_reporter"
|
|
13
|
+
require "action_reporter/audited_reporter"
|
|
14
|
+
require "action_reporter/paper_trail_reporter"
|
|
9
15
|
|
|
10
16
|
module ActionReporter
|
|
11
17
|
module_function
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
# Legacy hardcoded list (maintained for backward compatibility)
|
|
20
|
+
# Use `available_reporters` for auto-discovered reporters
|
|
15
21
|
AVAILABLE_REPORTERS = [
|
|
16
22
|
ActionReporter::RailsReporter,
|
|
17
23
|
ActionReporter::HoneybadgerReporter,
|
|
@@ -21,76 +27,163 @@ module ActionReporter
|
|
|
21
27
|
ActionReporter::PaperTrailReporter
|
|
22
28
|
].freeze
|
|
23
29
|
|
|
30
|
+
# Get available reporters (auto-discovered + registered)
|
|
31
|
+
# This is lazy-loaded and does not block application boot
|
|
32
|
+
# @return [Array<Class>] Array of reporter classes
|
|
33
|
+
def available_reporters
|
|
34
|
+
PluginDiscovery.available_reporters
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Register a custom reporter
|
|
38
|
+
# This allows third-party gems or custom code to register reporters
|
|
39
|
+
# @param name [Symbol] Reporter name
|
|
40
|
+
# @param class_name [String] Fully qualified class name
|
|
41
|
+
# @param require_path [String] Path to require
|
|
42
|
+
# @example
|
|
43
|
+
# ActionReporter.register_reporter(:custom, class_name: "MyApp::CustomReporter", require_path: "my_app/custom_reporter")
|
|
44
|
+
def register_reporter(name, class_name:, require_path:)
|
|
45
|
+
PluginDiscovery.register(name, class_name: class_name, require_path: require_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
24
48
|
@enabled_reporters = []
|
|
49
|
+
@logger = nil
|
|
50
|
+
@error_handler = nil
|
|
25
51
|
|
|
26
52
|
def enabled_reporters=(reporters)
|
|
27
|
-
@enabled_reporters = reporters
|
|
53
|
+
@enabled_reporters = reporters || []
|
|
28
54
|
end
|
|
29
55
|
|
|
30
56
|
def enabled_reporters
|
|
31
|
-
@enabled_reporters
|
|
57
|
+
@enabled_reporters || []
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def logger
|
|
61
|
+
@logger || ((defined?(Rails) && Rails.respond_to?(:logger)) ? Rails.logger : nil)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def logger=(logger)
|
|
65
|
+
@logger = logger
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def error_handler
|
|
69
|
+
@error_handler
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def error_handler=(handler)
|
|
73
|
+
@error_handler = handler
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def handle_reporter_error(reporter, error, method_name)
|
|
77
|
+
error_message = "ActionReporter: #{reporter.class}##{method_name} failed: #{error.class} - #{error.message}"
|
|
78
|
+
|
|
79
|
+
if logger
|
|
80
|
+
logger.error(error_message)
|
|
81
|
+
logger.debug(error.backtrace.join("\n")) if error.backtrace
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if error_handler&.respond_to?(:call)
|
|
85
|
+
error_handler.call(error, reporter, method_name)
|
|
86
|
+
end
|
|
87
|
+
rescue => e
|
|
88
|
+
# If error handling itself fails, log to stderr as last resort
|
|
89
|
+
warn "ActionReporter: Error handler failed: #{e.message}"
|
|
32
90
|
end
|
|
33
91
|
|
|
34
92
|
def notify(error, context: {})
|
|
35
93
|
enabled_reporters.each do |reporter|
|
|
36
94
|
next unless reporter.respond_to?(:notify)
|
|
37
95
|
|
|
38
|
-
|
|
96
|
+
begin
|
|
97
|
+
reporter.notify(error, context: context)
|
|
98
|
+
rescue => e
|
|
99
|
+
handle_reporter_error(reporter, e, "notify")
|
|
100
|
+
end
|
|
39
101
|
end
|
|
40
102
|
end
|
|
41
103
|
|
|
42
104
|
def context(args)
|
|
105
|
+
raise ArgumentError, "context must be a Hash" unless args.is_a?(Hash)
|
|
106
|
+
|
|
43
107
|
enabled_reporters.each do |reporter|
|
|
44
108
|
next unless reporter.respond_to?(:context)
|
|
45
109
|
|
|
46
|
-
|
|
110
|
+
begin
|
|
111
|
+
reporter.context(args)
|
|
112
|
+
rescue => e
|
|
113
|
+
handle_reporter_error(reporter, e, "context")
|
|
114
|
+
end
|
|
47
115
|
end
|
|
48
116
|
end
|
|
49
117
|
|
|
50
118
|
def reset_context
|
|
119
|
+
Current.current_user = nil
|
|
120
|
+
Current.current_request_uuid = nil
|
|
121
|
+
Current.current_remote_addr = nil
|
|
122
|
+
Current.transaction_id = nil
|
|
123
|
+
Current.transaction_name = nil
|
|
124
|
+
|
|
51
125
|
enabled_reporters.each do |reporter|
|
|
52
126
|
next unless reporter.respond_to?(:reset_context)
|
|
53
127
|
|
|
54
|
-
|
|
128
|
+
begin
|
|
129
|
+
reporter.reset_context
|
|
130
|
+
rescue => e
|
|
131
|
+
handle_reporter_error(reporter, e, "reset_context")
|
|
132
|
+
end
|
|
55
133
|
end
|
|
134
|
+
|
|
135
|
+
# Reset Current attributes if supported
|
|
136
|
+
Current.reset if Current.respond_to?(:reset)
|
|
56
137
|
end
|
|
57
138
|
|
|
58
139
|
def current_user
|
|
59
|
-
|
|
140
|
+
Current.current_user
|
|
60
141
|
end
|
|
61
142
|
|
|
62
143
|
def current_user=(user)
|
|
63
|
-
|
|
144
|
+
Current.current_user = user
|
|
64
145
|
enabled_reporters.each do |reporter|
|
|
65
146
|
next unless reporter.respond_to?(:current_user=)
|
|
66
147
|
|
|
67
|
-
|
|
148
|
+
begin
|
|
149
|
+
reporter.current_user = user
|
|
150
|
+
rescue => e
|
|
151
|
+
handle_reporter_error(reporter, e, "current_user=")
|
|
152
|
+
end
|
|
68
153
|
end
|
|
69
154
|
end
|
|
70
155
|
|
|
71
156
|
def current_request_uuid
|
|
72
|
-
|
|
157
|
+
Current.current_request_uuid
|
|
73
158
|
end
|
|
74
159
|
|
|
75
160
|
def current_request_uuid=(request_uuid)
|
|
76
|
-
|
|
161
|
+
Current.current_request_uuid = request_uuid
|
|
77
162
|
enabled_reporters.each do |reporter|
|
|
78
163
|
next unless reporter.respond_to?(:current_request_uuid=)
|
|
79
164
|
|
|
80
|
-
|
|
165
|
+
begin
|
|
166
|
+
reporter.current_request_uuid = request_uuid
|
|
167
|
+
rescue => e
|
|
168
|
+
handle_reporter_error(reporter, e, "current_request_uuid=")
|
|
169
|
+
end
|
|
81
170
|
end
|
|
82
171
|
end
|
|
83
172
|
|
|
84
173
|
def current_remote_addr
|
|
85
|
-
|
|
174
|
+
Current.current_remote_addr
|
|
86
175
|
end
|
|
87
176
|
|
|
88
177
|
def current_remote_addr=(remote_addr)
|
|
89
|
-
|
|
178
|
+
Current.current_remote_addr = remote_addr
|
|
90
179
|
enabled_reporters.each do |reporter|
|
|
91
180
|
next unless reporter.respond_to?(:current_remote_addr=)
|
|
92
181
|
|
|
93
|
-
|
|
182
|
+
begin
|
|
183
|
+
reporter.current_remote_addr = remote_addr
|
|
184
|
+
rescue => e
|
|
185
|
+
handle_reporter_error(reporter, e, "current_remote_addr=")
|
|
186
|
+
end
|
|
94
187
|
end
|
|
95
188
|
end
|
|
96
189
|
|
|
@@ -98,7 +191,68 @@ module ActionReporter
|
|
|
98
191
|
enabled_reporters.each do |reporter|
|
|
99
192
|
next unless reporter.respond_to?(:check_in)
|
|
100
193
|
|
|
101
|
-
|
|
194
|
+
begin
|
|
195
|
+
reporter.check_in(identifier)
|
|
196
|
+
rescue => e
|
|
197
|
+
handle_reporter_error(reporter, e, "check_in")
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def transaction_id
|
|
203
|
+
Current.transaction_id
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def transaction_id=(transaction_id)
|
|
207
|
+
Current.transaction_id = transaction_id
|
|
208
|
+
context(transaction_id: transaction_id)
|
|
209
|
+
|
|
210
|
+
enabled_reporters.each do |reporter|
|
|
211
|
+
next unless reporter.respond_to?(:transaction_id=)
|
|
212
|
+
|
|
213
|
+
begin
|
|
214
|
+
reporter.transaction_id = transaction_id
|
|
215
|
+
rescue => e
|
|
216
|
+
handle_reporter_error(reporter, e, "transaction_id=")
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def transaction_name
|
|
222
|
+
Current.transaction_name
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def transaction_name=(transaction_name)
|
|
226
|
+
Current.transaction_name = transaction_name
|
|
227
|
+
context(transaction_name: transaction_name)
|
|
228
|
+
|
|
229
|
+
enabled_reporters.each do |reporter|
|
|
230
|
+
next unless reporter.respond_to?(:transaction_name=)
|
|
231
|
+
|
|
232
|
+
begin
|
|
233
|
+
reporter.transaction_name = transaction_name
|
|
234
|
+
rescue => e
|
|
235
|
+
handle_reporter_error(reporter, e, "transaction_name=")
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def transaction(name: nil, id: nil, **context_options, &block)
|
|
241
|
+
raise ArgumentError, "transaction requires a block" unless block_given?
|
|
242
|
+
|
|
243
|
+
previous_name = transaction_name
|
|
244
|
+
previous_id = transaction_id
|
|
245
|
+
|
|
246
|
+
begin
|
|
247
|
+
self.transaction_name = name if name
|
|
248
|
+
self.transaction_id = id if id
|
|
249
|
+
|
|
250
|
+
context(context_options) if context_options.any?
|
|
251
|
+
|
|
252
|
+
block.call
|
|
253
|
+
ensure
|
|
254
|
+
self.transaction_name = previous_name if name
|
|
255
|
+
self.transaction_id = previous_id if id
|
|
102
256
|
end
|
|
103
257
|
end
|
|
104
258
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: action_reporter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-11-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -94,20 +94,34 @@ dependencies:
|
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '15'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: bundler
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '2'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '2'
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
112
|
name: rspec
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
100
114
|
requirements:
|
|
101
115
|
- - "~>"
|
|
102
116
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '3'
|
|
117
|
+
version: '3.12'
|
|
104
118
|
type: :development
|
|
105
119
|
prerelease: false
|
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
121
|
requirements:
|
|
108
122
|
- - "~>"
|
|
109
123
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '3'
|
|
124
|
+
version: '3.12'
|
|
111
125
|
- !ruby/object:Gem::Dependency
|
|
112
126
|
name: rspec_junit_formatter
|
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,17 +184,59 @@ dependencies:
|
|
|
170
184
|
requirements:
|
|
171
185
|
- - "~>"
|
|
172
186
|
- !ruby/object:Gem::Version
|
|
173
|
-
version: '
|
|
187
|
+
version: '3'
|
|
174
188
|
type: :development
|
|
175
189
|
prerelease: false
|
|
176
190
|
version_requirements: !ruby/object:Gem::Requirement
|
|
177
191
|
requirements:
|
|
178
192
|
- - "~>"
|
|
179
193
|
- !ruby/object:Gem::Version
|
|
180
|
-
version: '
|
|
194
|
+
version: '3'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: standard
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '1.0'
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '1.0'
|
|
209
|
+
- !ruby/object:Gem::Dependency
|
|
210
|
+
name: appraisal
|
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
|
212
|
+
requirements:
|
|
213
|
+
- - "~>"
|
|
214
|
+
- !ruby/object:Gem::Version
|
|
215
|
+
version: '2.4'
|
|
216
|
+
type: :development
|
|
217
|
+
prerelease: false
|
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
219
|
+
requirements:
|
|
220
|
+
- - "~>"
|
|
221
|
+
- !ruby/object:Gem::Version
|
|
222
|
+
version: '2.4'
|
|
223
|
+
- !ruby/object:Gem::Dependency
|
|
224
|
+
name: rbs
|
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
|
226
|
+
requirements:
|
|
227
|
+
- - "~>"
|
|
228
|
+
- !ruby/object:Gem::Version
|
|
229
|
+
version: '3.0'
|
|
230
|
+
type: :development
|
|
231
|
+
prerelease: false
|
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
233
|
+
requirements:
|
|
234
|
+
- - "~>"
|
|
235
|
+
- !ruby/object:Gem::Version
|
|
236
|
+
version: '3.0'
|
|
181
237
|
description: Ruby wrapper for multiple reporting services
|
|
182
238
|
email:
|
|
183
|
-
-
|
|
239
|
+
- contact@kiskolabs.com
|
|
184
240
|
executables: []
|
|
185
241
|
extensions: []
|
|
186
242
|
extra_rdoc_files: []
|
|
@@ -192,13 +248,16 @@ files:
|
|
|
192
248
|
- lib/action_reporter.rb
|
|
193
249
|
- lib/action_reporter/audited_reporter.rb
|
|
194
250
|
- lib/action_reporter/base.rb
|
|
251
|
+
- lib/action_reporter/current.rb
|
|
195
252
|
- lib/action_reporter/error.rb
|
|
196
253
|
- lib/action_reporter/honeybadger_reporter.rb
|
|
197
254
|
- lib/action_reporter/paper_trail_reporter.rb
|
|
255
|
+
- lib/action_reporter/plugin_discovery.rb
|
|
198
256
|
- lib/action_reporter/rails_reporter.rb
|
|
199
257
|
- lib/action_reporter/scout_apm_reporter.rb
|
|
200
258
|
- lib/action_reporter/sentry_reporter.rb
|
|
201
259
|
- lib/action_reporter/utils.rb
|
|
260
|
+
- lib/action_reporter/version.rb
|
|
202
261
|
homepage: https://github.com/amkisko/action_reporter.rb
|
|
203
262
|
licenses:
|
|
204
263
|
- MIT
|