exception_handling 3.1.2 → 3.2.0.pre.dc.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2233f129161cf047d7859362e4801aab61ee8f5c6a91224733b92c5c0222120c
4
- data.tar.gz: 16c764f0a44dac9de1774cdc5716a81e80488664f7b5e2d658dd2435f8dcfc8b
3
+ metadata.gz: 5a1419e36b2b184e6e49ad6b943537b1f5efaf54680aef66251093c242e93168
4
+ data.tar.gz: 641de9b2e454c20cb754469fce0f781136baefb14af6913ab25fce3f0263bae4
5
5
  SHA512:
6
- metadata.gz: acd751fa75679ea47611198b450caa91a2d46e9b36766f070d8344a499370004da310b54df8b841220fe74a35b36498317cdf7a333d84c7c7abcc374ef95ef17
7
- data.tar.gz: 25af611bb83d53bd23e038f38b5a5bf33f99b166d14e4dfd080a4824429b1d334a57560c8e739a6e6b5fdc4aa9776f6c18a0110b1452f08345ea2d3647d8104a
6
+ metadata.gz: d3ba9e37ec6c14e508341b604df6ffaeed7c88106ca19305f69a2990f6eefcf03a8ae41a3fb6f7245165e00cb910940ae99842f6d73d9c641d8a9f9c2293a883
7
+ data.tar.gz: a9402fb31a6cce4d2181d9b304376412c7acbf63ffb4e592615da2a2bfd77330c8e6ef1a9bb4c3e1428f6dd9bec32295c5f572860117912cb4f34c6f9e49df27
@@ -1,28 +1,9 @@
1
- ---
2
1
  name: Pipeline
3
- on: [push]
2
+ on:
3
+ push:
4
+ schedule:
5
+ - cron: '0 1 * * 1' # Every Monday at 1AM UTC
4
6
  jobs:
5
7
  tests:
