exception-track 0.6.2 → 1.3.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.
@@ -1,27 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExceptionNotifier
4
- class ExceptionTrackNotifier < ExceptionNotifier::BaseNotifier
5
- def initialize(_options); end
4
+ class DbNotifier < ExceptionNotifier::BaseNotifier
5
+ def initialize(opts = {})
6
+ super(opts)
7
+ end
6
8
 
7
- def call(exception, _options = {})
9
+ def call(exception, opts = {})
8
10
  return unless ExceptionTrack.config.enabled_env?(Rails.env)
9
11
 
10
12
  # send the notification
11
13
  title = exception.message || "None"
12
-
13
14
  messages = []
14
- messages << headers_for_env(_options[:env])
15
- messages << ""
16
- messages << "--------------------------------------------------"
17
- messages << ""
18
- messages << exception.inspect
19
- unless exception.backtrace.blank?
20
- messages << "\n"
21
- messages << exception.backtrace
22
- end
23
15
 
24
- ExceptionTrack::Log.create(title: title[0, 200], body: messages.join("\n"))
16
+ ActiveSupport::Notifications.instrument("track.exception_track", title: title) do
17
+ messages << headers_for_env(opts[:env])
18
+ messages << ""
19
+ messages << "--------------------------------------------------"
20
+ messages << ""
21
+ messages << exception.inspect
22
+ unless exception.backtrace.blank?
23
+ messages << "\n"
24
+ messages << exception.backtrace
25
+ end
26
+
27
+ Rails.logger.silence do
28
+ ExceptionTrack::Log.create(title: title[0, 200], body: messages.join("\n"))
29
+ end
30
+ end
25
31
  rescue => e
26
32
  errs = []
27
33
  errs << "-- [ExceptionTrack] create error ---------------------------"
@@ -41,16 +47,14 @@ module ExceptionNotifier
41
47
  parameters = filter_parameters(env)
42
48
 
43
49
  headers = []
44
- headers << "Method: #{env['REQUEST_METHOD']}"
45
- headers << "URL: #{env['REQUEST_URI']}"
46
- if env['REQUEST_METHOD'].downcase != "get"
47
- headers << "Parameters:\n#{pretty_hash(parameters.except(:controller, :action), 13)}"
48
- end
49
- headers << "Controller: #{parameters['controller']}##{parameters['action']}"
50
- headers << "RequestId: #{env['action_dispatch.request_id']}"
51
- headers << "User-Agent: #{env['HTTP_USER_AGENT']}"
52
- headers << "Remote IP: #{env['REMOTE_ADDR']}"
53
- headers << "Language: #{env['HTTP_ACCEPT_LANGUAGE']}"
50
+ headers << "Method: #{env["REQUEST_METHOD"]}"
51
+ headers << "URL: #{env["REQUEST_URI"]}"
52
+ headers << "Parameters:\n#{pretty_hash(parameters.except(:controller, :action), 13)}" if env["REQUEST_METHOD"].downcase != "get"
53
+ headers << "Controller: #{parameters["controller"]}##{parameters["action"]}"
54
+ headers << "RequestId: #{env["action_dispatch.request_id"]}"
55
+ headers << "User-Agent: #{env["HTTP_USER_AGENT"]}"
56
+ headers << "Remote IP: #{env["REMOTE_ADDR"]}"
57
+ headers << "Language: #{env["HTTP_ACCEPT_LANGUAGE"]}"
54
58
  headers << "Server: #{Socket.gethostname}"
55
59
  headers << "Process: #{$PROCESS_ID}"
56
60
 
@@ -60,10 +64,10 @@ module ExceptionNotifier
60
64
  def filter_parameters(env)
61
65
  parameters = env["action_dispatch.request.parameters"] || {}
62
66
  parameter_filter = ActiveSupport::ParameterFilter.new(env["action_dispatch.parameter_filter"] || [])
63
- return parameter_filter.filter(parameters)
67
+ parameter_filter.filter(parameters)
64
68
  rescue => e
65
69
  Rails.logger.error "filter_parameters error: #{e.inspect}"
66
- return parameters
70
+ parameters
67
71
  end
68
72
 
69
73
  def pretty_hash(params, indent = 0)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExceptionNotifier
4
+ module BacktraceCleaner
5
+ def clean_backtrace(exception)
6
+ if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
7
+ Rails.backtrace_cleaner.send(:filter, exception.backtrace)
8
+ else
9
+ exception.backtrace
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ if Rails.version > "7.0"
4
+ require "active_support/isolated_execution_state"
5
+ end
6
+ require "active_support/core_ext/numeric/time"
7
+ require "active_support/concern"
8
+
9
+ module ExceptionNotifier
10
+ module ErrorGrouping
11
+ extend ActiveSupport::Concern
12
+
13
+ included do
14
+ mattr_accessor :error_grouping
15
+ self.error_grouping = false
16
+
17
+ mattr_accessor :error_grouping_period
18
+ self.error_grouping_period = 5.minutes
19
+
20
+ mattr_accessor :notification_trigger
21
+
22
+ mattr_accessor :error_grouping_cache
23
+ end
24
+
25
+ module ClassMethods
26
+ # Fallback to the memory store while the specified cache store doesn't work
27
+ #
28
+ def fallback_cache_store
29
+ @fallback_cache_store ||= ActiveSupport::Cache::MemoryStore.new
30
+ end
31
+
32
+ def error_count(error_key)
33
+ count =
34
+ begin
35
+ error_grouping_cache.read(error_key)
36
+ rescue => e
37
+ log_cache_error(error_grouping_cache, e, :read)
38
+ fallback_cache_store.read(error_key)
39
+ end
40
+
41
+ count&.to_i
42
+ end
43
+
44
+ def save_error_count(error_key, count)
45
+ error_grouping_cache.write(error_key, count, expires_in: error_grouping_period)
46
+ rescue => e
47
+ log_cache_error(error_grouping_cache, e, :write)
48
+ fallback_cache_store.write(error_key, count, expires_in: error_grouping_period)
49
+ end
50
+
51
+ def group_error!(exception, options)
52
+ message_based_key = "exception:#{Zlib.crc32("#{exception.class.name}\nmessage:#{exception.message}")}"
53
+ accumulated_errors_count = 1
54
+
55
+ if (count = error_count(message_based_key))
56
+ accumulated_errors_count = count + 1
57
+ save_error_count(message_based_key, accumulated_errors_count)
58
+ else
59
+ backtrace_based_key =
60
+ "exception:#{Zlib.crc32("#{exception.class.name}\npath:#{exception.backtrace.try(:first)}")}"
61
+
62
+ if (count = error_grouping_cache.read(backtrace_based_key))
63
+ accumulated_errors_count = count + 1
64
+ save_error_count(backtrace_based_key, accumulated_errors_count)
65
+ else
66
+ save_error_count(backtrace_based_key, accumulated_errors_count)
67
+ save_error_count(message_based_key, accumulated_errors_count)
68
+ end
69
+ end
70
+
71
+ options[:accumulated_errors_count] = accumulated_errors_count
72
+ end
73
+
74
+ def send_notification?(exception, count)
75
+ if notification_trigger.respond_to?(:call)
76
+ notification_trigger.call(exception, count)
77
+ else
78
+ factor = Math.log2(count)
79
+ factor.to_i == factor
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def log_cache_error(cache, exception, action)
86
+ "#{cache.inspect} failed to #{action}, reason: #{exception.message}. Falling back to memory cache store."
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/time"
4
+ require "action_dispatch"
5
+
6
+ module ExceptionNotifier
7
+ class Formatter
8
+ include ExceptionNotifier::BacktraceCleaner
9
+
10
+ attr_reader :app_name
11
+
12
+ def initialize(exception, opts = {})
13
+ @exception = exception
14
+
15
+ @env = opts[:env]
16
+ @errors_count = opts[:accumulated_errors_count].to_i
17
+ @app_name = opts[:app_name] || rails_app_name
18
+ end
19
+
20
+ #
21
+ # :warning: Error occurred in production :warning:
22
+ # :warning: Error occurred :warning:
23
+ #
24
+ def title
25
+ env = Rails.env if defined?(::Rails) && ::Rails.respond_to?(:env)
26
+
27
+ if env
28
+ "⚠️ Error occurred in #{env} ⚠️"
29
+ else
30
+ "⚠️ Error occurred ⚠️"
31
+ end
32
+ end
33
+
34
+ #
35
+ # A *NoMethodError* occurred.
36
+ # 3 *NoMethodError* occurred.
37
+ # A *NoMethodError* occurred in *home#index*.
38
+ #
39
+ def subtitle
40
+ errors_text = if errors_count > 1
41
+ errors_count
42
+ else
43
+ /^[aeiou]/i.match?(exception.class.to_s) ? "An" : "A"
44
+ end
45
+
46
+ in_action = " in *#{controller_and_action}*" if controller
47
+
48
+ "#{errors_text} *#{exception.class}* occurred#{in_action}."
49
+ end
50
+
51
+ #
52
+ #
53
+ # *Request:*
54
+ # ```
55
+ # * url : https://www.example.com/
56
+ # * http_method : GET
57
+ # * ip_address : 127.0.0.1
58
+ # * parameters : {"controller"=>"home", "action"=>"index"}
59
+ # * timestamp : 2019-01-01 00:00:00 UTC
60
+ # ```
61
+ #
62
+ def request_message
63
+ request = ActionDispatch::Request.new(env) if env
64
+ return unless request
65
+
66
+ [
67
+ "```",
68
+ "* url : #{request.original_url}",
69
+ "* http_method : #{request.method}",
70
+ "* ip_address : #{request.remote_ip}",
71
+ "* parameters : #{request.filtered_parameters}",
72
+ "* timestamp : #{Time.current}",
73
+ "```"
74
+ ].join("\n")
75
+ end
76
+
77
+ #
78
+ #
79
+ # *Backtrace:*
80
+ # ```
81
+ # * app/controllers/my_controller.rb:99:in `specific_function'
82
+ # * app/controllers/my_controller.rb:70:in `specific_param'
83
+ # * app/controllers/my_controller.rb:53:in `my_controller_params'
84
+ # ```
85
+ #
86
+ def backtrace_message
87
+ backtrace = exception.backtrace ? clean_backtrace(exception) : nil
88
+
89
+ return unless backtrace
90
+
91
+ text = []
92
+
93
+ text << "```"
94
+ backtrace.first(3).each { |line| text << "* #{line}" }
95
+ text << "```"
96
+
97
+ text.join("\n")
98
+ end
99
+
100
+ #
101
+ # home#index
102
+ #
103
+ def controller_and_action
104
+ "#{controller.controller_name}##{controller.action_name}" if controller
105
+ end
106
+
107
+ private
108
+
109
+ attr_reader :exception, :env, :errors_count
110
+
111
+ def rails_app_name
112
+ return unless defined?(::Rails) && ::Rails.respond_to?(:application)
113
+
114
+ if Rails::VERSION::MAJOR >= 6
115
+ Rails.application.class.module_parent_name.underscore
116
+ else
117
+ Rails.application.class.parent_name.underscore
118
+ end
119
+ end
120
+
121
+ def controller
122
+ env["action_controller.instance"] if env
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+ require "active_support/core_ext/string/inflections"
5
+ require "active_support/core_ext/module/attribute_accessors"
6
+ require "exception_notifier/base_notifier"
7
+ require "exception_notifier/modules/error_grouping"
8
+
9
+ module ExceptionNotifier
10
+ include ErrorGrouping
11
+
12
+ autoload :BacktraceCleaner, "exception_notifier/modules/backtrace_cleaner"
13
+ autoload :Formatter, "exception_notifier/modules/formatter"
14
+
15
+ autoload :Notifier, "exception_notifier/notifier"
16
+ autoload :DbNotifier, "exception_notifier/db_notifier"
17
+
18
+ class UndefinedNotifierError < StandardError; end
19
+
20
+ # Define logger
21
+ mattr_accessor :logger
22
+ @@logger = Logger.new($stdout)
23
+
24
+ # Define a set of exceptions to be ignored, ie, dont send notifications when any of them are raised.
25
+ mattr_accessor :ignored_exceptions
26
+ @@ignored_exceptions = %w[
27
+ AbstractController::ActionNotFound
28
+ ActionController::BadRequest
29
+ ActionController::InvalidAuthenticityToken
30
+ ActionController::InvalidCrossOriginRequest
31
+ ActionController::ParameterMissing
32
+ ActionController::RoutingError
33
+ ActionController::UnknownFormat
34
+ ActionController::UrlGenerationError
35
+ ActionView::MissingTemplate
36
+ ActionView::TemplateError
37
+ ActiveRecord::RecordNotFound
38
+ Mime::Type::InvalidMimeType
39
+ Mongoid::Errors::DocumentNotFound
40
+ ]
41
+
42
+ mattr_accessor :testing_mode
43
+ @@testing_mode = false
44
+
45
+ class << self
46
+ # Store conditions that decide when exceptions must be ignored or not.
47
+ @@ignores = []
48
+
49
+ # Store by-notifier conditions that decide when exceptions must be ignored or not.
50
+ @@by_notifier_ignores = {}
51
+
52
+ # Store notifiers that send notifications when exceptions are raised.
53
+ @@notifiers = {}
54
+
55
+ def testing_mode!
56
+ self.testing_mode = true
57
+ end
58
+
59
+ def notify_exception(exception, options = {}, &block)
60
+ return false if ignored_exception?(options[:ignore_exceptions], exception)
61
+ return false if ignored?(exception, options)
62
+
63
+ if error_grouping
64
+ errors_count = group_error!(exception, options)
65
+ return false unless send_notification?(exception, errors_count)
66
+ end
67
+
68
+ notification_fired = false
69
+ selected_notifiers = options.delete(:notifiers) || notifiers
70
+ [*selected_notifiers].each do |notifier|
71
+ unless notifier_ignored?(exception, options, notifier: notifier)
72
+ fire_notification(notifier, exception, options.dup, &block)
73
+ notification_fired = true
74
+ end
75
+ end
76
+
77
+ notification_fired
78
+ end
79
+
80
+ def register_exception_notifier(name, notifier_or_options)
81
+ if notifier_or_options.respond_to?(:call)
82
+ @@notifiers[name] = notifier_or_options
83
+ elsif notifier_or_options.is_a?(Hash)
84
+ create_and_register_notifier(name, notifier_or_options)
85
+ else
86
+ raise ArgumentError, "Invalid notifier '#{name}' defined as #{notifier_or_options.inspect}"
87
+ end
88
+ end
89
+ alias_method :add_notifier, :register_exception_notifier
90
+
91
+ def unregister_exception_notifier(name)
92
+ @@notifiers.delete(name)
93
+ end
94
+
95
+ def registered_exception_notifier(name)
96
+ @@notifiers[name]
97
+ end
98
+
99
+ def notifiers
100
+ @@notifiers.keys
101
+ end
102
+
103
+ # Adds a condition to decide when an exception must be ignored or not.
104
+ #
105
+ # ExceptionNotifier.ignore_if do |exception, options|
106
+ # not Rails.env.production?
107
+ # end
108
+ def ignore_if(&block)
109
+ @@ignores << block
110
+ end
111
+
112
+ def ignore_notifier_if(notifier, &block)
113
+ @@by_notifier_ignores[notifier] = block
114
+ end
115
+
116
+ def ignore_crawlers(crawlers)
117
+ ignore_if do |_exception, opts|
118
+ opts.key?(:env) && from_crawler(opts[:env], crawlers)
119
+ end
120
+ end
121
+
122
+ def clear_ignore_conditions!
123
+ @@ignores.clear
124
+ @@by_notifier_ignores.clear
125
+ end
126
+
127
+ private
128
+
129
+ def ignored?(exception, options)
130
+ @@ignores.any? { |condition| condition.call(exception, options) }
131
+ rescue Exception => e
132
+ raise e if @@testing_mode
133
+
134
+ logger.warn(
135
+ "An error occurred when evaluating an ignore condition. #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
136
+ )
137
+ false
138
+ end
139
+
140
+ def notifier_ignored?(exception, options, notifier:)
141
+ return false unless @@by_notifier_ignores.key?(notifier)
142
+
143
+ condition = @@by_notifier_ignores[notifier]
144
+ condition.call(exception, options)
145
+ rescue Exception => e
146
+ raise e if @@testing_mode
147
+
148
+ logger.warn(<<~"MESSAGE")
149
+ An error occurred when evaluating a by-notifier ignore condition. #{e.class}: #{e.message}
150
+ #{e.backtrace.join("\n")}
151
+ MESSAGE
152
+ false
153
+ end
154
+
155
+ def ignored_exception?(ignore_array, exception)
156
+ all_ignored_exceptions = (Array(ignored_exceptions) + Array(ignore_array)).map(&:to_s)
157
+ exception_ancestors = exception.singleton_class.ancestors.map(&:to_s)
158
+ !(all_ignored_exceptions & exception_ancestors).empty?
159
+ end
160
+
161
+ def fire_notification(notifier_name, exception, options, &block)
162
+ notifier = registered_exception_notifier(notifier_name)
163
+ notifier.call(exception, options, &block)
164
+ rescue Exception => e
165
+ raise e if @@testing_mode
166
+
167
+ logger.warn(
168
+ "An error occurred when sending a notification using '#{notifier_name}' notifier." \
169
+ "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
170
+ )
171
+ false
172
+ end
173
+
174
+ def create_and_register_notifier(name, options)
175
+ notifier_classname = "#{name}_notifier".camelize
176
+ notifier_class = ExceptionNotifier.const_get(notifier_classname)
177
+ notifier = notifier_class.new(options)
178
+ register_exception_notifier(name, notifier)
179
+ rescue NameError => e
180
+ raise UndefinedNotifierError,
181
+ "No notifier named '#{name}' was found. Please, revise your configuration options. Cause: #{e.message}"
182
+ end
183
+
184
+ def from_crawler(env, ignored_crawlers)
185
+ agent = env["HTTP_USER_AGENT"]
186
+ Array(ignored_crawlers).any? do |crawler|
187
+ agent =~ Regexp.new(crawler)
188
+ end
189
+ end
190
+ end
191
+ end
metadata CHANGED
@@ -1,71 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exception-track
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-21 00:00:00.000000000 Z
11
+ date: 2021-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: exception_notification
14
+ name: kaminari
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4'
19
+ version: '0.15'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4'
26
+ version: '0.15'
27
27
  - !ruby/object:Gem::Dependency
