activerabbit-ai 0.4.0 → 0.4.2
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 +24 -0
- data/check_api_data.rb +0 -0
- data/lib/active_rabbit/client/action_mailer_patch.rb +40 -0
- data/lib/active_rabbit/client/active_job_extensions.rb +66 -0
- data/lib/active_rabbit/client/configuration.rb +12 -3
- data/lib/active_rabbit/client/dedupe.rb +42 -0
- data/lib/active_rabbit/client/error_reporter.rb +78 -0
- data/lib/active_rabbit/client/event_processor.rb +5 -0
- data/lib/active_rabbit/client/exception_tracker.rb +90 -19
- data/lib/active_rabbit/client/http_client.rb +134 -16
- data/lib/active_rabbit/client/railtie.rb +492 -46
- data/lib/active_rabbit/client/version.rb +1 -1
- data/lib/active_rabbit/client.rb +23 -4
- data/lib/active_rabbit/middleware/error_capture_middleware.rb +24 -0
- data/lib/active_rabbit/reporting.rb +63 -0
- data/lib/active_rabbit/routing/not_found_app.rb +19 -0
- data/lib/active_rabbit-client.gemspec +0 -0
- data/lib/active_rabbit.rb +10 -2
- data/setup_local_gem_testing.sh +48 -0
- data/test_net_http.rb +47 -0
- data/test_with_api.rb +169 -0
- data/trigger_errors.rb +64 -0
- metadata +15 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48326a10836bf940aea7ebf3b6eca91f60086eb69e51e5e94266db5012d47ad9
|
|
4
|
+
data.tar.gz: 9244e314ba69d85fd9652604014520f8cbc6a4ab2c6da046b28a7f9c540a402e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 866f2f2f296c7a254526691e02e6c182aade30274985de6ca69f8e715b9af4036b489437eb2742840bf9fe1a582a0eaafae3ad0605342da4acde3dc6ee4d752a
|
|
7
|
+
data.tar.gz: f59a2b3dcfd170f048f96751f870cc238333fc576fbf200668ef040db9a88b97de8b1a0f60cf8c6490c3ee3f8c4ee1941318571d39d644921e0f04e2a2ae29c8
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.4.2] - 2025-01-04
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Major Rails 6.1 compatibility fix**: Added Rails Engine as primary integration method
|
|
9
|
+
- Engine loads after Rails initialization (safer than Railtie)
|
|
10
|
+
- Added comprehensive error handling for Rails loading edge cases
|
|
11
|
+
- Fallback mechanism: Engine -> Railtie -> Graceful degradation
|
|
12
|
+
- Fixed Logger initialization issues in Docker environments
|
|
13
|
+
- Added better error messages for debugging Rails integration issues
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Rails Engine integration (`ActiveRabbit::Client::Engine`)
|
|
17
|
+
- Safer middleware insertion with error handling
|
|
18
|
+
- Enhanced shutdown hooks and signal handling
|
|
19
|
+
- Better request context management
|
|
20
|
+
|
|
21
|
+
## [0.4.1] - 2025-01-04
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Added explicit `require "logger"` to prevent Rails initialization issues
|
|
25
|
+
- Made Rails.logger access safer with fallback to STDOUT logger
|
|
26
|
+
- Changed initializer to run after `:initialize_logger` to ensure proper load order
|
|
27
|
+
- Fixed potential NameError with ActiveSupport::LoggerThreadSafeLevel::Logger
|
|
28
|
+
|
|
5
29
|
## [0.4.0] - 2025-01-04
|
|
6
30
|
|
|
7
31
|
### Added
|
data/check_api_data.rb
ADDED
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
return unless defined?(ActionMailer)
|
|
4
|
+
|
|
5
|
+
module ActiveRabbit
|
|
6
|
+
module Client
|
|
7
|
+
module ActionMailerPatch
|
|
8
|
+
def deliver_now
|
|
9
|
+
start_time = Time.now
|
|
10
|
+
super
|
|
11
|
+
ensure
|
|
12
|
+
if ActiveRabbit::Client.configured?
|
|
13
|
+
duration_ms = ((Time.now - start_time) * 1000).round(2)
|
|
14
|
+
ActiveRabbit::Client.track_event(
|
|
15
|
+
"email_sent",
|
|
16
|
+
{
|
|
17
|
+
mailer: self.class.name,
|
|
18
|
+
message_id: (message.message_id rescue nil),
|
|
19
|
+
subject: (message.subject rescue nil),
|
|
20
|
+
to: (Array(message.to).first rescue nil),
|
|
21
|
+
duration_ms: duration_ms
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def deliver_later
|
|
28
|
+
ActiveRabbit::Client.track_event(
|
|
29
|
+
"email_enqueued",
|
|
30
|
+
{ mailer: self.class.name, subject: (message.subject rescue nil), to: (Array(message.to).first rescue nil) }
|
|
31
|
+
) if ActiveRabbit::Client.configured?
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
ActionMailer::MessageDelivery.prepend(ActiveRabbit::Client::ActionMailerPatch)
|
|
39
|
+
|
|
40
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRabbit
|
|
4
|
+
module Client
|
|
5
|
+
module ActiveJobExtensions
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.around_perform do |job, block|
|
|
8
|
+
start_time = Time.now
|
|
9
|
+
|
|
10
|
+
Thread.current[:active_rabbit_job_context] = {
|
|
11
|
+
job_class: job.class.name,
|
|
12
|
+
job_id: job.job_id,
|
|
13
|
+
queue_name: job.queue_name,
|
|
14
|
+
arguments: ActiveRabbit::Client::ActiveJobExtensions.scrub_arguments(job.arguments),
|
|
15
|
+
provider_job_id: (job.respond_to?(:provider_job_id) ? job.provider_job_id : nil)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
block.call
|
|
20
|
+
|
|
21
|
+
duration_ms = ((Time.now - start_time) * 1000).round(2)
|
|
22
|
+
if ActiveRabbit::Client.configured?
|
|
23
|
+
ActiveRabbit::Client.track_performance(
|
|
24
|
+
"active_job.perform",
|
|
25
|
+
duration_ms,
|
|
26
|
+
metadata: { job_class: job.class.name, queue_name: job.queue_name, status: "completed" }
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
rescue Exception => exception
|
|
30
|
+
duration_ms = ((Time.now - start_time) * 1000).round(2)
|
|
31
|
+
if ActiveRabbit::Client.configured?
|
|
32
|
+
ActiveRabbit::Client.track_performance(
|
|
33
|
+
"active_job.perform",
|
|
34
|
+
duration_ms,
|
|
35
|
+
metadata: { job_class: job.class.name, queue_name: job.queue_name, status: "failed" }
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
ActiveRabbit::Client.track_exception(
|
|
39
|
+
exception,
|
|
40
|
+
context: {
|
|
41
|
+
job: {
|
|
42
|
+
job_class: job.class.name,
|
|
43
|
+
job_id: job.job_id,
|
|
44
|
+
queue_name: job.queue_name,
|
|
45
|
+
arguments: ActiveRabbit::Client::ActiveJobExtensions.scrub_arguments(job.arguments)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
tags: { component: "active_job", queue: job.queue_name }
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
raise
|
|
52
|
+
ensure
|
|
53
|
+
Thread.current[:active_rabbit_job_context] = nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.scrub_arguments(args)
|
|
59
|
+
return args unless ActiveRabbit::Client.configuration&.enable_pii_scrubbing
|
|
60
|
+
PiiScrubber.new(ActiveRabbit::Client.configuration).scrub(args)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
@@ -11,12 +11,12 @@ module ActiveRabbit
|
|
|
11
11
|
attr_accessor :batch_size, :flush_interval, :queue_size
|
|
12
12
|
attr_accessor :enable_performance_monitoring, :enable_n_plus_one_detection
|
|
13
13
|
attr_accessor :enable_pii_scrubbing, :pii_fields
|
|
14
|
-
attr_accessor :ignored_exceptions, :ignored_user_agents
|
|
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
17
|
|
|
18
18
|
def initialize
|
|
19
|
-
@api_url = ENV.fetch("active_rabbit_API_URL", "https://api.activerabbit.
|
|
19
|
+
@api_url = ENV.fetch("active_rabbit_API_URL", "https://api.activerabbit.ai")
|
|
20
20
|
@api_key = ENV["active_rabbit_API_KEY"]
|
|
21
21
|
@project_id = ENV["active_rabbit_PROJECT_ID"]
|
|
22
22
|
@environment = ENV.fetch("active_rabbit_ENVIRONMENT", detect_environment)
|
|
@@ -45,9 +45,10 @@ module ActiveRabbit
|
|
|
45
45
|
]
|
|
46
46
|
|
|
47
47
|
# Filtering
|
|
48
|
+
# default ignores (404 controlled by ignore_404)
|
|
49
|
+
@ignore_404 = true
|
|
48
50
|
@ignored_exceptions = %w[
|
|
49
51
|
ActiveRecord::RecordNotFound
|
|
50
|
-
ActionController::RoutingError
|
|
51
52
|
ActionController::InvalidAuthenticityToken
|
|
52
53
|
CGI::Session::CookieStore::TamperedWithCookie
|
|
53
54
|
]
|
|
@@ -83,6 +84,14 @@ module ActiveRabbit
|
|
|
83
84
|
|
|
84
85
|
def should_ignore_exception?(exception)
|
|
85
86
|
return false unless exception
|
|
87
|
+
# Special-case 404 via flag
|
|
88
|
+
if @ignore_404
|
|
89
|
+
begin
|
|
90
|
+
return true if exception.is_a?(ActionController::RoutingError)
|
|
91
|
+
rescue NameError
|
|
92
|
+
# Ignore if AC not loaded
|
|
93
|
+
end
|
|
94
|
+
end
|
|
86
95
|
|
|
87
96
|
ignored_exceptions.any? do |ignored|
|
|
88
97
|
case ignored
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "monitor"
|
|
4
|
+
|
|
5
|
+
module ActiveRabbit
|
|
6
|
+
module Client
|
|
7
|
+
module Dedupe
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
WINDOW_SECONDS = 5
|
|
11
|
+
|
|
12
|
+
@seen = {}
|
|
13
|
+
@lock = Monitor.new
|
|
14
|
+
|
|
15
|
+
def seen_recently?(exception, context = {}, window: WINDOW_SECONDS)
|
|
16
|
+
key = build_key(exception, context)
|
|
17
|
+
now = Time.now.to_f
|
|
18
|
+
@lock.synchronize do
|
|
19
|
+
prune!(now, window)
|
|
20
|
+
last = @seen[key]
|
|
21
|
+
@seen[key] = now
|
|
22
|
+
return last && (now - last) < window
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def prune!(now, window)
|
|
29
|
+
cutoff = now - window
|
|
30
|
+
@seen.delete_if { |_k, ts| ts < cutoff }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def build_key(exception, context)
|
|
34
|
+
top = Array(exception.backtrace).first.to_s
|
|
35
|
+
req_id = context[:request]&.[](:request_id) || context[:request_id] || context[:requestId]
|
|
36
|
+
[exception.class.name, top, req_id].join("|")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'set'
|
|
3
|
+
require_relative '../reporting'
|
|
4
|
+
|
|
5
|
+
module ActiveRabbit
|
|
6
|
+
module Client
|
|
7
|
+
module ErrorReporter
|
|
8
|
+
class Subscriber
|
|
9
|
+
def report(exception, handled:, severity:, context:, source: nil)
|
|
10
|
+
begin
|
|
11
|
+
Rails.logger.info "[ActiveRabbit] Error reporter caught: #{exception.class}: #{exception.message}" if defined?(Rails.logger)
|
|
12
|
+
|
|
13
|
+
# Initialize de-dup set
|
|
14
|
+
$reported_errors ||= Set.new
|
|
15
|
+
|
|
16
|
+
# Generate a unique key for this error
|
|
17
|
+
error_key = "#{exception.class.name}:#{exception.message}:#{exception.backtrace&.first}"
|
|
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)
|
|
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
|
|
28
|
+
end
|
|
29
|
+
rescue => e
|
|
30
|
+
Rails.logger.error "[ActiveRabbit] Error in ErrorReporter::Subscriber#report: #{e.class} - #{e.message}" if defined?(Rails.logger)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def build_enriched_context(exception, handled:, severity:, context: {})
|
|
37
|
+
ctx = { handled: handled, severity: severity, source: 'rails_error_reporter' }
|
|
38
|
+
ctx[:framework_context] = context || {}
|
|
39
|
+
|
|
40
|
+
env = context && (context[:env] || context['env'])
|
|
41
|
+
if env
|
|
42
|
+
req_info = ActiveRabbit::Reporting.rack_request_info(env)
|
|
43
|
+
ctx[:request] = req_info[:request]
|
|
44
|
+
ctx[:routing] = req_info[:routing]
|
|
45
|
+
# Top-level convenience for UI
|
|
46
|
+
ctx[:request_path] = ctx[:request][:path]
|
|
47
|
+
ctx[:request_method] = ctx[:request][:method]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if defined?(ActionController::RoutingError) && exception.is_a?(ActionController::RoutingError)
|
|
51
|
+
ctx[:controller_action] = 'Routing#not_found'
|
|
52
|
+
ctx[:error_type] = 'route_not_found'
|
|
53
|
+
ctx[:error_status] = 404
|
|
54
|
+
ctx[:error_component] = 'ActionDispatch'
|
|
55
|
+
ctx[:error_source] = 'Router'
|
|
56
|
+
ctx[:tags] = (ctx[:tags] || {}).merge(error_type: 'routing_error', severity: 'warning')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
ctx
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.attach!
|
|
64
|
+
# Rails 7.0+: Rails.error; earlier versions no-op
|
|
65
|
+
if defined?(Rails) && Rails.respond_to?(:error)
|
|
66
|
+
Rails.logger.info "[ActiveRabbit] Attaching to Rails error reporter" if defined?(Rails.logger)
|
|
67
|
+
|
|
68
|
+
subscriber = Subscriber.new
|
|
69
|
+
Rails.error.subscribe(subscriber)
|
|
70
|
+
|
|
71
|
+
Rails.logger.info "[ActiveRabbit] Rails error reporter attached successfully" if defined?(Rails.logger)
|
|
72
|
+
else
|
|
73
|
+
Rails.logger.info "[ActiveRabbit] Rails error reporter not available (Rails < 7.0)" if defined?(Rails.logger)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -102,6 +102,11 @@ module ActiveRabbit
|
|
|
102
102
|
context[:request] = Thread.current[:active_rabbit_request_context]
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
+
# Background job information (if available)
|
|
106
|
+
if defined?(Thread) && Thread.current[:active_rabbit_job_context]
|
|
107
|
+
context[:job] = Thread.current[:active_rabbit_job_context]
|
|
108
|
+
end
|
|
109
|
+
|
|
105
110
|
context
|
|
106
111
|
end
|
|
107
112
|
|
|
@@ -13,15 +13,16 @@ module ActiveRabbit
|
|
|
13
13
|
@http_client = http_client
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def track_exception(exception:, context: {}, user_id: nil, tags: {})
|
|
16
|
+
def track_exception(exception:, context: {}, user_id: nil, tags: {}, handled: nil, force: false)
|
|
17
17
|
return unless exception
|
|
18
|
-
return if should_ignore_exception?(exception)
|
|
18
|
+
return if !force && should_ignore_exception?(exception)
|
|
19
19
|
|
|
20
20
|
exception_data = build_exception_data(
|
|
21
21
|
exception: exception,
|
|
22
22
|
context: context,
|
|
23
23
|
user_id: user_id,
|
|
24
|
-
tags: tags
|
|
24
|
+
tags: tags,
|
|
25
|
+
handled: handled
|
|
25
26
|
)
|
|
26
27
|
|
|
27
28
|
# Apply before_send callback if configured
|
|
@@ -30,7 +31,27 @@ module ActiveRabbit
|
|
|
30
31
|
return unless exception_data # Callback can filter out exceptions by returning nil
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
# Send exception to API and return response
|
|
35
|
+
configuration.logger&.info("[ActiveRabbit] Preparing to send exception: #{exception.class.name}")
|
|
36
|
+
configuration.logger&.debug("[ActiveRabbit] Exception data: #{exception_data.inspect}")
|
|
37
|
+
|
|
38
|
+
# Ensure we have required fields
|
|
39
|
+
unless exception_data[:exception_class] && exception_data[:message] && exception_data[:backtrace]
|
|
40
|
+
configuration.logger&.error("[ActiveRabbit] Missing required fields in exception data")
|
|
41
|
+
configuration.logger&.debug("[ActiveRabbit] Available fields: #{exception_data.keys.inspect}")
|
|
42
|
+
return nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
response = http_client.post_exception(exception_data)
|
|
46
|
+
|
|
47
|
+
if response.nil?
|
|
48
|
+
configuration.logger&.error("[ActiveRabbit] Failed to send exception - both primary and fallback endpoints failed")
|
|
49
|
+
return nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
configuration.logger&.info("[ActiveRabbit] Exception successfully sent to API")
|
|
53
|
+
configuration.logger&.debug("[ActiveRabbit] API Response: #{response.inspect}")
|
|
54
|
+
response
|
|
34
55
|
end
|
|
35
56
|
|
|
36
57
|
def flush
|
|
@@ -39,33 +60,83 @@ module ActiveRabbit
|
|
|
39
60
|
|
|
40
61
|
private
|
|
41
62
|
|
|
42
|
-
def build_exception_data(exception:, context:, user_id:, tags:)
|
|
43
|
-
|
|
63
|
+
def build_exception_data(exception:, context:, user_id:, tags:, handled: nil)
|
|
64
|
+
parsed_bt = parse_backtrace(exception.backtrace || [])
|
|
65
|
+
backtrace_lines = parsed_bt.map { |frame| frame[:line] }
|
|
66
|
+
|
|
67
|
+
# Fallback: synthesize a helpful frame for routing errors with no backtrace
|
|
68
|
+
if backtrace_lines.empty?
|
|
69
|
+
synthetic = nil
|
|
70
|
+
if context && (context[:routing]&.[](:path) || context[:request_path])
|
|
71
|
+
path = context[:routing]&.[](:path) || context[:request_path]
|
|
72
|
+
synthetic = "#{defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : 'app'}/config/routes.rb:1:in `route_not_found' for #{path}"
|
|
73
|
+
elsif exception && exception.message && exception.message =~ /No route matches \[(\w+)\] \"(.+?)\"/
|
|
74
|
+
path = $2
|
|
75
|
+
synthetic = "#{defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : 'app'}/config/routes.rb:1:in `route_not_found' for #{path}"
|
|
76
|
+
end
|
|
77
|
+
backtrace_lines = [synthetic] if synthetic
|
|
78
|
+
end
|
|
44
79
|
|
|
80
|
+
# Build data in the format the API expects
|
|
45
81
|
data = {
|
|
46
|
-
|
|
82
|
+
# Required fields
|
|
83
|
+
exception_class: exception.class.name,
|
|
47
84
|
message: exception.message,
|
|
48
|
-
backtrace:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
85
|
+
backtrace: backtrace_lines,
|
|
86
|
+
|
|
87
|
+
# Timing and environment
|
|
88
|
+
occurred_at: Time.now.iso8601(3),
|
|
89
|
+
environment: configuration.environment || 'development',
|
|
90
|
+
release_version: configuration.release,
|
|
53
91
|
server_name: configuration.server_name,
|
|
54
|
-
context: scrub_pii(context || {}),
|
|
55
|
-
tags: tags || {}
|
|
56
|
-
}
|
|
57
92
|
|
|
58
|
-
|
|
59
|
-
|
|
93
|
+
# Context from the error
|
|
94
|
+
controller_action: context[:controller_action],
|
|
95
|
+
request_path: context[:request_path],
|
|
96
|
+
request_method: context[:request_method],
|
|
60
97
|
|
|
61
|
-
|
|
62
|
-
|
|
98
|
+
# Additional context
|
|
99
|
+
context: scrub_pii(context || {}),
|
|
100
|
+
tags: tags || {},
|
|
101
|
+
user_id: user_id,
|
|
102
|
+
project_id: configuration.project_id,
|
|
103
|
+
|
|
104
|
+
# Runtime info
|
|
105
|
+
runtime_context: build_runtime_context,
|
|
106
|
+
|
|
107
|
+
# Error details (for better UI display)
|
|
108
|
+
error_type: context[:error_type] || exception.class.name,
|
|
109
|
+
error_message: context[:error_message] || exception.message,
|
|
110
|
+
error_location: context[:error_location] || backtrace_lines.first,
|
|
111
|
+
error_severity: context[:error_severity] || :error,
|
|
112
|
+
error_status: context[:error_status] || 500,
|
|
113
|
+
error_source: context[:error_source] || 'Application',
|
|
114
|
+
error_component: context[:error_component] || 'Unknown',
|
|
115
|
+
error_action: context[:error_action],
|
|
116
|
+
handled: context.key?(:handled) ? context[:handled] : handled,
|
|
117
|
+
|
|
118
|
+
# Request details
|
|
119
|
+
request_details: context[:request_details],
|
|
120
|
+
response_time: context[:response_time],
|
|
121
|
+
routing_info: context[:routing_info]
|
|
122
|
+
}
|
|
63
123
|
|
|
64
124
|
# Add request context if available
|
|
65
125
|
if defined?(Thread) && Thread.current[:active_rabbit_request_context]
|
|
66
126
|
data[:request_context] = Thread.current[:active_rabbit_request_context]
|
|
67
127
|
end
|
|
68
128
|
|
|
129
|
+
# Add background job context if available
|
|
130
|
+
if defined?(Thread) && Thread.current[:active_rabbit_job_context]
|
|
131
|
+
data[:job_context] = Thread.current[:active_rabbit_job_context]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Log what we're sending
|
|
135
|
+
configuration.logger&.debug("[ActiveRabbit] Built exception data:")
|
|
136
|
+
configuration.logger&.debug("[ActiveRabbit] - Required fields: class=#{data[:exception_class]}, message=#{data[:message]}, backtrace=#{data[:backtrace]&.first}")
|
|
137
|
+
configuration.logger&.debug("[ActiveRabbit] - Error details: type=#{data[:error_type]}, source=#{data[:error_source]}, component=#{data[:error_component]}")
|
|
138
|
+
configuration.logger&.debug("[ActiveRabbit] - Request info: path=#{data[:request_path]}, method=#{data[:request_method]}, action=#{data[:controller_action]}")
|
|
139
|
+
|
|
69
140
|
data
|
|
70
141
|
end
|
|
71
142
|
|