6
- name: Unit Tests
7
- runs-on: ubuntu-latest
8
- strategy:
9
- fail-fast: false
10
- matrix:
11
- ruby: [2.7, '3.0', 3.1, 3.2, 3.3]
12
- gemfile:
13
- - Gemfile
14
- - gemfiles/rails_6_0.gemfile
15
- - gemfiles/rails_6_1.gemfile
16
- - gemfiles/rails_7_0.gemfile
17
- - gemfiles/rails_7_1.gemfile
18
- env:
19
- BUNDLE_GEMFILE: ${{ matrix.gemfile }}
20
- steps:
21
- - uses: actions/checkout@v2
22
- - uses: ruby/setup-ruby@v1
23
- with:
24
- ruby-version: ${{ matrix.ruby }}
25
- bundler: 2.3.26
26
- bundler-cache: true
27
- - name: Unit tests
28
- run: bundle exec rspec
8
+ uses: Invoca/ruby-test-matrix-workflow/.github/workflows/ruby-test-matrix.yml@main
9
+ secrets: inherit
data/.gitignore CHANGED
@@ -4,3 +4,4 @@
4
4
  spec/reports/*
5
5
  gemfiles/*.lock
6
6
  pkg/
7
+ coverage/
data/Appraisals CHANGED
@@ -1,17 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise "rails-6-0" do
4
- gem 'activesupport', '~> 6.0.0'
5
- end
6
-
7
- appraise "rails-6-1" do
8
- gem 'activesupport', '~> 6.1.0'
9
- end
10
-
11
- appraise "rails-7-0" do
12
- gem 'activesupport', '~> 7.0.0'
13
- end
14
-
15
- appraise "rails-7-1" do
16
- gem 'activesupport', '~> 7.1.0'
17
- end
3
+ require "appraisal/matrix"
4
+ appraisal_matrix(rails: "7.0")
data/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4
4
 
5
5
  **Note:** this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.2.0] - 2026-08-04
8
+ ### Added
9
+ - Optional Sentry notifications from `send_external_notifications` when the `Sentry` constant is defined
10
+ - `send_to_sentry` exception filter flag (default `false`); filters with `send_to_honeybadger: true` also send to Sentry to ease migration
11
+
7
12
  ## [3.1.2] - 2024-05-08
8
13
  ### Fixed
9
14
  - Fixed deprecation warnings that were coming from usage of `silence` when using this gem with Rails 7.1
data/Gemfile CHANGED
@@ -5,7 +5,8 @@ source 'https://rubygems.org'
5
5
  gemspec
6
6
 
7
7
  gem 'activesupport'
8
- gem 'appraisal', '~> 2.2'
8
+ gem 'appraisal'
9
+ gem 'appraisal-matrix'
9
10
  gem 'gem-release'
10
11
  gem 'honeybadger', '~> 4.11'
11
12
  gem 'pry'
@@ -14,4 +15,13 @@ gem 'rake'
14
15
  gem 'rspec'
15
16
  gem 'rspec_junit_formatter'
16
17
  gem 'rubocop'
18
+ gem 'simplecov', '~> 0.22'
19
+ gem 'simplecov-lcov', '~> 0.8'
17
20
  gem 'test-unit'
21
+
22
+
23
+ gem "concurrent-ruby", "~> 1.3", "< 1.3.5"
24
+
25
+ gem "base64", ">= 0.2.0"
26
+ gem "bigdecimal", ">= 3.1"
27
+ gem "mutex_m", ">= 0.2.0"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- exception_handling (3.1.2)
4
+ exception_handling (3.2.0.pre.dc.0)
5
5
  activesupport (>= 5.2)
6
6
  contextual_logger (~> 1.0)
7
7
  escalate (~> 0.3)
@@ -25,25 +25,29 @@ GEM
25
25
  bundler
26
26
  rake
27
27
  thor (>= 0.14.0)
28
+ appraisal-matrix (0.3.0)
29
+ appraisal (~> 2.2)
28
30
  ast (2.4.2)
29
31
  base64 (0.2.0)
30
32
  bigdecimal (3.1.8)
31
33
  byebug (11.1.3)
32
34
  coderay (1.1.3)
33
- concurrent-ruby (1.2.3)
35
+ concurrent-ruby (1.3.4)
34
36
  connection_pool (2.4.1)
35
- contextual_logger (1.2.0)
36
- activesupport
37
+ contextual_logger (1.5.0)
38
+ activesupport (>= 6.0)
37
39
  json
40
+ date (3.5.1)
38
41
  diff-lcs (1.5.1)
42
+ docile (1.4.1)
39
43
  drb (2.2.1)
40
44
  escalate (0.3.0)
41
45
  gem-release (2.2.2)
42
46
  honeybadger (4.12.2)
43
47
  i18n (1.14.5)
44
48
  concurrent-ruby (~> 1.0)
45
- invoca-utils (0.5.1)
46
- activesupport (>= 5.0)
49
+ invoca-utils (0.7.0)
50
+ activesupport (>= 6.0)
47
51
  json (2.7.2)
48
52
  language_server-protocol (3.17.0.3)
49
53
  method_source (1.1.0)
@@ -60,7 +64,8 @@ GEM
60
64
  pry-byebug (3.10.1)
61
65
  byebug (~> 11.0)
62
66
  pry (>= 0.13, < 0.15)
63
- psych (5.1.2)
67
+ psych (5.4.0)
68
+ date
64
69
  stringio
65
70
  racc (1.7.3)
66
71
  rainbow (3.1.1)
@@ -96,7 +101,14 @@ GEM
96
101
  rubocop-ast (1.31.3)
97
102
  parser (>= 3.3.1.0)
98
103
  ruby-progressbar (1.13.0)
99
- stringio (3.1.0)
104
+ simplecov (0.22.0)
105
+ docile (~> 1.1)
106
+ simplecov-html (~> 0.11)
107
+ simplecov_json_formatter (~> 0.1)
108
+ simplecov-html (0.13.2)
109
+ simplecov-lcov (0.9.0)
110
+ simplecov_json_formatter (0.1.4)
111
+ stringio (3.2.0)
100
112
  test-unit (3.6.2)
101
113
  power_assert
102
114
  thor (1.3.1)
@@ -109,16 +121,23 @@ PLATFORMS
109
121
 
110
122
  DEPENDENCIES
111
123
  activesupport
112
- appraisal (~> 2.2)
124
+ appraisal
125
+ appraisal-matrix
126
+ base64 (>= 0.2.0)
127
+ bigdecimal (>= 3.1)
128
+ concurrent-ruby (~> 1.3, < 1.3.5)
113
129
  exception_handling!
114
130
  gem-release
115
131
  honeybadger (~> 4.11)
132
+ mutex_m (>= 0.2.0)
116
133
  pry
117
134
  pry-byebug
118
135
  rake
119
136
  rspec
120
137
  rspec_junit_formatter
121
138
  rubocop
139
+ simplecov (~> 0.22)
140
+ simplecov-lcov (~> 0.8)
122
141
  test-unit
123
142
 
124
143
  BUNDLED WITH
data/README.md CHANGED
@@ -39,6 +39,22 @@ ExceptionHandling.honeybadger_auto_tagger = ->(exception) { [] } # See "Automati
39
39
  ExceptionHandling.add_honeybadger_tag_from_log_context("tag-name", path: ["path", "in", "log", "context"])
40
40
  ```
41
41
 
42
+ ### External error trackers (Honeybadger / Sentry)
43
+
44
+ ExceptionHandling notifies configured external services from `log_error` (and related paths):
45
+
46
+ - **Honeybadger** — when the `Honeybadger` constant is defined
47
+ - **Sentry** — when the `Sentry` constant is defined (for example after initializing the Sentry Ruby SDK in your app)
48
+
49
+ Both can run at the same time. This gem does not depend on `sentry-ruby`; initialize Sentry in the host application.
50
+
51
+ Matched exception filters in `exception_filters.yml` control delivery:
52
+
53
+ - `send_to_honeybadger: true` — send to Honeybadger (and also to Sentry during migration)
54
+ - `send_to_sentry: true` — send to Sentry
55
+ - Unmatched exceptions are sent when the corresponding service is defined
56
+ - Matched filters with both flags false skip both services
57
+
42
58
  ## Usage
43
59
 
44
60
  Mixin the `ExceptionHandling::Methods` module into your controllers, models or classes. The example below adds it to all the controllers in you rails application:
data/catalog-info.yaml ADDED
@@ -0,0 +1,39 @@
1
+ # This file is partially auto-generated by the invoca-backstage-tools gem
2
+ # The following fields should not be edited manually as they are auto-generated
3
+ # based on the contents of the repo:
4
+ # - metadata.name
5
+ # - metadata.title
6
+ # - metadata.description
7
+ # - annotations.github.com/project-slug
8
+ # - invoca.com/version-repository-location
9
+ # - invoca.com/version-repository-name
10
+ # - spec.type
11
+ # - spec.owner
12
+ ---
13
+ apiVersion: backstage.io/v1alpha1
14
+ kind: Component
15
+ metadata:
16
+ name: exception_handling-gem
17
+ title: ExceptionHandling
18
+ annotations:
19
+ buildkite.com/project-slug: Invoca/exception_handling
20
+ github.com/project-slug: Invoca/exception_handling
21
+ invoca.com/version-repository-location: rubygems
22
+ invoca.com/version-repository-name: exception_handling
23
+ endoflife.date/products: ruby@3.3
24
+ tags:
25
+ - ruby
26
+ - open-source
27
+ - gem
28
+ - public
29
+ - rails-dependent
30
+ description: Exception handling logger
31
+ spec:
32
+ type: library
33
+ lifecycle: production
34
+ owner: octothorpe
35
+ system: platform-observability
36
+ dependsOn:
37
+ - component:escalate-gem
38
+ - component:invoca-utils-gem
39
+ - component:contextual_logger-gem
@@ -2,8 +2,9 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 7.0.0"
6
- gem "appraisal", "~> 2.2"
5
+ gem "activesupport"
6
+ gem "appraisal"
7
+ gem "appraisal-matrix"
7
8
  gem "gem-release"
8
9
  gem "honeybadger", "~> 4.11"
9
10
  gem "pry"
@@ -13,5 +14,12 @@ gem "rspec"
13
14
  gem "rspec_junit_formatter"
14
15
  gem "rubocop"
15
16
  gem "test-unit"
17
+ gem "concurrent-ruby", "~> 1.3", "< 1.3.5"
18
+ gem "base64", ">= 0.2.0"
19
+ gem "bigdecimal", ">= 3.1"
20
+ gem "mutex_m", ">= 0.2.0"
21
+ gem "rails", "~> 7.0.0"
22
+ gem "simplecov", "~> 0.22"
23
+ gem "simplecov-lcov", "~> 0.8"
16
24
 
17
25
  gemspec path: "../"
@@ -2,8 +2,9 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 7.1.0"
6
- gem "appraisal", "~> 2.2"
5
+ gem "activesupport"
6
+ gem "appraisal"
7
+ gem "appraisal-matrix"
7
8
  gem "gem-release"
8
9
  gem "honeybadger", "~> 4.11"
9
10
  gem "pry"
@@ -13,5 +14,12 @@ gem "rspec"
13
14
  gem "rspec_junit_formatter"
14
15
  gem "rubocop"
15
16
  gem "test-unit"
17
+ gem "concurrent-ruby", "~> 1.3", "< 1.3.5"
18
+ gem "base64", ">= 0.2.0"
19
+ gem "bigdecimal", ">= 3.1"
20
+ gem "mutex_m", ">= 0.2.0"
21
+ gem "rails", "~> 7.1.0"
22
+ gem "simplecov", "~> 0.22"
23
+ gem "simplecov-lcov", "~> 0.8"
16
24
 
17
25
  gemspec path: "../"
@@ -0,0 +1,25 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport"
6
+ gem "appraisal"
7
+ gem "appraisal-matrix"
8
+ gem "gem-release"
9
+ gem "honeybadger", "~> 4.11"
10
+ gem "pry"
11
+ gem "pry-byebug"
12
+ gem "rake"
13
+ gem "rspec"
14
+ gem "rspec_junit_formatter"
15
+ gem "rubocop"
16
+ gem "test-unit"
17
+ gem "concurrent-ruby", "~> 1.3", "< 1.3.5"
18
+ gem "base64", ">= 0.2.0"
19
+ gem "bigdecimal", ">= 3.1"
20
+ gem "mutex_m", ">= 0.2.0"
21
+ gem "rails", "~> 7.2.0"
22
+ gem "simplecov", "~> 0.22"
23
+ gem "simplecov-lcov", "~> 0.8"
24
+
25
+ gemspec path: "../"
@@ -0,0 +1,25 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport"
6
+ gem "appraisal"
7
+ gem "appraisal-matrix"
8
+ gem "gem-release"
9
+ gem "honeybadger", "~> 4.11"
10
+ gem "pry"
11
+ gem "pry-byebug"
12
+ gem "rake"
13
+ gem "rspec"
14
+ gem "rspec_junit_formatter"
15
+ gem "rubocop"
16
+ gem "test-unit"
17
+ gem "concurrent-ruby", "~> 1.3", "< 1.3.5"
18
+ gem "base64", ">= 0.2.0"
19
+ gem "bigdecimal", ">= 3.1"
20
+ gem "mutex_m", ">= 0.2.0"
21
+ gem "rails", "~> 8.0.0"
22
+ gem "simplecov", "~> 0.22"
23
+ gem "simplecov-lcov", "~> 0.8"
24
+
25
+ gemspec path: "../"
@@ -6,12 +6,13 @@ module ExceptionHandling
6
6
 
7
7
  CONFIGURATION_SECTIONS = {
8
8
  send_to_honeybadger: false, # should be sent to honeybadger?
9
+ send_to_sentry: false, # should be sent to sentry?
9
10
  send_metric: true, # should the metric be sent.
10
11
  metric_name: nil, # Will be derived from section name if not passed
11
12
  notes: nil # Will be included in exception email if set, used to keep notes and relevant links
12
13
  }.freeze
13
14
 
14
- attr_reader :filter_name, :send_to_honeybadger, :send_metric, :metric_name, :notes
15
+ attr_reader :filter_name, :send_to_honeybadger, :send_to_sentry, :send_metric, :metric_name, :notes
15
16
 
16
17
  def initialize(filter_name, configuration)
17
18
  @filter_name = filter_name
@@ -21,6 +22,7 @@ module ExceptionHandling
21
22
 
22
23
  @configuration = CONFIGURATION_SECTIONS.merge(configuration)
23
24
  @send_to_honeybadger = @configuration[:send_to_honeybadger]
25
+ @send_to_sentry = @configuration[:send_to_sentry]
24
26
  @send_metric = @configuration[:send_metric]
25
27
  @metric_name = (@configuration[:metric_name] || @filter_name).to_s.gsub(" ", "_")
26
28
  @notes = @configuration[:notes]
@@ -78,6 +78,14 @@ module ExceptionHandling
78
78
  ExceptionHandling.honeybadger_defined? && (!exception_description || exception_description.send_to_honeybadger)
79
79
  end
80
80
 
81
+ def send_to_sentry?
82
+ ExceptionHandling.sentry_defined? && (
83
+ !exception_description ||
84
+ exception_description.send_to_sentry ||
85
+ exception_description.send_to_honeybadger
86
+ )
87
+ end
88
+
81
89
  def honeybadger_context_data
82
90
  @honeybadger_context_data ||= enhanced_data_to_honeybadger_context
83
91
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExceptionHandling
4
- VERSION = '3.1.2'
4
+ VERSION = '3.2.0.pre.dc.0'
5
5
  end
@@ -211,6 +211,9 @@ module ExceptionHandling # never included
211
211
  if honeybadger_defined?
212
212
  results[:honeybadger_status] = send_exception_to_honeybadger_unless_filtered(exception_info)
213
213
  end
214
+ if sentry_defined?
215
+ results[:sentry_status] = send_exception_to_sentry_unless_filtered(exception_info)
216
+ end
214
217
  results
215
218
  end
216
219
 
@@ -249,6 +252,31 @@ module ExceptionHandling # never included
249
252
  :failure
250
253
  end
251
254
 
255
+ # Returns :success or :failure or :skipped
256
+ def send_exception_to_sentry_unless_filtered(exception_info)
257
+ if exception_info.send_to_sentry?
258
+ send_exception_to_sentry(exception_info)
259
+ else
260
+ log_info("Filtered exception using '#{exception_info.exception_description.filter_name}'; not sending notification to Sentry")
261
+ :skipped
262
+ end
263
+ end
264
+
265
+ #
266
+ # Log exception to Sentry.
267
+ #
268
+ # Returns :success or :failure
269
+ #
270
+ def send_exception_to_sentry(exception_info)
271
+ exception = exception_info.exception
272
+ response = Sentry.capture_exception(exception)
273
+ response ? :success : :failure
274
+ rescue Exception => ex
275
+ warn("ExceptionHandling.send_exception_to_sentry rescued exception while logging #{exception_info.exception_context}:\n#{exception.class}: #{exception.message}:\n#{ex.class}: #{ex.message}\n#{ex.backtrace.join("\n")}")
276
+ write_exception_to_log(ex, "ExceptionHandling.send_exception_to_sentry rescued exception while logging #{exception_info.exception_context}:\n#{exception.class}: #{exception.message}", exception_info.timestamp)
277
+ :failure
278
+ end
279
+
252
280
  #
253
281
  # Check if Honeybadger defined.
254
282
  #
@@ -256,6 +284,13 @@ module ExceptionHandling # never included
256
284
  Object.const_defined?("Honeybadger")
257
285
  end
258
286
 
287
+ #
288
+ # Check if Sentry defined.
289
+ #
290
+ def sentry_defined?
291
+ Object.const_defined?("Sentry")
292
+ end
293
+
259
294
  #
260
295
  # Expects passed in hash to only include keys which be directly set on the Honeybadger config
261
296
  #
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless ENV["NO_COVERAGE"] == "true"
4
+ require "simplecov"
5
+
6
+ SimpleCov.start do
7
+ add_filter "/spec/"
8
+ track_files "lib/**/*.rb"
9
+
10
+ if ENV["GITHUB_ACTIONS"]
11
+ require "simplecov-lcov"
12
+
13
+ SimpleCov::Formatter::LcovFormatter.config do |config|
14
+ config.report_with_single_file = true
15
+ config.single_report_path = "coverage/lcov.info"
16
+ end
17
+
18
+ formatter SimpleCov::Formatter::LcovFormatter
19
+ else
20
+ formatter SimpleCov::Formatter::HTMLFormatter
21
+ end
22
+ end
23
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "simplecov_helper"
4
+
3
5
  require 'rspec'
