activerabbit-ai 0.4.2 → 0.4.5

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: 48326a10836bf940aea7ebf3b6eca91f60086eb69e51e5e94266db5012d47ad9
4
- data.tar.gz: 9244e314ba69d85fd9652604014520f8cbc6a4ab2c6da046b28a7f9c540a402e
3
+ metadata.gz: e2afb9bf892d3e3a7e83a65e224c791855aa7d6e86feb476ee0f66c108f617cd
4
+ data.tar.gz: 20e74e7fa56e865bd707ccd852e62894fa73fc1d5ac2145d7d6a606dff351722
5
5
  SHA512:
6
- metadata.gz: 866f2f2f296c7a254526691e02e6c182aade30274985de6ca69f8e715b9af4036b489437eb2742840bf9fe1a582a0eaafae3ad0605342da4acde3dc6ee4d752a
7
- data.tar.gz: f59a2b3dcfd170f048f96751f870cc238333fc576fbf200668ef040db9a88b97de8b1a0f60cf8c6490c3ee3f8c4ee1941318571d39d644921e0f04e2a2ae29c8
6
+ metadata.gz: 40e742a6578a155441efe51fd97de272e8bfc7fe2e024cc2abe17e29ac2ee664079c6eb3093ae0aa311dea8f5438c96b60d88ba0a50e2477fdc2cc01b7b32006
7
+ data.tar.gz: 55fe08ec494af877576561418a7d3c9b63fd0b0bd34d3c04c3e59d5cb39d3d032992369ac056dc6e2417e75bad363fb5ac1dce115d3150765be7870b7859c34b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.4.4] - 2025-10-22
6
+
7
+ ### Improved
8
+ - **Time-based error deduplication**: Changed from "once per server lifecycle" to time-window based
9
+ - Added `dedupe_window` configuration option (default: 300 seconds / 5 minutes)
10
+ - Set `dedupe_window` to `0` to disable deduplication (useful for development/testing)
11
+ - Automatic memory cleanup of old dedupe entries (keeps last hour only)
12
+ - Better logging when errors are deduplicated
13
+
14
+ ### Fixed
15
+ - Error deduplication no longer prevents same error from being reported after time window expires
16
+ - Memory leak prevention by cleaning old deduplication entries
17
+
18
+ ## [0.4.3] - 2025-10-22
19
+
20
+ ### Fixed
21
+ - **Critical bug fix**: Removed reference to non-existent `ActiveRabbit::Client::Dedupe` class in error reporter
22
+ - Error tracking now works properly via Rails error reporter integration
23
+ - Errors are successfully captured and sent to ActiveRabbit API
24
+
5
25
  ## [0.4.2] - 2025-01-04
6
26
 
7
27
  ### Fixed
data/README.md CHANGED
@@ -236,6 +236,65 @@ ActiveRabbit::Client.configure do |config|
236
236
  end
