Class: RailsErrorDashboard::ErrorLog
- Inherits:
-
ErrorLogsRecord
- Object
- ActiveRecord::Base
- ErrorLogsRecord
- RailsErrorDashboard::ErrorLog
- Defined in:
- app/models/rails_error_dashboard/error_log.rb
Constant Summary collapse
- CRITICAL_ERROR_TYPES =
%w[ SecurityError NoMemoryError SystemStackError SignalException ActiveRecord::StatementInvalid ].freeze
- HIGH_SEVERITY_ERROR_TYPES =
%w[ ActiveRecord::RecordNotFound ArgumentError TypeError NoMethodError NameError ].freeze
- MEDIUM_SEVERITY_ERROR_TYPES =
%w[ ActiveRecord::RecordInvalid Timeout::Error Net::ReadTimeout Net::OpenTimeout ].freeze
Class Method Summary collapse
-
.belongs_to(*args, **options) ⇒ Object
Override user association to use configured user model.
-
.find_or_increment_by_hash(error_hash, attributes = {}) ⇒ Object
Find existing error by hash or create new one This is CRITICAL for accurate occurrence tracking.
-
.log_error(exception, context = {}) ⇒ Object
Log an error with context (delegates to Command).
-
.statistics(days = 7) ⇒ Object
Get error statistics.
Instance Method Summary collapse
-
#critical? ⇒ Boolean
Check if this is a critical error.
-
#generate_error_hash ⇒ Object
Generate unique hash for error grouping Includes controller/action for better context-aware grouping.
-
#recent? ⇒ Boolean
Check if error is recent (< 1 hour).
-
#related_errors(limit: 5) ⇒ Object
Find related errors of the same type.
-
#resolve!(resolution_data = {}) ⇒ Object
Mark error as resolved (delegates to Command).
- #set_defaults ⇒ Object
- #set_tracking_fields ⇒ Object
-
#severity ⇒ Object
Get severity level.
-
#stale? ⇒ Boolean
Check if error is old unresolved (> 7 days).
Class Method Details
.belongs_to(*args, **options) ⇒ Object
Override user association to use configured user model
177 178 179 180 181 182 183 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 177 def self.belongs_to(*args, **) if args.first == :user user_model = RailsErrorDashboard.configuration.user_model [:class_name] = user_model if user_model.present? end super end |
.find_or_increment_by_hash(error_hash, attributes = {}) ⇒ Object
Find existing error by hash or create new one This is CRITICAL for accurate occurrence tracking
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 109 def self.find_or_increment_by_hash(error_hash, attributes = {}) # Look for unresolved error with same hash in last 24 hours # (resolved errors are considered "fixed" so new occurrence = new issue) existing = unresolved .where(error_hash: error_hash) .where("occurred_at >= ?", 24.hours.ago) .order(last_seen_at: :desc) .first if existing # Increment existing error existing.update!( occurrence_count: existing.occurrence_count + 1, last_seen_at: Time.current, # Update context from latest occurrence user_id: attributes[:user_id] || existing.user_id, request_url: attributes[:request_url] || existing.request_url, request_params: attributes[:request_params] || existing.request_params, user_agent: attributes[:user_agent] || existing.user_agent, ip_address: attributes[:ip_address] || existing.ip_address ) existing else # Create new error record # Ensure resolved has a value (default to false) create!(attributes.reverse_merge(resolved: false)) end end |
.log_error(exception, context = {}) ⇒ Object
Log an error with context (delegates to Command)
139 140 141 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 139 def self.log_error(exception, context = {}) Commands::LogError.call(exception, context) end |
.statistics(days = 7) ⇒ Object
Get error statistics
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 149 def self.statistics(days = 7) start_date = days.days.ago { total: where("occurred_at >= ?", start_date).count, unresolved: where("occurred_at >= ?", start_date).unresolved.count, by_type: where("occurred_at >= ?", start_date) .group(:error_type) .count .sort_by { |_, count| -count } .to_h, by_day: where("occurred_at >= ?", start_date) .group("DATE(occurred_at)") .count } end |
Instance Method Details
#critical? ⇒ Boolean
Check if this is a critical error
62 63 64 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 62 def critical? CRITICAL_ERROR_TYPES.include?(error_type) end |
#generate_error_hash ⇒ Object
Generate unique hash for error grouping Includes controller/action for better context-aware grouping
48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 48 def generate_error_hash # Hash based on error class, normalized message, first stack frame, controller, and action digest_input = [ error_type, &.gsub(/\d+/, "N")&.gsub(/"[^"]*"/, '""'), # Normalize numbers and strings backtrace&.lines&.first&.split(":")&.first, # Just the file, not line number controller_name, # Controller context action_name # Action context ].compact.join("|") Digest::SHA256.hexdigest(digest_input)[0..15] end |
#recent? ⇒ Boolean
Check if error is recent (< 1 hour)
67 68 69 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 67 def recent? occurred_at >= 1.hour.ago end |
#related_errors(limit: 5) ⇒ Object
Find related errors of the same type
167 168 169 170 171 172 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 167 def (limit: 5) self.class.where(error_type: error_type) .where.not(id: id) .order(occurred_at: :desc) .limit(limit) end |
#resolve!(resolution_data = {}) ⇒ Object
Mark error as resolved (delegates to Command)
144 145 146 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 144 def resolve!(resolution_data = {}) Commands::ResolveError.call(id, resolution_data) end |
#set_defaults ⇒ Object
34 35 36 37 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 34 def set_defaults self.environment ||= Rails.env.to_s self.platform ||= "API" end |
#set_tracking_fields ⇒ Object
39 40 41 42 43 44 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 39 def set_tracking_fields self.error_hash ||= generate_error_hash self.first_seen_at ||= Time.current self.last_seen_at ||= Time.current self.occurrence_count ||= 1 end |
#severity ⇒ Object
Get severity level
77 78 79 80 81 82 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 77 def severity return :critical if CRITICAL_ERROR_TYPES.include?(error_type) return :high if HIGH_SEVERITY_ERROR_TYPES.include?(error_type) return :medium if MEDIUM_SEVERITY_ERROR_TYPES.include?(error_type) :low end |
#stale? ⇒ Boolean
Check if error is old unresolved (> 7 days)
72 73 74 |
# File 'app/models/rails_error_dashboard/error_log.rb', line 72 def stale? !resolved? && occurred_at < 7.days.ago end |