4
6
  require 'rspec/mocks'
5
7
  require 'rspec_junit_formatter'
@@ -35,6 +35,12 @@ module ExceptionHandling
35
35
  expect(!ExceptionDescription.new(:filter1, error: "my error message").send_to_honeybadger).to be_truthy
36
36
  end
37
37
 
38
+ it "allow send_to_sentry to be specified and have it disabled by default" do
39
+ expect(ExceptionDescription.new(:filter1, error: "my error message", send_to_sentry: false).send_to_sentry).to eq(false)
40
+ expect(ExceptionDescription.new(:filter1, error: "my error message", send_to_sentry: true).send_to_sentry).to eq(true)
41
+ expect(ExceptionDescription.new(:filter1, error: "my error message").send_to_sentry).to eq(false)
42
+ end
43
+
38
44
  it "allow send_metric to be configured" do
39
45
  expect(!ExceptionDescription.new(:filter1, error: "my error message", send_metric: false).send_metric).to be_truthy
40
46
  expect(ExceptionDescription.new(:filter1, error: "my error message").send_metric).to be_truthy
@@ -452,6 +452,48 @@ module ExceptionHandling
452
452
  end
453
453
  end
454
454
 
455
+ context "send_to_sentry?" do
456
+ it "be enabled when Sentry is defined and exception is not in the filter list" do
457
+ allow(ExceptionHandling).to receive(:sentry_defined?).and_return(true)
458
+ exception_info = ExceptionInfo.new(StandardError.new("something went wrong"), nil, Time.now)
459
+ expect(exception_info.exception_description).to be_nil
460
+ expect(exception_info.send_to_sentry?).to eq(true)
461
+ end
462
+
463
+ it "be enabled when Sentry is defined and filter has send_to_sentry true" do
464
+ allow(ExceptionHandling).to receive(:sentry_defined?).and_return(true)
465
+ exception = StandardError.new("No route matches")
466
+ exception_info = ExceptionInfo.new(exception, nil, Time.now)
467
+ allow(exception_info.exception_description).to receive(:send_to_sentry).and_return(true)
468
+ allow(exception_info.exception_description).to receive(:send_to_honeybadger).and_return(false)
469
+ expect(exception_info.send_to_sentry?).to eq(true)
470
+ end
471
+
472
+ it "be enabled when Sentry is defined and filter has send_to_honeybadger true only" do
473
+ allow(ExceptionHandling).to receive(:sentry_defined?).and_return(true)
474
+ exception = StandardError.new("No route matches")
475
+ exception_info = ExceptionInfo.new(exception, nil, Time.now)
476
+ allow(exception_info.exception_description).to receive(:send_to_sentry).and_return(false)
477
+ allow(exception_info.exception_description).to receive(:send_to_honeybadger).and_return(true)
478
+ expect(exception_info.send_to_sentry?).to eq(true)
479
+ end
480
+
481
+ it "be disabled when Sentry is defined and both filter flags are false" do
482
+ allow(ExceptionHandling).to receive(:sentry_defined?).and_return(true)
483
+ exception = StandardError.new("No route matches")
484
+ exception_info = ExceptionInfo.new(exception, nil, Time.now)
485
+ allow(exception_info.exception_description).to receive(:send_to_sentry).and_return(false)
486
+ allow(exception_info.exception_description).to receive(:send_to_honeybadger).and_return(false)
487
+ expect(exception_info.send_to_sentry?).to eq(false)
488
+ end
489
+
490
+ it "be disabled when Sentry is not defined" do
491
+ allow(ExceptionHandling).to receive(:sentry_defined?).and_return(false)
492
+ exception_info = ExceptionInfo.new(StandardError.new("something went wrong"), nil, Time.now)
493
+ expect(exception_info.send_to_sentry?).to eq(false)
494
+ end
495
+ end
496
+
455
497
  context "honeybadger_context_data" do