28
- name: kaminari
28
+ name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0.15'
33
+ version: '5.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0.15'
40
+ version: '5.2'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rails
42
+ name: pg
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '4.0'
48
- type: :runtime
47
+ version: '1'
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '4.0'
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.13.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.13.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: mock_redis
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.19.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.19.0
55
83
  - !ruby/object:Gem::Dependency
56
- name: mysql2
84
+ name: resque
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: sidekiq
57
99
  requirement: !ruby/object:Gem::Requirement
58
100
  requirements:
59
101
  - - ">="
60
102
  - !ruby/object:Gem::Version
61
- version: '0'
103
+ version: 5.0.4
62
104
  type: :development
63
105
  prerelease: false
64
106
  version_requirements: !ruby/object:Gem::Requirement
65
107
  requirements:
66
108
  - - ">="
67
109
  - !ruby/object:Gem::Version
68
- version: '0'
110
+ version: 5.0.4
111
+ - !ruby/object:Gem::Dependency
112
+ name: timecop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.9.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.9.0
69
125
  description: Tracking exceptions for Rails application store them in database by exception_notification
70
126
  gem.
71
127
  email:
@@ -76,6 +132,7 @@ extra_rdoc_files: []
76
132
  files:
77
133
  - MIT-LICENSE
78
134
  - README.md