237
237
  ```
238
238
 
239
+ ### Recommended Exceptions to Capture
240
+
241
+ Below is a practical list of exceptions APMs should capture by default in a Rails app. Some are optional/noisy and typically excluded unless needed.
242
+
243
+ - Core (Ruby/Stdlib)
244
+ - `StandardError`, `RuntimeError`, `NoMethodError`, `NameError`, `ArgumentError`, `TypeError`, `IndexError`, `KeyError`
245
+ - `Timeout::Error`, `JSON::ParserError`, `OpenSSL::SSL::SSLError`, `SocketError`, `Errno::ECONNREFUSED`/`ETIMEDOUT`/`EHOSTUNREACH`
246
+
247
+ - ActionPack / Controllers
248
+ - `ActionController::ParameterMissing`
249
+ - `ActionController::BadRequest`
250
+ - `ActionController::InvalidAuthenticityToken` (optional; can be noisy)
251
+ - `ActionController::UnknownFormat`
252
+ - `ActionController::NotImplemented`
253
+
254
+ - Routing (optional/noisy)
255
+ - `ActionController::RoutingError` (commonly excluded; enable only if needed)
256
+
257
+ - Views / Templates
258
+ - `ActionView::Template::Error`
259
+ - `ActionView::MissingTemplate`
260
+ - `Encoding::UndefinedConversionError` (template rendering)
261
+
262
+ - ActiveRecord / Database
263
+ - `ActiveRecord::RecordInvalid`
264
+ - `ActiveRecord::RecordNotFound` (optional; may be expected business logic)
265
+ - `ActiveRecord::StatementInvalid` (includes `PG::Error` subclasses)
266
+ - `ActiveRecord::Deadlocked`, `ActiveRecord::LockWaitTimeout`
267
+ - `ActiveRecord::RecordNotUnique`
268
+ - `ActiveRecord::ConnectionTimeoutError`
269
+ - `ActiveRecord::SerializationFailure`
270
+
271
+ - Background Jobs (ActiveJob/Sidekiq)
272
+ - `ActiveJob::DeserializationError`
273
+ - Any unhandled exception raised in job `perform`
274
+
275
+ - Networking/HTTP Clients
276
+ - `Net::OpenTimeout`, `Net::ReadTimeout`
277
+ - `Faraday::TimeoutError`, `Faraday::ConnectionFailed`
278
+ - `HTTP::Error` (http.rb), `RestClient::Exception`
279
+
280
+ - Caching/Redis
281
+ - `Redis::BaseError`, `Redis::TimeoutError`, `Redis::CannotConnectError`
282
+
283
+ - ActiveStorage
284
+ - `ActiveStorage::IntegrityError`
285
+ - `ActiveStorage::FileNotFoundError`
286
+
287
+ - ActionCable
288
+ - `ActionCable::Connection::Authorization::UnauthorizedError` (if applicable)
289
+
290
+ - Security/Crypto
291
+ - `ActiveSupport::MessageEncryptor::InvalidMessage`
292
+ - `ActiveSupport::MessageVerifier::InvalidSignature`
293
+
294
+ Notes:
295
+ - Optional/noisy: `RoutingError`, `RecordNotFound`, `InvalidAuthenticityToken`. Consider monitoring via metrics or targeted capture.
296
+ - If exceptions are rescued by your app, enable reporting of rescued exceptions (`before_send_exception`/custom middleware) so they are still tracked when appropriate.
297
+
239
298
  ### Callbacks
240
299
 
241
300
  ```ruby
@@ -14,6 +14,7 @@ module ActiveRabbit
14
14
  attr_accessor :ignored_exceptions, :ignored_user_agents, :ignore_404
15
15
  attr_accessor :release, :server_name, :logger
16
16
  attr_accessor :before_send_event, :before_send_exception
17
+ attr_accessor :dedupe_window # Time window in seconds for error deduplication (0 = disabled)
17
18
 
18
19
  def initialize
19
20
  @api_url = ENV.fetch("active_rabbit_API_URL", "https://api.activerabbit.ai")
@@ -60,6 +61,9 @@ module ActiveRabbit
60
61
  /Twitterbot/i
61
62
  ]
62
63
 
64
+ # Deduplication (0 = disabled, time in seconds for same error to be considered duplicate)
65
+ @dedupe_window = 300 # 5 minutes by default
66
+
63
67
  # Metadata
64
68
  @release = detect_release
65
69
  @server_name = detect_server_name
@@ -10,21 +10,32 @@ module ActiveRabbit
10
10
  begin
11
11
  Rails.logger.info "[ActiveRabbit] Error reporter caught: #{exception.class}: #{exception.message}" if defined?(Rails.logger)
12
12
 
13
- # Initialize de-dup set
14
- $reported_errors ||= Set.new
13
+ # Time-based deduplication: track errors with timestamps
14
+ $reported_errors ||= {}
15
15
 
16
16
  # Generate a unique key for this error
17
17
  error_key = "#{exception.class.name}:#{exception.message}:#{exception.backtrace&.first}"
18
18
 
19
- # Only report if we haven't seen this error before and not deduped in short window
20
- unless $reported_errors.include?(error_key)
21
- $reported_errors.add(error_key)
19
+ # Get dedupe window from config (default 5 minutes, 0 = disabled)
20
+ dedupe_window = defined?(ActiveRabbit::Client.configuration.dedupe_window) ?
21
+ ActiveRabbit::Client.configuration.dedupe_window : 300
22
22
 