456
498
  before do
457
499
  allow(ExceptionHandling.logger).to receive(:current_context_for_thread).and_return({ cuid: 'ABCD' })
@@ -690,6 +690,139 @@ describe ExceptionHandling do
690
690
  end
691
691
  end
692
692
 
693
+ context "Sentry integration" do
694
+ context "with Sentry not defined" do
695
+ before do
696
+ allow(ExceptionHandling).to receive(:sentry_defined?).and_return(false)
697
+ end
698
+
699
+ it "not invoke send_exception_to_sentry when log_error is executed" do
700
+ expect(ExceptionHandling).to_not receive(:send_exception_to_sentry)
701
+ ExceptionHandling.log_error(exception_1)
702
+ end
703
+
704
+ it "not invoke send_exception_to_sentry when ensure_safe is executed" do
705
+ expect(ExceptionHandling).to_not receive(:send_exception_to_sentry)
706
+ ExceptionHandling.ensure_safe { raise exception_1 }
707
+ end
708
+ end
709
+
710
+ context "with Sentry defined" do
711
+ let(:sentry_module) do
712
+ Module.new do
713
+ def self.capture_exception(_exception); end
714
+ end
715
+ end
716
+
717
+ before do
718
+ stub_const("Sentry", sentry_module)
719
+ allow(Sentry).to receive(:capture_exception).and_return(Object.new)
720
+ end
721
+
722
+ it "not send_exception_to_sentry when log_warning is executed" do
723
+ expect(ExceptionHandling).to_not receive(:send_exception_to_sentry)
724
+ ExceptionHandling.log_warning("This should not go to sentry")
725
+ end
726
+
727
+ it "not send_exception_to_sentry when log_error is called with a Warning" do
728
+ expect(ExceptionHandling).to_not receive(:send_exception_to_sentry)
729
+ ExceptionHandling.log_error(ExceptionHandling::Warning.new("This should not go to sentry"))
730
+ end
731
+
732
+ it "invoke send_exception_to_sentry when log_error is executed" do
733
+ expect(ExceptionHandling).to receive(:send_exception_to_sentry).with(any_args).and_call_original
734
+ ExceptionHandling.log_error(exception_1)
735
+ end
736
+
737
+ it "invoke send_exception_to_sentry when log_error_rack is executed" do
738
+ expect(ExceptionHandling).to receive(:send_exception_to_sentry).with(any_args).and_call_original
739
+ ExceptionHandling.log_error_rack(exception_1, {}, nil)
740
+ end
741
+
742
+ it "invoke send_exception_to_sentry when ensure_safe is executed" do
743
+ expect(ExceptionHandling).to receive(:send_exception_to_sentry).with(any_args).and_call_original
744
+ ExceptionHandling.ensure_safe { raise exception_1 }
745
+ end
746
+
747
+ it "call Sentry.capture_exception with the exception" do
748
+ expect(Sentry).to receive(:capture_exception).with(exception_1)
749
+ ExceptionHandling.log_error(exception_1)
750
+ end
751
+
752
+ it "also notify Honeybadger when both are defined" do
753
+ expect(Honeybadger).to receive(:notify).with(any_args).and_return("hb-id")
754
+ expect(Sentry).to receive(:capture_exception).with(exception_1).and_return(Object.new)
755
+ ExceptionHandling.log_error(exception_1)
756
+ end
757
+
758
+ it "not send to Sentry when filter has both flags false" do
759
+ filter_list = {
760
+ NoSentry: {
761
+ error: "suppress Sentry notification",
762
+ send_to_honeybadger: false,
763
+ send_to_sentry: false
764
+ }
765
+ }
766
+ allow(File).to receive(:mtime) { incrementing_mtime }
767
+ expect(YAML).to receive(:load_file).with(any_args) { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }.at_least(1)
768
+
769
+ expect(ExceptionHandling).to receive(:send_exception_to_sentry_unless_filtered).with(any_args).exactly(1).and_call_original
770
+ expect(Sentry).to_not receive(:capture_exception)
771
+ ExceptionHandling.log_error(StandardError.new("suppress Sentry notification"))
772
+ end
773
+
774
+ it "send to Sentry when filter has send_to_honeybadger true only" do
775
+ filter_list = {
776
+ HoneybadgerOnly: {
777
+ error: "honeybadger only filter",
778
+ send_to_honeybadger: true,
779
+ send_to_sentry: false
780
+ }
781
+ }
782
+ allow(File).to receive(:mtime) { incrementing_mtime }
783
+ expect(YAML).to receive(:load_file).with(any_args) { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }.at_least(1)
784
+
785
+ expect(Sentry).to receive(:capture_exception).with(instance_of(StandardError))
786
+ ExceptionHandling.log_error(StandardError.new("honeybadger only filter"))
787
+ end
788
+
789
+ it "send to Sentry when filter has send_to_sentry true only" do
790
+ filter_list = {
791
+ SentryOnly: {
792
+ error: "sentry only filter",
793
+ send_to_honeybadger: false,
794
+ send_to_sentry: true
795
+ }
796
+ }
797
+ allow(File).to receive(:mtime) { incrementing_mtime }
798
+ expect(YAML).to receive(:load_file).with(any_args) { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }.at_least(1)
799
+
800
+ expect(Sentry).to receive(:capture_exception).with(instance_of(StandardError))
801
+ ExceptionHandling.log_error(StandardError.new("sentry only filter"))
802
+ end
803
+
804
+ it "still complete log_error and notify Honeybadger if Sentry.capture_exception raises" do
805
+ expect(Honeybadger).to receive(:notify).with(any_args).and_return("hb-id")
806
+ expect(Sentry).to receive(:capture_exception).and_raise(StandardError, "Sentry Notification Failure")
807
+ expect { ExceptionHandling.log_error(exception_1) }.not_to raise_error
808
+ end
809
+
810
+ it "return :failure when Sentry.capture_exception returns nil" do
811
+ expect(Sentry).to receive(:capture_exception).and_return(nil)
812
+ expect(ExceptionHandling.send_exception_to_sentry(
813
+ ExceptionHandling::ExceptionInfo.new(exception_1, "", Time.now)
814
+ )).to eq(:failure)
815
+ end
816
+
817
+ it "return :success when Sentry.capture_exception returns an event" do
818
+ expect(Sentry).to receive(:capture_exception).and_return(Object.new)
819
+ expect(ExceptionHandling.send_exception_to_sentry(
820
+ ExceptionHandling::ExceptionInfo.new(exception_1, "", Time.now)
821
+ )).to eq(:success)
822
+ end
823
+ end
824
+ end
825
+
693
826
  class EventResponse
