beskar 0.0.2 → 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 +4 -4
- data/CHANGELOG.md +274 -0
- data/README.md +412 -204
- data/app/channels/concerns/beskar/channels/session_security.rb +46 -0
- data/app/controllers/beskar/administrative_actions_controller.rb +16 -0
- data/app/controllers/beskar/application_controller.rb +214 -0
- data/app/controllers/beskar/banned_ips_controller.rb +255 -0
- data/app/controllers/beskar/dashboard_controller.rb +62 -0
- data/app/controllers/beskar/security_events_controller.rb +164 -0
- data/app/controllers/concerns/beskar/controllers/audit_export.rb +54 -0
- data/app/controllers/concerns/beskar/controllers/security_tracking.rb +76 -48
- data/app/controllers/concerns/beskar/controllers/session_security.rb +29 -0
- data/app/jobs/beskar/notification_job.rb +33 -0
- data/app/mailers/beskar/security_mailer.rb +59 -0
- data/app/models/beskar/administrative_action.rb +41 -0
- data/app/models/beskar/banned_ip.rb +105 -105
- data/app/models/beskar/security_event.rb +51 -4
- data/app/models/beskar/security_state.rb +58 -0
- data/app/services/beskar/banned_ip_manager.rb +88 -0
- data/app/views/beskar/administrative_actions/index.html.erb +33 -0
- data/app/views/beskar/administrative_actions/show.html.erb +21 -0
- data/app/views/beskar/banned_ips/edit.html.erb +195 -0
- data/app/views/beskar/banned_ips/index.html.erb +319 -0
- data/app/views/beskar/banned_ips/new.html.erb +190 -0
- data/app/views/beskar/banned_ips/review.html.erb +24 -0
- data/app/views/beskar/banned_ips/show.html.erb +304 -0
- data/app/views/beskar/dashboard/index.html.erb +280 -0
- data/app/views/beskar/security_events/index.html.erb +302 -0
- data/app/views/beskar/security_events/show.html.erb +293 -0
- data/app/views/beskar/shared/_export_form.html.erb +10 -0
- data/app/views/layouts/beskar/_behavior.html.erb +121 -0
- data/app/views/layouts/beskar/application.html.erb +581 -6
- data/config/routes.rb +30 -0
- data/db/migrate/20251016000001_create_beskar_security_events.rb +3 -3
- data/db/migrate/20260910000001_create_beskar_security_states.rb +14 -0
- data/db/migrate/20260911000001_create_beskar_administrative_actions.rb +22 -0
- data/db/migrate/20260911000002_expand_administrative_action_targets.rb +6 -0
- data/docs/README.md +73 -0
- data/docs/archive/project-documentation.md +659 -0
- data/docs/audits/project-review.md +437 -0
- data/docs/audits/repair-status.md +216 -0
- data/docs/guides/audit-and-waf.md +175 -0
- data/docs/guides/audit-lifecycle.md +172 -0
- data/docs/guides/authentication.md +213 -0
- data/docs/guides/configuration.md +182 -0
- data/docs/guides/dashboard-and-search.md +251 -0
- data/docs/guides/notifications-and-recovery.md +157 -0
- data/docs/guides/risk-scoring.md +116 -0
- data/docs/operations/monitor-only-mode.md +85 -0
- data/docs/operations/security-hardening.md +167 -0
- data/docs/operations/state-storage.md +144 -0
- data/docs/research/rust-performance-assessment.md +69 -0
- data/lib/beskar/configuration.rb +105 -20
- data/lib/beskar/configuration_validator.rb +188 -0
- data/lib/beskar/devise_authentication.rb +24 -0
- data/lib/beskar/engine.rb +21 -88
- data/lib/beskar/logger.rb +288 -0
- data/lib/beskar/middleware/request_analyzer.rb +133 -99
- data/lib/beskar/models/security_trackable_authenticable.rb +76 -97
- data/lib/beskar/models/security_trackable_devise.rb +34 -25
- data/lib/beskar/models/security_trackable_generic.rb +171 -214
- data/lib/beskar/risk_level.rb +22 -0
- data/lib/beskar/services/account_locker.rb +90 -81
- data/lib/beskar/services/administrative_audit.rb +36 -0
- data/lib/beskar/services/administrative_bans.rb +104 -0
- data/lib/beskar/services/audit_data.rb +72 -0
- data/lib/beskar/services/authentication.rb +31 -0
- data/lib/beskar/services/authentication_attempt.rb +141 -0
- data/lib/beskar/services/ban_expiry.rb +28 -0
- data/lib/beskar/services/device_detector.rb +32 -41
- data/lib/beskar/services/event_search.rb +58 -0
- data/lib/beskar/services/geolocation_service.rb +83 -114
- data/lib/beskar/services/ip_whitelist.rb +31 -40
- data/lib/beskar/services/location_assessment.rb +109 -0
- data/lib/beskar/services/native_account_lock.rb +82 -0
- data/lib/beskar/services/notifications.rb +46 -0
- data/lib/beskar/services/rate_limiter.rb +99 -125
- data/lib/beskar/services/request_context.rb +64 -0
- data/lib/beskar/services/risk_assessment.rb +58 -0
- data/lib/beskar/services/session_revocation.rb +62 -0
- data/lib/beskar/services/waf.rb +311 -198
- data/lib/beskar/services/waf_request.rb +60 -0
- data/lib/beskar/version.rb +1 -1
- data/lib/beskar/warden_authentication.rb +53 -0
- data/lib/beskar.rb +54 -4
- data/lib/generators/beskar/install/install_generator.rb +158 -0
- data/lib/generators/beskar/install/templates/initializer.rb.tt +261 -0
- data/lib/tasks/beskar_tasks.rake +25 -20
- metadata +93 -12
- data/lib/beskar/templates/beskar_initializer.rb +0 -107
data/lib/beskar/engine.rb
CHANGED
|
@@ -6,105 +6,38 @@ module Beskar
|
|
|
6
6
|
app.config.middleware.use ::Beskar::Middleware::RequestAnalyzer
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Beskar::BannedIp.preload_cache!
|
|
14
|
-
Rails.logger.info "[Beskar] Preloaded banned IPs into cache"
|
|
15
|
-
rescue => e
|
|
16
|
-
Rails.logger.warn "[Beskar] Failed to preload banned IPs: #{e.message}"
|
|
17
|
-
end
|
|
9
|
+
initializer "beskar.warden_callbacks", after: :load_config_initializers do
|
|
10
|
+
if defined?(Devise)
|
|
11
|
+
require "devise/strategies/database_authenticatable"
|
|
12
|
+
Devise::Strategies::DatabaseAuthenticatable.prepend(Beskar::DeviseAuthentication)
|
|
18
13
|
end
|
|
19
|
-
end
|
|
20
14
|
|
|
21
|
-
initializer "beskar.warden_callbacks", after: :load_config_initializers do |app|
|
|
22
15
|
if defined?(Warden)
|
|
23
|
-
|
|
24
|
-
Warden::
|
|
25
|
-
# Only proceed if Beskar security tracking is available and enabled
|
|
26
|
-
if user.respond_to?(:track_authentication_event) && auth.request
|
|
27
|
-
# Track the authentication event (creates security event)
|
|
28
|
-
security_event = user.track_authentication_event(auth.request, :success)
|
|
29
|
-
|
|
30
|
-
# Check if account was locked due to high risk (only if immediate_signout is enabled)
|
|
31
|
-
# This happens AFTER successful authentication but BEFORE the request completes
|
|
32
|
-
# Requires :lockable module to be enabled on the user model
|
|
33
|
-
if Beskar.configuration.immediate_signout? &&
|
|
34
|
-
Beskar.configuration.risk_based_locking_enabled? &&
|
|
35
|
-
security_event &&
|
|
36
|
-
user_was_just_locked?(user, security_event) &&
|
|
37
|
-
user.respond_to?(:access_locked?) && user.access_locked?
|
|
38
|
-
Rails.logger.warn "[Beskar] Signing out user #{user.id} due to high-risk lock"
|
|
39
|
-
auth.logout
|
|
40
|
-
throw :warden, scope: opts[:scope], message: :account_locked_due_to_high_risk
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Alternative approach using after_authentication is available but not enabled by default
|
|
46
|
-
# Uncomment this to use the alternative approach (more targeted, only on authentication)
|
|
47
|
-
# Warden::Manager.after_authentication do |user, auth, opts|
|
|
48
|
-
# if user.respond_to?(:check_high_risk_lock_and_signout)
|
|
49
|
-
# user.check_high_risk_lock_and_signout(auth)
|
|
50
|
-
# end
|
|
51
|
-
# end
|
|
16
|
+
Warden::Strategies::Base.prepend(Beskar::WardenStrategyAdmission)
|
|
17
|
+
Warden::Proxy.prepend(Beskar::WardenSessionAdmission)
|
|
52
18
|
|
|
53
19
|
Warden::Manager.before_failure do |env, opts|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if model_class && model_class.respond_to?(:track_failed_authentication)
|
|
62
|
-
model_class.track_failed_authentication(request, scope)
|
|
63
|
-
else
|
|
64
|
-
Rails.logger.debug "[Beskar] No trackable model found for scope: #{scope}"
|
|
65
|
-
end
|
|
66
|
-
end
|
|
20
|
+
next unless env
|
|
21
|
+
request = ActionDispatch::Request.new(env)
|
|
22
|
+
attempt = Services::AuthenticationAttempt.current(request, opts[:scope])
|
|
23
|
+
next unless attempt && !attempt.completed
|
|
24
|
+
model = Beskar.configuration.model_class_for_scope(opts[:scope])
|
|
25
|
+
model.track_failed_authentication(request, opts[:scope], attempt: attempt) if model&.respond_to?(:track_failed_authentication)
|
|
67
26
|
end
|
|
68
27
|
end
|
|
69
28
|
end
|
|
70
29
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return false unless user&.respond_to?(:security_events)
|
|
76
|
-
|
|
77
|
-
# Check if an account_locked or lock_attempted event was just created
|
|
78
|
-
recent_lock = user.security_events
|
|
79
|
-
.where(event_type: [ "account_locked", "lock_attempted" ])
|
|
80
|
-
.where("created_at >= ?", 10.seconds.ago)
|
|
81
|
-
.order(created_at: :desc)
|
|
82
|
-
.first
|
|
83
|
-
|
|
84
|
-
recent_lock.present?
|
|
30
|
+
initializer "beskar.register_configuration_validation", after: :load_config_initializers do |app|
|
|
31
|
+
# Register after host configuration files, so their after_initialize hooks
|
|
32
|
+
# precede this one. Resolve app/jobs only after the main autoloader is ready.
|
|
33
|
+
app.config.after_initialize { Beskar.configuration.validate!.seal! }
|
|
85
34
|
end
|
|
86
35
|
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# Add to Rails paths
|
|
94
|
-
app.config.paths["db/migrate"] << engine_migrations
|
|
95
|
-
end
|
|
36
|
+
# Compatibility helper: only the current attempt's actual lock qualifies.
|
|
37
|
+
def self.user_was_just_locked?(user, security_event)
|
|
38
|
+
return false unless Beskar.configuration.risk_based_locking_enabled?
|
|
39
|
+
attempt = security_event&.beskar_attempt
|
|
40
|
+
!!(attempt && attempt.user == user && attempt.locked_now)
|
|
96
41
|
end
|
|
97
|
-
|
|
98
|
-
# Ensure ActiveRecord sees the engine migrations after initialization
|
|
99
|
-
# config.after_initialize do |app|
|
|
100
|
-
# unless root.to_s.include?(app.root.to_s)
|
|
101
|
-
# engine_migrations = root.join("db", "migrate").to_s
|
|
102
|
-
|
|
103
|
-
# # Update ActiveRecord::Tasks paths
|
|
104
|
-
# current_paths = Array(ActiveRecord::Tasks::DatabaseTasks.migrations_paths)
|
|
105
|
-
# current_paths << engine_migrations
|
|
106
|
-
# ActiveRecord::Tasks::DatabaseTasks.migrations_paths = current_paths.uniq
|
|
107
|
-
# end
|
|
108
|
-
# end
|
|
109
42
|
end
|
|
110
43
|
end
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Beskar
|
|
4
|
+
# Centralized logging module for consistent log formatting and flexible output handling
|
|
5
|
+
module Logger
|
|
6
|
+
class << self
|
|
7
|
+
# Available log levels
|
|
8
|
+
LOG_LEVELS = %i[debug info warn error fatal].freeze
|
|
9
|
+
|
|
10
|
+
# Generate logging methods for each level
|
|
11
|
+
LOG_LEVELS.each do |level|
|
|
12
|
+
define_method(level) do |message, component: nil|
|
|
13
|
+
log(level, message, component: component)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Main logging method that handles formatting and output
|
|
18
|
+
#
|
|
19
|
+
# @param level [Symbol] The log level (:debug, :info, :warn, :error, :fatal)
|
|
20
|
+
# @param message [String] The message to log
|
|
21
|
+
# @param component [String, Symbol, nil] Optional component name for more specific prefixes
|
|
22
|
+
#
|
|
23
|
+
# @example Basic usage
|
|
24
|
+
# Beskar::Logger.info("User authenticated successfully")
|
|
25
|
+
# # => [Beskar] User authenticated successfully
|
|
26
|
+
#
|
|
27
|
+
# @example With component
|
|
28
|
+
# Beskar::Logger.warn("Rate limit exceeded", component: :WAF)
|
|
29
|
+
# # => [Beskar::WAF] Rate limit exceeded
|
|
30
|
+
#
|
|
31
|
+
# @example With class as component
|
|
32
|
+
# Beskar::Logger.error("Failed to lock account", component: self.class)
|
|
33
|
+
# # => [Beskar::AccountLocker] Failed to lock account
|
|
34
|
+
def log(level, message, component: nil)
|
|
35
|
+
return unless should_log?(level)
|
|
36
|
+
|
|
37
|
+
formatted_message = format_message(message, component)
|
|
38
|
+
logger.send(level, formatted_message)
|
|
39
|
+
rescue => e
|
|
40
|
+
# Fallback to stderr if logging fails
|
|
41
|
+
Kernel.warn "[Beskar::Logger] Logging unavailable (#{e.class})"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Configure the logger instance
|
|
45
|
+
#
|
|
46
|
+
# @param logger_instance [Logger, nil] The logger to use, defaults to Rails.logger
|
|
47
|
+
attr_writer :logger
|
|
48
|
+
|
|
49
|
+
# Get the current logger instance
|
|
50
|
+
#
|
|
51
|
+
# @return [Logger] The configured logger or Rails.logger as default
|
|
52
|
+
def logger
|
|
53
|
+
@logger ||= default_logger
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Configure log level threshold
|
|
57
|
+
#
|
|
58
|
+
# @param level [Symbol, String] Minimum log level to output
|
|
59
|
+
def level=(level)
|
|
60
|
+
@level = level.to_sym if LOG_LEVELS.include?(level.to_sym)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Get the current log level
|
|
64
|
+
#
|
|
65
|
+
# @return [Symbol] Current log level
|
|
66
|
+
def level
|
|
67
|
+
@level ||= :debug
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Reset logger configuration to defaults
|
|
71
|
+
def reset!
|
|
72
|
+
@logger = nil
|
|
73
|
+
@level = nil
|
|
74
|
+
@component_aliases = nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Configure component name aliases for cleaner output
|
|
78
|
+
#
|
|
79
|
+
# @param aliases [Hash] Mapping of classes/modules to display names
|
|
80
|
+
#
|
|
81
|
+
# @example
|
|
82
|
+
# Beskar::Logger.component_aliases = {
|
|
83
|
+
# 'Beskar::Services::Waf' => 'WAF',
|
|
84
|
+
# 'Beskar::Services::AccountLocker' => 'AccountLocker'
|
|
85
|
+
# }
|
|
86
|
+
attr_writer :component_aliases
|
|
87
|
+
|
|
88
|
+
# Get component aliases
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash] Current component aliases
|
|
91
|
+
def component_aliases
|
|
92
|
+
@component_aliases ||= default_component_aliases
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# Format the log message with appropriate prefix
|
|
98
|
+
#
|
|
99
|
+
# @param message [String] The message to format
|
|
100
|
+
# @param component [String, Symbol, Class, nil] Component identifier
|
|
101
|
+
# @return [String] Formatted message with prefix
|
|
102
|
+
def format_message(message, component)
|
|
103
|
+
prefix = build_prefix(component)
|
|
104
|
+
"#{prefix} #{message}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Build the log prefix based on component
|
|
108
|
+
#
|
|
109
|
+
# @param component [String, Symbol, Class, nil] Component identifier
|
|
110
|
+
# @return [String] Formatted prefix
|
|
111
|
+
def build_prefix(component)
|
|
112
|
+
return "[Beskar]" if component.nil?
|
|
113
|
+
|
|
114
|
+
component_name = normalize_component_name(component)
|
|
115
|
+
|
|
116
|
+
if component_name.nil? || component_name.empty?
|
|
117
|
+
"[Beskar]"
|
|
118
|
+
else
|
|
119
|
+
"[Beskar::#{component_name}]"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Normalize component name from various input types
|
|
124
|
+
#
|
|
125
|
+
# @param component [String, Symbol, Class] Component identifier
|
|
126
|
+
# @return [String, nil] Normalized component name
|
|
127
|
+
def normalize_component_name(component)
|
|
128
|
+
case component
|
|
129
|
+
when String
|
|
130
|
+
apply_component_alias(component)
|
|
131
|
+
when Symbol
|
|
132
|
+
component.to_s
|
|
133
|
+
when Class
|
|
134
|
+
apply_component_alias(component.name)
|
|
135
|
+
when Module
|
|
136
|
+
apply_component_alias(component.name)
|
|
137
|
+
else
|
|
138
|
+
component.to_s
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Apply component alias if configured
|
|
143
|
+
#
|
|
144
|
+
# @param component_name [String] Original component name
|
|
145
|
+
# @return [String] Aliased name or original
|
|
146
|
+
def apply_component_alias(component_name)
|
|
147
|
+
return nil if component_name.nil?
|
|
148
|
+
|
|
149
|
+
# First check exact matches
|
|
150
|
+
aliased = component_aliases[component_name]
|
|
151
|
+
return aliased if aliased
|
|
152
|
+
|
|
153
|
+
# Remove Beskar:: prefix if present for lookup
|
|
154
|
+
clean_name = component_name.sub(/^Beskar::/, "")
|
|
155
|
+
aliased = component_aliases[clean_name]
|
|
156
|
+
return aliased if aliased
|
|
157
|
+
|
|
158
|
+
# Check if it's already a simple component name (no ::)
|
|
159
|
+
return clean_name unless clean_name.include?("::")
|
|
160
|
+
|
|
161
|
+
# Extract the last component for nested classes
|
|
162
|
+
# e.g., "Beskar::Services::Waf" -> "Waf"
|
|
163
|
+
last_component = clean_name.split("::").last
|
|
164
|
+
component_aliases[clean_name] || last_component
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Check if message should be logged based on current level
|
|
168
|
+
#
|
|
169
|
+
# @param message_level [Symbol] Level of the message
|
|
170
|
+
# @return [Boolean] True if message should be logged
|
|
171
|
+
def should_log?(message_level)
|
|
172
|
+
level_value(message_level) >= level_value(level)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Convert log level to numeric value for comparison
|
|
176
|
+
#
|
|
177
|
+
# @param level_sym [Symbol] Log level
|
|
178
|
+
# @return [Integer] Numeric value
|
|
179
|
+
def level_value(level_sym)
|
|
180
|
+
LOG_LEVELS.index(level_sym) || 0
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Get the default logger instance
|
|
184
|
+
#
|
|
185
|
+
# @return [Logger] Default logger (Rails.logger or stdlib Logger)
|
|
186
|
+
def default_logger
|
|
187
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
188
|
+
Rails.logger
|
|
189
|
+
else
|
|
190
|
+
require "logger"
|
|
191
|
+
::Logger.new($stdout)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Default component name aliases for cleaner output
|
|
196
|
+
#
|
|
197
|
+
# @return [Hash] Default aliases
|
|
198
|
+
def default_component_aliases
|
|
199
|
+
{
|
|
200
|
+
"Beskar::Services::Waf" => "WAF",
|
|
201
|
+
"Beskar::Services::WAF" => "WAF",
|
|
202
|
+
"Services::Waf" => "WAF",
|
|
203
|
+
"Services::WAF" => "WAF",
|
|
204
|
+
"Beskar::Services::AccountLocker" => "AccountLocker",
|
|
205
|
+
"Services::AccountLocker" => "AccountLocker",
|
|
206
|
+
"Beskar::Services::RateLimiter" => "RateLimiter",
|
|
207
|
+
"Services::RateLimiter" => "RateLimiter",
|
|
208
|
+
"Beskar::Services::IpWhitelist" => "IpWhitelist",
|
|
209
|
+
"Services::IpWhitelist" => "IpWhitelist",
|
|
210
|
+
"Beskar::Services::GeolocationService" => "GeolocationService",
|
|
211
|
+
"Services::GeolocationService" => "GeolocationService",
|
|
212
|
+
"Beskar::Services::DeviceDetector" => "DeviceDetector",
|
|
213
|
+
"Services::DeviceDetector" => "DeviceDetector",
|
|
214
|
+
"Beskar::Middleware::RequestAnalyzer" => "Middleware",
|
|
215
|
+
"Middleware::RequestAnalyzer" => "Middleware",
|
|
216
|
+
"Beskar::Models::SecurityTrackableDevise" => "SecurityTracking",
|
|
217
|
+
"Models::SecurityTrackableDevise" => "SecurityTracking",
|
|
218
|
+
"Beskar::Models::SecurityTrackableAuthenticable" => "SecurityTracking",
|
|
219
|
+
"Models::SecurityTrackableAuthenticable" => "SecurityTracking",
|
|
220
|
+
"Beskar::Models::SecurityTrackableGeneric" => "SecurityTracking",
|
|
221
|
+
"Models::SecurityTrackableGeneric" => "SecurityTracking"
|
|
222
|
+
}
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Module to include in classes for instance-level logging
|
|
227
|
+
module ClassMethods
|
|
228
|
+
# Log a debug message with automatic component detection
|
|
229
|
+
def log_debug(message)
|
|
230
|
+
Beskar::Logger.debug(message, component: self)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Log an info message with automatic component detection
|
|
234
|
+
def log_info(message)
|
|
235
|
+
Beskar::Logger.info(message, component: self)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Log a warning message with automatic component detection
|
|
239
|
+
def log_warn(message)
|
|
240
|
+
Beskar::Logger.warn(message, component: self)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Log an error message with automatic component detection
|
|
244
|
+
def log_error(message)
|
|
245
|
+
Beskar::Logger.error(message, component: self)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Log a fatal message with automatic component detection
|
|
249
|
+
def log_fatal(message)
|
|
250
|
+
Beskar::Logger.fatal(message, component: self)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Module to include in classes for instance-level logging
|
|
255
|
+
module InstanceMethods
|
|
256
|
+
# Log a debug message with automatic component detection
|
|
257
|
+
def log_debug(message)
|
|
258
|
+
Beskar::Logger.debug(message, component: self.class)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Log an info message with automatic component detection
|
|
262
|
+
def log_info(message)
|
|
263
|
+
Beskar::Logger.info(message, component: self.class)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Log a warning message with automatic component detection
|
|
267
|
+
def log_warn(message)
|
|
268
|
+
Beskar::Logger.warn(message, component: self.class)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Log an error message with automatic component detection
|
|
272
|
+
def log_error(message)
|
|
273
|
+
Beskar::Logger.error(message, component: self.class)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Log a fatal message with automatic component detection
|
|
277
|
+
def log_fatal(message)
|
|
278
|
+
Beskar::Logger.fatal(message, component: self.class)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Convenience method to include both class and instance methods
|
|
283
|
+
def self.included(base)
|
|
284
|
+
base.extend(ClassMethods)
|
|
285
|
+
base.include(InstanceMethods)
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|