23
- dedupe_context = { request_id: (context && (context[:request_id] || context[:request]&.[](:request_id))) }
24
- unless ActiveRabbit::Client::Dedupe.seen_recently?(exception, dedupe_context)
25
- enriched = build_enriched_context(exception, handled: handled, severity: severity, context: context)
26
- ActiveRabbit::Client.track_exception(exception, handled: handled, context: enriched)
27
- end
23
+ current_time = Time.now.to_i
24
+ last_seen = $reported_errors[error_key]
25
+
26
+ # Report if: never seen before, OR dedupe disabled (0), OR outside dedupe window
27
+ should_report = last_seen.nil? || dedupe_window == 0 || (current_time - last_seen) > dedupe_window
28
+
29
+ if should_report
30
+ $reported_errors[error_key] = current_time
31
+
32
+ # Clean old entries to prevent memory leak (keep last hour)
33
+ $reported_errors.delete_if { |_, timestamp| current_time - timestamp > 3600 }
34
+
35
+ enriched = build_enriched_context(exception, handled: handled, severity: severity, context: context)
36
+ ActiveRabbit::Client.track_exception(exception, handled: handled, context: enriched)
37
+ else
38
+ Rails.logger.debug "[ActiveRabbit] Error deduplicated (last seen #{current_time - last_seen}s ago)" if defined?(Rails.logger)
28
39
  end
29
40
  rescue => e
30
41
  Rails.logger.error "[ActiveRabbit] Error in ErrorReporter::Subscriber#report: #{e.class} - #{e.message}" if defined?(Rails.logger)
@@ -46,15 +46,18 @@ module ActiveRabbit
46
46
  setup_exception_tracking(app) if ActiveRabbit::Client.configured?
47
47
  end
48
48
 
49
- initializer "active_rabbit.subscribe_to_notifications" do |app|
50
- # Defer subscription until after application initializers (configuration complete)
49
+ initializer "active_rabbit.subscribe_to_notifications", after: :load_config_initializers do |app|
50
+ Rails.logger.info "[ActiveRabbit] Setting up performance notifications subscriptions"
51
+ # Subscribe regardless; each handler guards on configured?
52
+ subscribe_to_controller_events
53
+ subscribe_to_active_record_events
54
+ subscribe_to_action_view_events
55
+ subscribe_to_action_mailer_events if defined?(ActionMailer)
56
+ subscribe_to_exception_notifications
57
+ Rails.logger.info "[ActiveRabbit] Subscriptions setup complete"
58
+
59
+ # Defer complex subscriptions until after initialization
51
60
  app.config.after_initialize do
52
- # Subscribe regardless; each handler guards on configured?
53
- subscribe_to_controller_events
54
- subscribe_to_active_record_events
55
- subscribe_to_action_view_events
56
- subscribe_to_action_mailer_events if defined?(ActionMailer)
57
- subscribe_to_exception_notifications
58
61
 
59
62
  # Fallback: low-level rack.exception subscription (older Rails and deep middleware errors)
60
63
  ActiveSupport::Notifications.subscribe("rack.exception") do |*args|
@@ -387,10 +390,19 @@ module ActiveRabbit
387
390
  end
388
391
 
389
392
  def subscribe_to_controller_events
393
+ Rails.logger.info "[ActiveRabbit] Subscribing to controller events (configured=#{ActiveRabbit::Client.configured?})"
394
+
390
395
  ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, payload|
391
396
  begin
397
+ unless ActiveRabbit::Client.configured?
398
+ Rails.logger.debug "[ActiveRabbit] Skipping performance tracking - not configured"
399
+ return
400
+ end
401
+
392
402
  duration_ms = ((finished - started) * 1000).round(2)
393
403
 
404
+ Rails.logger.info "[ActiveRabbit] 📊 Controller action: #{payload[:controller]}##{payload[:action]} - #{duration_ms}ms"
405
+
394
406
  ActiveRabbit::Client.track_performance(
395
407
  "controller.action",
396
408
  duration_ms,
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRabbit
4
4
  module Client
5
- VERSION = "0.4.2"
5
+ VERSION = "0.4.5"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerabbit-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Shapalov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-21 00:00:00.000000000 Z
11
+ date: 2025-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby