dislogger 0.1.8 → 0.2.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: 0b7ddd219546d4b47916d9e0cfd1303679ed1a3f4befa6675a7be486ada7de25
4
- data.tar.gz: '001685aeefc4f82fd7a07f8a539ea9c737de5a1760eebdc0799660ea62c4087d'
3
+ metadata.gz: 40772178fe1446aaa2cc9bafcb10f11815e3416ad6a7b294dfbd69e9c153c338
4
+ data.tar.gz: e6e2d4e174ae770eff2b0be41cd9364a6f81606b393061379b168a23eb60fbf8
5
5
  SHA512:
6
- metadata.gz: 40495b36577cce4bb00ea8ab38b74019b4792e2ca6452c1edd735f4042557403ab382bb70b08f94e4fb952b7e5240c1828057a5068f76aad4c1da5ba6be1fc41
7
- data.tar.gz: 2d90483f3e1db1969355be2565384cde9f38f7048e5dd4f7573203a47bb814f3ba45bf11554bf9e0dd71c4751e0d7fcece7d547664afa8f2959bc98fbdba0eb9
6
+ metadata.gz: 8bd268340561e183ef3668cee56ea2ca964d4c2a9b70571a7d2a9b683e57199be8444191284ff1a358167002acccefd57d7abe607594c2adbcf08703c9afa484
7
+ data.tar.gz: bbfbeed87f691bfa3d1f7049a5873d16f938fbd5b019dc71f04eb4024e1be59fb3fe5b65e77de547560df35fb2adeb63f1fbe14934f0679172c0aa0b03a69497
@@ -13,7 +13,7 @@ module Dislogger
13
13
  @discord_webhook_url = nil
14
14
  @bot_username = 'Error Logger'
15
15
  @backtrace_lines_limit = 5
16
- @enabled_environments = %w[production staging development]
16
+ @enabled_environments = %w[production staging]
17
17
  @environment = nil
18
18
  @error_color_map = {
19
19
  500 => 15158332, # Red for server errors
@@ -7,16 +7,116 @@ module Dislogger
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- rescue_from StandardError, with: :handle_internal_server_error
11
- rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
12
- rescue_from ActiveRecord::RecordInvalid, with: :handle_unprocessable_entity
13
- rescue_from ActionController::ParameterMissing, with: :handle_unprocessable_entity
14
- rescue_from Pundit::NotAuthorizedError, with: :handle_forbidden if defined?(Pundit)
15
- rescue_from CanCan::AccessDenied, with: :handle_forbidden if defined?(CanCan)
10
+ if ancestors.include?(ActionController::API) || ancestors.include?(ActionController::Base)
11
+ # System and Runtime Errors
12
+ rescue_from Exception, with: :handle_exception
13
+ rescue_from StandardError, with: :handle_internal_server_error
14
+ rescue_from RuntimeError, with: :handle_runtime_error
15
+ rescue_from SystemStackError, with: :handle_stack_error
16
+ rescue_from NoMemoryError, with: :handle_memory_error
17
+ rescue_from SystemCallError, with: :handle_system_error
18
+ rescue_from SignalException, with: :handle_signal_error
19
+ rescue_from ScriptError, with: :handle_script_error
20
+
21
+ # Database Errors
22
+ rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
23
+ rescue_from ActiveRecord::RecordInvalid, with: :handle_unprocessable_entity
24
+ rescue_from ActiveRecord::RecordNotUnique, with: :handle_conflict
25
+ rescue_from ActiveRecord::ConnectionTimeoutError, with: :handle_timeout
26
+ rescue_from ActiveRecord::InvalidForeignKey, with: :handle_foreign_key_error
27
+ rescue_from ActiveRecord::ReadOnlyRecord, with: :handle_forbidden
28
+ rescue_from ActiveRecord::StaleObjectError, with: :handle_conflict
29
+
30
+ # Controller and Routing Errors
31
+ rescue_from ActionController::ParameterMissing, with: :handle_unprocessable_entity
32
+ rescue_from ActionController::InvalidAuthenticityToken, with: :handle_unauthorized
33
+ rescue_from ActionController::UnknownFormat, with: :handle_not_acceptable
34
+ rescue_from ActionController::UrlGenerationError, with: :handle_bad_request
35
+ rescue_from ActionController::RoutingError, with: :handle_not_found
36
+ rescue_from AbstractController::ActionNotFound, with: :handle_not_found
37
+
38
+ # Authorization Errors
39
+ rescue_from Pundit::NotAuthorizedError, with: :handle_forbidden if defined?(Pundit)
40
+ rescue_from CanCan::AccessDenied, with: :handle_forbidden if defined?(CanCan)
41
+
42
+ # Common Ruby Errors
43
+ rescue_from NameError, with: :handle_internal_server_error
44
+ rescue_from NoMethodError, with: :handle_internal_server_error
45
+ rescue_from ArgumentError, with: :handle_bad_request
46
+ rescue_from TypeError, with: :handle_internal_server_error
47
+ rescue_from LoadError, with: :handle_internal_server_error
48
+ rescue_from SyntaxError, with: :handle_internal_server_error
49
+ rescue_from Timeout::Error, with: :handle_timeout
50
+ end
16
51
  end
17
52
 
18
53
  private
19
54
 
55
+ def handle_exception(exception)
56
+ # Log detailed error information
57
+ Rails.logger.error("[Dislogger] Unexpected error caught: #{exception.class.name}")
58
+ Rails.logger.error("[Dislogger] Message: #{exception.message}")
59
+ Rails.logger.error("[Dislogger] Backtrace:\n#{exception.backtrace.join("\n")}") if exception.backtrace
60
+
61
+ notify_and_render_error(
62
+ message: "An unexpected error occurred: #{exception.class.name} - #{exception.message}",
63
+ status: :internal_server_error,
64
+ backtrace: exception.backtrace,
65
+ details: {
66
+ error_class: exception.class.name,
67
+ message: exception.message
68
+ }
69
+ )
70
+ end
71
+
72
+ def handle_runtime_error(exception)
73
+ notify_and_render_error(
74
+ message: "Runtime error: #{exception.message}",
75
+ status: :internal_server_error,
76
+ backtrace: exception.backtrace
77
+ )
78
+ end
79
+
80
+ def handle_stack_error(exception)
81
+ notify_and_render_error(
82
+ message: "Stack overflow error: #{exception.message}",
83
+ status: :internal_server_error,
84
+ backtrace: exception.backtrace
85
+ )
86
+ end
87
+
88
+ def handle_memory_error(exception)
89
+ notify_and_render_error(
90
+ message: "Out of memory error: #{exception.message}",
91
+ status: :internal_server_error,
92
+ backtrace: exception.backtrace
93
+ )
94
+ end
95
+
96
+ def handle_system_error(exception)
97
+ notify_and_render_error(
98
+ message: "System error: #{exception.message}",
99
+ status: :internal_server_error,
100
+ backtrace: exception.backtrace
101
+ )
102
+ end
103
+
104
+ def handle_signal_error(exception)
105
+ notify_and_render_error(
106
+ message: "Signal error: #{exception.message}",
107
+ status: :internal_server_error,
108
+ backtrace: exception.backtrace
109
+ )
110
+ end
111
+
112
+ def handle_script_error(exception)
113
+ notify_and_render_error(
114
+ message: "Script error: #{exception.message}",
115
+ status: :internal_server_error,
116
+ backtrace: exception.backtrace
117
+ )
118
+ end
119
+
20
120
  def handle_not_found(exception)
21
121
  notify_and_render_error(
22
122
  message: exception.message.presence || 'Resource not found',
@@ -25,7 +125,14 @@ module Dislogger
25
125
  end
26
126
 
27
127
  def handle_unprocessable_entity(exception)
28
- errors = exception.respond_to?(:record) ? exception.record.errors.full_messages : [exception.message]
128
+ errors = if exception.respond_to?(:record)
129
+ exception.record.errors.full_messages
130
+ elsif exception.respond_to?(:errors)
131
+ exception.errors
132
+ else
133
+ [exception.message]
134
+ end
135
+
29
136
  notify_and_render_error(
30
137
  message: 'Validation failed',
31
138
  status: :unprocessable_entity,
@@ -33,16 +140,59 @@ module Dislogger
33
140
  )
34
141
  end
35
142
 
143
+ def handle_conflict(exception)
144
+ notify_and_render_error(
145
+ message: exception.message || 'Resource conflict',
146
+ status: :conflict
147
+ )
148
+ end
149
+
150
+ def handle_timeout(exception)
151
+ notify_and_render_error(
152
+ message: exception.message || 'Request timeout',
153
+ status: :request_timeout
154
+ )
155
+ end
156
+
157
+ def handle_foreign_key_error(exception)
158
+ notify_and_render_error(
159
+ message: 'Cannot delete or update due to database constraint',
160
+ status: :unprocessable_entity,
161
+ details: [exception.message]
162
+ )
163
+ end
164
+
165
+ def handle_unauthorized(exception)
166
+ notify_and_render_error(
167
+ message: exception.message || 'Unauthorized access',
168
+ status: :unauthorized
169
+ )
170
+ end
171
+
36
172
  def handle_forbidden(exception)
37
173
  notify_and_render_error(
38
- message: exception.message.presence || 'You are not authorized to perform this action',
174
+ message: exception.message.presence || 'Access forbidden',
39
175
  status: :forbidden
40
176
  )
41
177
  end
42
178
 
179
+ def handle_not_acceptable(exception)
180
+ notify_and_render_error(
181
+ message: exception.message || 'Not acceptable',
182
+ status: :not_acceptable
183
+ )
184
+ end
185
+
186
+ def handle_bad_request(exception)
187
+ notify_and_render_error(
188
+ message: exception.message || 'Bad request',
189
+ status: :bad_request
190
+ )
191
+ end
192
+
43
193
  def handle_internal_server_error(exception)
44
194
  notify_and_render_error(
45
- message: 'Internal Server Error',
195
+ message: exception.message || 'Internal server error',
46
196
  status: :internal_server_error,
47
197
  backtrace: exception.backtrace
48
198
  )
@@ -51,23 +201,42 @@ module Dislogger
51
201
  def notify_and_render_error(message:, status:, details: nil, backtrace: nil)
52
202
  status_code = Rack::Utils::SYMBOL_TO_STATUS_CODE[status]
53
203
 
54
- Notifiers::DiscordNotifier.new.notify(
204
+ notifier = Notifiers::DiscordNotifier.new
205
+ notification_result = notifier.notify(
55
206
  message: message,
56
207
  status: status_code,
57
208
  backtrace: backtrace
58
209
  )
59
210
 
60
- render_error(message, status, details)
211
+ Rails.logger.info("[Dislogger] Notification result: #{notification_result}") if defined?(Rails)
212
+
213
+ render_error(message, status, error_details)
61
214
  end
62
215
 
63
216
  def render_error(message, status, details = nil)
64
217
  error_response = {
65
218
  status: status,
66
- message: message
219
+ message: message,
220
+ timestamp: Time.current.utc.iso8601
67
221
  }
68
222
  error_response[:details] = details if details
69
223
 
70
224
  render json: error_response, status: status
71
225
  end
226
+
227
+ private
228
+
229
+ def filter_sensitive_params(params_hash)
230
+ # List of sensitive parameters we don't want to show
231
+ sensitive_params = %w[password password_confirmation token api_key secret]
232
+
233
+ params_hash.deep_transform_values do |value|
234
+ if sensitive_params.any? { |param| value.to_s.include?(param) }
235
+ '[FILTERED]'
236
+ else
237
+ value
238
+ end
239
+ end
240
+ end
72
241
  end
73
242
  end
@@ -4,22 +4,21 @@ module Dislogger
4
4
  module Notifiers
5
5
  class DiscordNotifier < BaseNotifier
6
6
  def notify(message:, status:, backtrace: nil)
7
- return unless enabled? && @config.discord_webhook_url.present?
7
+ return false unless enabled? && @config.discord_webhook_url.present?
8
8
 
9
+ log_info("Attempting to send Discord notification")
9
10
  formatted_message = format_message(message, status, backtrace)
10
11
  send_notification(formatted_message)
11
12
  rescue StandardError => e
12
- if defined?(Rails) && Rails.logger
13
- Rails.logger.error("Discord notification failed: #{e.message}")
14
- else
15
- warn("Discord notification failed: #{e.message}")
16
- end
13
+ log_error("Discord notification failed: #{e.message}")
14
+ log_error(e.backtrace.join("\n")) if e.backtrace
17
15
  false
18
16
  end
19
17
 
20
18
  protected
21
19
 
22
20
  def format_message(message, status, backtrace)
21
+ log_info("Formatting Discord message")
23
22
  Formatters::DiscordFormatter.new(
24
23
  message: message,
25
24
  status: status,
@@ -29,6 +28,7 @@ module Dislogger
29
28
  end
30
29
 
31
30
  def send_notification(payload)
31
+ log_info("Sending notification to Discord")
32
32
  response = HTTParty.post(
33
33
  @config.discord_webhook_url,
34
34
  body: payload.to_json,
@@ -37,19 +37,40 @@ module Dislogger
37
37
 
38
38
  unless response.success?
39
39
  error_message = "Discord API Error: #{response.code} - #{response.body}"
40
- if defined?(Rails) && Rails.logger
41
- Rails.logger.error(error_message)
42
- else
43
- warn(error_message)
44
- end
40
+ log_error(error_message)
45
41
  return false
46
42
  end
47
43
 
44
+ log_info("Discord notification sent successfully")
48
45
  true
46
+ rescue StandardError => e
47
+ log_error("Failed to send Discord notification: #{e.message}")
48
+ log_error(e.backtrace.join("\n")) if e.backtrace
49
+ false
49
50
  end
50
51
 
51
52
  def enabled?
52
- @config.enabled?
53
+ result = @config.enabled?
54
+ log_info("Dislogger enabled? #{result} (environment: #{@config.environment}, enabled_environments: #{@config.enabled_environments})")
55
+ result
56
+ end
57
+
58
+ private
59
+
60
+ def log_info(message)
61
+ if defined?(Rails) && Rails.logger
62
+ Rails.logger.info("[Dislogger] #{message}")
63
+ else
64
+ puts "[Dislogger] #{message}"
65
+ end
66
+ end
67
+
68
+ def log_error(message)
69
+ if defined?(Rails) && Rails.logger
70
+ Rails.logger.error("[Dislogger] #{message}")
71
+ else
72
+ warn "[Dislogger] #{message}"
73
+ end
53
74
  end
54
75
  end
55
76
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dislogger
4
- VERSION = "0.1.8"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dislogger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nelson