694
827
  def to_s
695
828
  "message from to_s!"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exception_handling
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.2.0.pre.dc.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-08 00:00:00.000000000 Z
11
+ date: 2026-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -103,12 +103,13 @@ files:
103
103
  - LICENSE
104
104
  - README.md
105
105
  - Rakefile
106
+ - catalog-info.yaml
106
107
  - config/exception_filters.yml
107
108
  - exception_handling.gemspec
108
- - gemfiles/rails_6_0.gemfile
109
- - gemfiles/rails_6_1.gemfile
110
109
  - gemfiles/rails_7_0.gemfile
111
110
  - gemfiles/rails_7_1.gemfile
111
+ - gemfiles/rails_7_2.gemfile
112
+ - gemfiles/rails_8_0.gemfile
112
113
  - lib/exception_handling.rb
113
114
  - lib/exception_handling/escalate_callback.rb
114
115
  - lib/exception_handling/exception_catalog.rb
@@ -121,6 +122,7 @@ files:
121
122
  - spec/helpers/controller_helpers.rb
122
123
  - spec/helpers/exception_helpers.rb
123
124
  - spec/rake_test_warning_false.rb
125
+ - spec/simplecov_helper.rb
124
126
  - spec/spec_helper.rb
125
127
  - spec/unit/exception_handling/escalate_callback_spec.rb