135
+ - app/assets/config/exception_track_manifest.js
79
136
  - app/assets/stylesheets/exception-track/application.css
80
137
  - app/controllers/exception_track/logs_controller.rb
81
138
  - app/models/exception_track/log.rb
@@ -88,14 +145,26 @@ files:
88
145
  - lib/exception-track.rb
89
146
  - lib/exception-track/configuration.rb
90
147
  - lib/exception-track/engine.rb
148
+ - lib/exception-track/log_subscriber.rb
91
149
  - lib/exception-track/version.rb
92
- - lib/exception_notifier/exception_track_notifier.rb
150
+ - lib/exception_notification.rb
151
+ - lib/exception_notification/rack.rb
152
+ - lib/exception_notification/rails.rb
153
+ - lib/exception_notification/resque.rb
154
+ - lib/exception_notification/sidekiq.rb
155
+ - lib/exception_notification/version.rb
156
+ - lib/exception_notifier/base_notifier.rb
157
+ - lib/exception_notifier/db_notifier.rb
158
+ - lib/exception_notifier/modules/backtrace_cleaner.rb
159
+ - lib/exception_notifier/modules/error_grouping.rb
160
+ - lib/exception_notifier/modules/formatter.rb
161
+ - lib/exception_notifier/notifier.rb
93
162
  - lib/generators/exception_track/install_generator.rb
94
163
  homepage: https://github.com/rails-engine/exception-track
95
164
  licenses:
96
165
  - MIT
97
166
  metadata: {}
98
- post_install_message:
167
+ post_install_message:
99
168
  rdoc_options: []
100
169
  require_paths:
101
170
  - lib
@@ -110,8 +179,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
179
  - !ruby/object:Gem::Version
111
180
  version: '0'
112
181
  requirements: []
113
- rubygems_version: 3.0.3
114
- signing_key:
182
+ rubygems_version: 3.2.3
183
+ signing_key:
115
184
  specification_version: 4
116
185
  summary: Tracking exceptions for Rails application store them in database.
117
186
  test_files: []