126
128
  - spec/unit/exception_handling/exception_catalog_spec.rb
@@ -149,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  - !ruby/object:Gem::Version
150
152
  version: '0'
151
153
  requirements: []
152
- rubygems_version: 3.4.21
154
+ rubygems_version: 3.5.10
153
155
  signing_key:
154
156
  specification_version: 4
155
157
  summary: Invoca's exception handling logger layer, based on exception_notifier.
@@ -157,6 +159,7 @@ test_files:
157
159
  - spec/helpers/controller_helpers.rb
158
160
  - spec/helpers/exception_helpers.rb
159
161
  - spec/rake_test_warning_false.rb
162
+ - spec/simplecov_helper.rb
160
163
  - spec/spec_helper.rb
161
164
  - spec/unit/exception_handling/escalate_callback_spec.rb
162
165
  - spec/unit/exception_handling/exception_catalog_spec.rb
@@ -1,17 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activesupport", "~> 6.0.0"
6
- gem "appraisal", "~> 2.2"
7
- gem "gem-release"
8
- gem "honeybadger", "~> 4.11"
9
- gem "pry"
10
- gem "pry-byebug"
11
- gem "rake"
12
- gem "rspec"
13
- gem "rspec_junit_formatter"
14
- gem "rubocop"
15
- gem "test-unit"
16
-
17
- gemspec path: "../"
@@ -1,17 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activesupport", "~> 6.1.0"
6
- gem "appraisal", "~> 2.2"
7
- gem "gem-release"
8
- gem "honeybadger", "~> 4.11"
9
- gem "pry"
10
- gem "pry-byebug"
11
- gem "rake"
12
- gem "rspec"
13
- gem "rspec_junit_formatter"
14
- gem "rubocop"
15
- gem "test-unit"
16
-
17
- gemspec path: "../"