active_model_logger 0.2.1
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 +7 -0
- data/.rubocop.yml +44 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +55 -0
- data/LICENSE.txt +21 -0
- data/README.md +1215 -0
- data/Rakefile +12 -0
- data/examples/basic_usage.rb +142 -0
- data/examples/log_block_demo.rb +487 -0
- data/examples/stdout_logging_demo.rb +35 -0
- data/identifier.sqlite +0 -0
- data/lib/active_model_logger/block_logger.rb +133 -0
- data/lib/active_model_logger/generators/active_model_logger/install_generator.rb +30 -0
- data/lib/active_model_logger/generators/active_model_logger/templates/README +33 -0
- data/lib/active_model_logger/generators/active_model_logger/templates/create_active_model_logs.rb +34 -0
- data/lib/active_model_logger/json_query_helpers.rb +103 -0
- data/lib/active_model_logger/log.rb +86 -0
- data/lib/active_model_logger/loggable.rb +380 -0
- data/lib/active_model_logger/loggable_helpers.rb +78 -0
- data/lib/active_model_logger/railtie.rb +14 -0
- data/lib/active_model_logger/version.rb +5 -0
- data/lib/active_model_logger.rb +17 -0
- data/sig/ActiveModelLogger.rbs +4 -0
- metadata +211 -0
data/Rakefile
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Basic usage example for ActiveModelLogger
|
4
|
+
# This file demonstrates how to use the gem in a Rails application
|
5
|
+
|
6
|
+
# 1. Include the Loggable concern in your models
|
7
|
+
# This will add the active_model_logs association and logging methods
|
8
|
+
# The logs are stored as Log records and sent to stdout by default
|
9
|
+
class User < ActiveRecord::Base
|
10
|
+
include ActiveModelLogger::Loggable
|
11
|
+
end
|
12
|
+
|
13
|
+
class Order < ActiveRecord::Base
|
14
|
+
include ActiveModelLogger::Loggable
|
15
|
+
end
|
16
|
+
|
17
|
+
# 2. Basic logging with automatic stdout output
|
18
|
+
user = User.find(1)
|
19
|
+
user.log("User logged in") # Will appear in both database and stdout
|
20
|
+
user.log("Payment processed", log_level: "info")
|
21
|
+
|
22
|
+
# 3. Logging with log_chain parameter
|
23
|
+
user.log("Process started", log_chain: "order_processing_123")
|
24
|
+
user.log("Step 1 completed") # Uses cached log_chain
|
25
|
+
user.log("Step 2 completed") # Uses cached log_chain
|
26
|
+
|
27
|
+
# 4. Logging with metadata
|
28
|
+
user.log("Order created",
|
29
|
+
log_level: "info",
|
30
|
+
log_chain: "order_123",
|
31
|
+
metadata: {
|
32
|
+
status: "success",
|
33
|
+
category: "order",
|
34
|
+
order_id: 123,
|
35
|
+
})
|
36
|
+
|
37
|
+
# 5. Logging with custom data field
|
38
|
+
user.log("Payment processed",
|
39
|
+
log_level: "info",
|
40
|
+
metadata: {
|
41
|
+
status: "success",
|
42
|
+
category: "payment",
|
43
|
+
data: {
|
44
|
+
amount: 99.99,
|
45
|
+
currency: "USD",
|
46
|
+
payment_method: "credit_card",
|
47
|
+
transaction_id: "txn_123456",
|
48
|
+
},
|
49
|
+
})
|
50
|
+
|
51
|
+
# 6. Logging with custom visibility
|
52
|
+
user.log("Admin action performed",
|
53
|
+
visible_to: "admin",
|
54
|
+
metadata: { action: "user_suspended" })
|
55
|
+
|
56
|
+
# 7. Working with log chains (automatic caching)
|
57
|
+
# First log generates and caches a UUID
|
58
|
+
user.log("Process started") # Uses: "abc-123-def"
|
59
|
+
|
60
|
+
# Subsequent logs use the cached chain
|
61
|
+
user.log("Step 1 completed") # Uses: "abc-123-def" (cached)
|
62
|
+
user.log("Step 2 completed") # Uses: "abc-123-def" (cached)
|
63
|
+
|
64
|
+
# Explicit log_chain breaks the cache
|
65
|
+
user.log("New process", log_chain: "process_456") # Uses: "process_456"
|
66
|
+
|
67
|
+
# Next logs use the new cached chain
|
68
|
+
user.log("Step A") # Uses: "process_456" (cached)
|
69
|
+
user.log("Step B") # Uses: "process_456" (cached)
|
70
|
+
|
71
|
+
# 8. Batch logging for efficiency
|
72
|
+
user.log_batch([
|
73
|
+
{ message: "Batch step 1", status: "success", log_chain: "batch_123" },
|
74
|
+
{ message: "Batch step 2", status: "success" }, # Uses cached log_chain
|
75
|
+
{ message: "Batch completed", status: "complete" }, # Uses cached log_chain
|
76
|
+
])
|
77
|
+
|
78
|
+
# 8.1. Block-based logging for grouping related operations
|
79
|
+
user.log_block do |logger|
|
80
|
+
logger.log("Process started")
|
81
|
+
logger.log("Step 1 completed", status: "success")
|
82
|
+
logger.log("Step 2 completed", status: "success")
|
83
|
+
logger.log("Process finished", status: "complete")
|
84
|
+
end
|
85
|
+
|
86
|
+
# 8.2. Block logging with custom log chain and metadata
|
87
|
+
user.log_block(log_chain: "order_processing_456", metadata: { category: "order" }) do |logger|
|
88
|
+
logger.log("Order processing started")
|
89
|
+
logger.log("Payment processed", status: "success", amount: 99.99)
|
90
|
+
logger.log("Inventory updated", status: "success", items: 3)
|
91
|
+
logger.log("Order completed", status: "complete")
|
92
|
+
end
|
93
|
+
|
94
|
+
# 8.3. Block logging with custom visibility and log level
|
95
|
+
user.log_block(visible_to: "admin", log_level: "debug") do |logger|
|
96
|
+
logger.log("Admin action started")
|
97
|
+
logger.log("Sensitive operation performed", type: "admin_action")
|
98
|
+
logger.log("Admin action completed")
|
99
|
+
end
|
100
|
+
|
101
|
+
# 9. Accessing logs
|
102
|
+
user.active_model_logs.newest(1).first # Most recent log
|
103
|
+
user.active_model_logs.by_log_chain("process_456").order(:created_at).first # First log in specific chain
|
104
|
+
user.logs # All logs for this user (default limit: 10)
|
105
|
+
user.logs(limit: 5) # Recent logs limited to 5
|
106
|
+
user.logs(log_chain: "process_456") # Logs in specific chain
|
107
|
+
user.logs(log_chain: "process_456", limit: 3) # Logs in specific chain, limited to 3
|
108
|
+
|
109
|
+
# 10. Configuration options
|
110
|
+
class User < ActiveRecord::Base
|
111
|
+
include ActiveModelLogger::Loggable
|
112
|
+
|
113
|
+
# Configure default values
|
114
|
+
configure_loggable(
|
115
|
+
default_visible_to: "user",
|
116
|
+
default_log_level: "debug",
|
117
|
+
stdout_logging: true, # Enable stdout logging (default: true)
|
118
|
+
stdout_logger: Logger.new($stdout) # Custom logger (optional)
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
# 11. Disabling stdout logging
|
123
|
+
class Order < ActiveRecord::Base
|
124
|
+
include ActiveModelLogger::Loggable
|
125
|
+
|
126
|
+
configure_loggable(stdout_logging: false) # Only store in database
|
127
|
+
end
|
128
|
+
|
129
|
+
# 12. Using scopes for querying
|
130
|
+
ActiveModelLogger::Log.by_level("error")
|
131
|
+
ActiveModelLogger::Log.by_visibility("admin")
|
132
|
+
ActiveModelLogger::Log.by_log_chain("process_456")
|
133
|
+
ActiveModelLogger::Log.by_status("success")
|
134
|
+
ActiveModelLogger::Log.by_category("payment")
|
135
|
+
ActiveModelLogger::Log.with_data
|
136
|
+
ActiveModelLogger::Log.newest(10) # Last 10 logs
|
137
|
+
ActiveModelLogger::Log.in_range(1.hour.ago, Time.current)
|
138
|
+
|
139
|
+
# 13. Example output format in stdout:
|
140
|
+
# [2025-09-05 20:58:15] INFO User#123 [chain:abc-123-def] - User logged in (status=success, category=authentication)
|
141
|
+
# [2025-09-05 20:58:16] WARN Order#456 [chain:order-789] - Payment processing started (amount=99.99)
|
142
|
+
# [2025-09-05 20:58:17] ERROR User#123 [chain:abc-123-def] - Payment failed (error=insufficient_funds)
|
@@ -0,0 +1,487 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# This example demonstrates the log_block functionality of ActiveModelLogger
|
5
|
+
# Run this script to see logs being collected during block execution and saved when the block exits
|
6
|
+
|
7
|
+
require "bundler/setup"
|
8
|
+
require "active_record"
|
9
|
+
require "active_support"
|
10
|
+
require "active_support/core_ext"
|
11
|
+
require "logger"
|
12
|
+
|
13
|
+
# Load the gem
|
14
|
+
require_relative "../lib/active_model_logger"
|
15
|
+
|
16
|
+
puts "=== ActiveModelLogger Comprehensive Demo ==="
|
17
|
+
puts "This demo showcases all the latest functionality including log_block, scopes, and advanced features."
|
18
|
+
puts ""
|
19
|
+
|
20
|
+
# Set up a simple in-memory SQLite database for demonstration
|
21
|
+
ActiveRecord::Base.establish_connection(
|
22
|
+
adapter: "sqlite3",
|
23
|
+
database: ":memory:"
|
24
|
+
)
|
25
|
+
|
26
|
+
# Create the logs table
|
27
|
+
ActiveRecord::Base.connection.create_table :active_model_logs do |t|
|
28
|
+
t.references :loggable, polymorphic: true, null: false
|
29
|
+
t.string :message, null: false
|
30
|
+
t.string :log_level, default: "info"
|
31
|
+
t.string :visible_to, default: "user"
|
32
|
+
t.string :log_chain
|
33
|
+
t.json :metadata
|
34
|
+
t.timestamps
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create a simple demo_models table
|
38
|
+
ActiveRecord::Base.connection.create_table :demo_models, &:timestamps
|
39
|
+
|
40
|
+
# Create a custom_demo_models table
|
41
|
+
ActiveRecord::Base.connection.create_table :custom_demo_models, &:timestamps
|
42
|
+
|
43
|
+
# Create a simple model for demonstration
|
44
|
+
class DemoModel < ActiveRecord::Base
|
45
|
+
include ActiveModelLogger::Loggable
|
46
|
+
|
47
|
+
# Configure with stdout logging for demonstration
|
48
|
+
configure_loggable(
|
49
|
+
stdout_logging: true,
|
50
|
+
stdout_logger: Logger.new($stdout)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create a test instance
|
55
|
+
demo = DemoModel.create!(id: 1)
|
56
|
+
|
57
|
+
puts "š Starting Log Block Demonstrations"
|
58
|
+
puts "=" * 50
|
59
|
+
puts ""
|
60
|
+
|
61
|
+
# Demo 1: Basic log_block usage
|
62
|
+
puts "š Demo 1: Basic Log Block"
|
63
|
+
puts "-" * 30
|
64
|
+
puts "Creating a basic log block with multiple log entries..."
|
65
|
+
|
66
|
+
logs = demo.log_block do |logger|
|
67
|
+
logger.log("Process started")
|
68
|
+
sleep(0.1) # Simulate some work
|
69
|
+
logger.log("Step 1 completed", status: "success")
|
70
|
+
sleep(0.1) # Simulate some work
|
71
|
+
logger.log("Step 2 completed", status: "success")
|
72
|
+
sleep(0.1) # Simulate some work
|
73
|
+
logger.log("Process finished", status: "complete")
|
74
|
+
end
|
75
|
+
|
76
|
+
puts "ā
Log block completed! Created #{logs.count} log entries"
|
77
|
+
if logs.any?
|
78
|
+
puts "š Log chain: #{logs.first.metadata['log_chain']}"
|
79
|
+
else
|
80
|
+
puts "ā ļø No logs returned - checking all logs for this model..."
|
81
|
+
all_logs = demo.logs
|
82
|
+
puts "š Total logs in database: #{all_logs.count}"
|
83
|
+
puts "š First log metadata: #{all_logs.first.metadata}" if all_logs.any?
|
84
|
+
end
|
85
|
+
puts ""
|
86
|
+
|
87
|
+
# Demo 2: Custom log_chain and metadata
|
88
|
+
puts "š Demo 2: Custom Log Chain and Metadata"
|
89
|
+
puts "-" * 40
|
90
|
+
puts "Creating a log block with custom parameters..."
|
91
|
+
|
92
|
+
order_logs = demo.log_block(
|
93
|
+
log_chain: "order_processing_123",
|
94
|
+
metadata: { category: "order", order_id: 123 }
|
95
|
+
) do |logger|
|
96
|
+
logger.log("Order processing started")
|
97
|
+
sleep(0.1)
|
98
|
+
logger.log("Payment processed", status: "success", amount: 99.99)
|
99
|
+
sleep(0.1)
|
100
|
+
logger.log("Inventory updated", status: "success", items: 3)
|
101
|
+
sleep(0.1)
|
102
|
+
logger.log("Order completed", status: "complete")
|
103
|
+
end
|
104
|
+
|
105
|
+
puts "ā
Order processing completed! Created #{order_logs.count} log entries"
|
106
|
+
puts "š Log chain: #{order_logs.first.log_chain}"
|
107
|
+
puts "š Category: #{order_logs.first.metadata['category']}"
|
108
|
+
puts ""
|
109
|
+
|
110
|
+
# Demo 3: Custom visibility and log level
|
111
|
+
puts "š Demo 3: Admin Actions with Custom Visibility"
|
112
|
+
puts "-" * 45
|
113
|
+
puts "Creating an admin log block with debug level..."
|
114
|
+
|
115
|
+
admin_logs = demo.log_block(
|
116
|
+
visible_to: "admin",
|
117
|
+
log_level: "debug"
|
118
|
+
) do |logger|
|
119
|
+
logger.log("Admin action started")
|
120
|
+
sleep(0.1)
|
121
|
+
logger.log("Sensitive operation performed", type: "admin_action", user_id: 456)
|
122
|
+
sleep(0.1)
|
123
|
+
logger.log("Admin action completed")
|
124
|
+
end
|
125
|
+
|
126
|
+
puts "ā
Admin action completed! Created #{admin_logs.count} log entries"
|
127
|
+
puts "š Visibility: #{admin_logs.first.visible_to}"
|
128
|
+
puts "š Log level: #{admin_logs.first.log_level}"
|
129
|
+
puts ""
|
130
|
+
|
131
|
+
# Demo 4: Error handling in log blocks
|
132
|
+
puts "š Demo 4: Error Handling in Log Blocks"
|
133
|
+
puts "-" * 40
|
134
|
+
puts "Demonstrating error handling within log blocks..."
|
135
|
+
|
136
|
+
begin
|
137
|
+
demo.log_block(log_chain: "error_demo") do |logger|
|
138
|
+
logger.log("Process started")
|
139
|
+
sleep(0.1)
|
140
|
+
logger.log("Step 1 completed", status: "success")
|
141
|
+
sleep(0.1)
|
142
|
+
logger.log("Step 2 failed", status: "error", error: "simulated_error")
|
143
|
+
sleep(0.1)
|
144
|
+
# Simulate an error
|
145
|
+
raise StandardError, "Something went wrong!"
|
146
|
+
end
|
147
|
+
rescue StandardError => e
|
148
|
+
puts "ā ļø Error caught: #{e.message}"
|
149
|
+
puts "ā
Logs were still saved before the error occurred"
|
150
|
+
end
|
151
|
+
|
152
|
+
puts ""
|
153
|
+
|
154
|
+
# Demo 5: Nested log blocks
|
155
|
+
puts "š Demo 5: Nested Log Blocks"
|
156
|
+
puts "-" * 30
|
157
|
+
puts "Demonstrating nested log blocks..."
|
158
|
+
|
159
|
+
# Track inner logs separately
|
160
|
+
inner_logs = nil
|
161
|
+
|
162
|
+
outer_logs = demo.log_block(log_chain: "outer_process") do |logger|
|
163
|
+
logger.log("Outer process started")
|
164
|
+
sleep(0.1)
|
165
|
+
|
166
|
+
# Nested log block
|
167
|
+
inner_logs = demo.log_block(log_chain: "inner_process") do |inner_logger|
|
168
|
+
inner_logger.log("Inner process started")
|
169
|
+
sleep(0.1)
|
170
|
+
inner_logger.log("Inner process completed")
|
171
|
+
end
|
172
|
+
|
173
|
+
logger.log("Outer process completed")
|
174
|
+
end
|
175
|
+
|
176
|
+
puts "ā
Nested log blocks completed!"
|
177
|
+
puts "š Outer logs: #{outer_logs.count}"
|
178
|
+
puts "š Inner logs: #{inner_logs.count}"
|
179
|
+
puts ""
|
180
|
+
|
181
|
+
# Demo 6: Querying logs from blocks
|
182
|
+
puts "š Demo 6: Querying Logs from Blocks"
|
183
|
+
puts "-" * 35
|
184
|
+
puts "Demonstrating how to query logs created in blocks..."
|
185
|
+
|
186
|
+
# Get all logs for our demo model
|
187
|
+
all_logs = demo.logs(limit: 20)
|
188
|
+
puts "š Total logs created: #{all_logs.count}"
|
189
|
+
|
190
|
+
# Get logs by log_chain
|
191
|
+
order_logs_query = demo.logs(log_chain: "order_processing_123")
|
192
|
+
puts "š Order processing logs: #{order_logs_query.count}"
|
193
|
+
|
194
|
+
# Get logs by visibility
|
195
|
+
admin_logs_query = demo.logs.select { |log| log.visible_to == "admin" }
|
196
|
+
puts "š Admin logs: #{admin_logs_query.count}"
|
197
|
+
|
198
|
+
# Get logs by status
|
199
|
+
success_logs = demo.logs.select { |log| log.metadata&.dig("status") == "success" }
|
200
|
+
puts "š Success logs: #{success_logs.count}"
|
201
|
+
|
202
|
+
puts ""
|
203
|
+
|
204
|
+
# Demo 7: Performance comparison
|
205
|
+
puts "š Demo 7: Performance Comparison"
|
206
|
+
puts "-" * 35
|
207
|
+
puts "Comparing individual logs vs log_block performance..."
|
208
|
+
|
209
|
+
# Individual logs
|
210
|
+
start_time = Time.current
|
211
|
+
10.times do |i|
|
212
|
+
demo.log("Individual log #{i}", metadata: { status: "test" })
|
213
|
+
end
|
214
|
+
individual_time = Time.current - start_time
|
215
|
+
|
216
|
+
# Log block
|
217
|
+
start_time = Time.current
|
218
|
+
demo.log_block(log_chain: "performance_test") do |logger|
|
219
|
+
10.times do |i|
|
220
|
+
logger.log("Block log #{i}", status: "test")
|
221
|
+
end
|
222
|
+
end
|
223
|
+
block_time = Time.current - start_time
|
224
|
+
|
225
|
+
puts "ā±ļø Individual logs time: #{(individual_time * 1000).round(2)}ms"
|
226
|
+
puts "ā±ļø Log block time: #{(block_time * 1000).round(2)}ms"
|
227
|
+
puts "š Performance improvement: #{((individual_time - block_time) / individual_time * 100).round(1)}%"
|
228
|
+
puts ""
|
229
|
+
|
230
|
+
# Demo 8: Advanced Scopes and Querying
|
231
|
+
puts "š Demo 8: Advanced Scopes and Querying"
|
232
|
+
puts "-" * 40
|
233
|
+
puts "Demonstrating the powerful scopes available for querying logs..."
|
234
|
+
|
235
|
+
# Create some diverse logs for querying
|
236
|
+
demo.log("User authentication started", log_level: "info", metadata: { category: "auth", status: "started" })
|
237
|
+
demo.log("Database connection established", log_level: "debug", metadata: { category: "database", status: "success" })
|
238
|
+
demo.log("Payment processing failed", log_level: "error",
|
239
|
+
metadata: { category: "payment", status: "failed", error_code: "INSUFFICIENT_FUNDS" })
|
240
|
+
demo.log("Email sent successfully", log_level: "info",
|
241
|
+
metadata: { category: "notification", status: "sent", recipient: "user@example.com" })
|
242
|
+
demo.log("Cache cleared", log_level: "debug", metadata: { category: "cache", status: "cleared" })
|
243
|
+
demo.log("Security alert triggered", log_level: "warn",
|
244
|
+
metadata: { category: "security", status: "alert", severity: "high" })
|
245
|
+
|
246
|
+
# Add some logs with data for demonstration
|
247
|
+
demo.log("User profile updated", log_level: "info",
|
248
|
+
metadata: { category: "user", status: "success",
|
249
|
+
data: { user_id: 123, changes: %w[email name] } })
|
250
|
+
demo.log("Order created", log_level: "info",
|
251
|
+
metadata: { category: "order", status: "created",
|
252
|
+
data: { order_id: 456, amount: 99.99, currency: "USD" } })
|
253
|
+
demo.log("Admin action", log_level: "info",
|
254
|
+
metadata: { category: "admin", status: "success",
|
255
|
+
data: { user_id: 123, action: "user_created", target_user: 789 } })
|
256
|
+
|
257
|
+
# Add some logs with keys at root level for with_keys demonstration
|
258
|
+
demo.log("User login", log_level: "info",
|
259
|
+
metadata: { user_id: 456, session_id: "abc123", ip_address: "192.168.1.1" })
|
260
|
+
demo.log("Payment processed", log_level: "info",
|
261
|
+
metadata: { order_id: 789, amount: 149.99, status: "completed" })
|
262
|
+
demo.log("System event", log_level: "info",
|
263
|
+
metadata: { event_type: "backup", status: "completed", category: "system" })
|
264
|
+
|
265
|
+
puts "š Total logs created: #{ActiveModelLogger::Log.count}"
|
266
|
+
|
267
|
+
# Demonstrate various scopes
|
268
|
+
puts "\nš Querying by log level:"
|
269
|
+
puts " Info logs: #{ActiveModelLogger::Log.info_logs.count}"
|
270
|
+
puts " Debug logs: #{ActiveModelLogger::Log.debug_logs.count}"
|
271
|
+
puts " Error logs: #{ActiveModelLogger::Log.error_logs.count}"
|
272
|
+
puts " Warning logs: #{ActiveModelLogger::Log.warning_logs.count}"
|
273
|
+
|
274
|
+
puts "\nš Querying by category:"
|
275
|
+
puts " Auth logs: #{ActiveModelLogger::Log.by_category('auth').count}"
|
276
|
+
puts " Payment logs: #{ActiveModelLogger::Log.by_category('payment').count}"
|
277
|
+
puts " Database logs: #{ActiveModelLogger::Log.by_category('database').count}"
|
278
|
+
|
279
|
+
puts "\nš Querying by status:"
|
280
|
+
puts " Success logs: #{ActiveModelLogger::Log.by_status('success').count}"
|
281
|
+
puts " Failed logs: #{ActiveModelLogger::Log.by_status('failed').count}"
|
282
|
+
|
283
|
+
puts "\nš Querying with data:"
|
284
|
+
puts " Logs with data: #{ActiveModelLogger::Log.with_data.count}"
|
285
|
+
|
286
|
+
puts "\nš Recent logs:"
|
287
|
+
recent_logs = ActiveModelLogger::Log.newest(3)
|
288
|
+
recent_logs.each_with_index do |log, index|
|
289
|
+
puts " #{index + 1}. [#{log.log_level.upcase}] #{log.message} (#{log.metadata['category']})"
|
290
|
+
end
|
291
|
+
|
292
|
+
puts ""
|
293
|
+
|
294
|
+
# Demo 9: Log Chain Management
|
295
|
+
puts "š Demo 9: Log Chain Management"
|
296
|
+
puts "-" * 35
|
297
|
+
puts "Demonstrating automatic log chain management..."
|
298
|
+
|
299
|
+
# Create logs with automatic chain management
|
300
|
+
demo.log("Process A started")
|
301
|
+
demo.log("Process A step 1 completed", metadata: { status: "success" })
|
302
|
+
demo.log("Process A step 2 completed", metadata: { status: "success" })
|
303
|
+
|
304
|
+
# Start a new process (new chain)
|
305
|
+
demo.log("Process B started", log_chain: "process_b_123")
|
306
|
+
demo.log("Process B step 1 completed", metadata: { status: "success" })
|
307
|
+
demo.log("Process B step 2 completed", metadata: { status: "success" })
|
308
|
+
|
309
|
+
# Continue with Process A (should use cached chain)
|
310
|
+
demo.log("Process A step 3 completed", metadata: { status: "success" })
|
311
|
+
demo.log("Process A finished", metadata: { status: "complete" })
|
312
|
+
|
313
|
+
puts "š Current log chain: #{demo.log_chain}"
|
314
|
+
puts "š Most recent log chain: #{demo.most_recent_log_chain}"
|
315
|
+
|
316
|
+
# Query by log chain
|
317
|
+
process_a_logs = demo.logs(log_chain: demo.most_recent_log_chain)
|
318
|
+
puts "š Process A logs: #{process_a_logs.count}"
|
319
|
+
|
320
|
+
process_b_logs = demo.logs(log_chain: "process_b_123")
|
321
|
+
puts "š Process B logs: #{process_b_logs.count}"
|
322
|
+
|
323
|
+
puts ""
|
324
|
+
|
325
|
+
# Demo 10: Batch Logging
|
326
|
+
puts "š Demo 10: Batch Logging"
|
327
|
+
puts "-" * 30
|
328
|
+
puts "Demonstrating efficient batch logging..."
|
329
|
+
|
330
|
+
batch_entries = [
|
331
|
+
{ message: "Batch step 1", metadata: { status: "success", category: "batch" } },
|
332
|
+
{ message: "Batch step 2", metadata: { status: "success", category: "batch" } },
|
333
|
+
{ message: "Batch step 3", metadata: { status: "success", category: "batch" } },
|
334
|
+
{ message: "Batch completed", metadata: { status: "complete", category: "batch" } },
|
335
|
+
]
|
336
|
+
|
337
|
+
batch_logs = demo.log_batch(batch_entries)
|
338
|
+
puts "ā
Batch logging completed! Created #{batch_logs.count} log entries"
|
339
|
+
puts "š Batch log chain: #{batch_logs.first.metadata['log_chain']}"
|
340
|
+
|
341
|
+
puts ""
|
342
|
+
|
343
|
+
# Demo 11: Log Cleanup
|
344
|
+
puts "š Demo 11: Log Cleanup"
|
345
|
+
puts "-" * 25
|
346
|
+
puts "Demonstrating log cleanup functionality..."
|
347
|
+
|
348
|
+
# Create some old logs (simulate by setting created_at in the past)
|
349
|
+
old_log = ActiveModelLogger::Log.create!(
|
350
|
+
loggable: demo,
|
351
|
+
message: "Old log entry",
|
352
|
+
metadata: { log_chain: "old_chain", status: "old", category: "cleanup" },
|
353
|
+
created_at: 35.days.ago,
|
354
|
+
updated_at: 35.days.ago
|
355
|
+
)
|
356
|
+
|
357
|
+
puts "š Logs before cleanup: #{ActiveModelLogger::Log.count}"
|
358
|
+
|
359
|
+
# Cleanup logs older than 30 days, keeping 100 recent
|
360
|
+
demo.cleanup_logs(older_than: 30.days, keep_recent: 100)
|
361
|
+
|
362
|
+
puts "š Logs after cleanup: #{ActiveModelLogger::Log.count}"
|
363
|
+
puts "ā
Old log cleaned up: #{ActiveModelLogger::Log.find_by(id: old_log.id).nil?}"
|
364
|
+
|
365
|
+
puts ""
|
366
|
+
|
367
|
+
# Demo 12: Model-Level Querying
|
368
|
+
puts "š Demo 12: Model-Level Querying"
|
369
|
+
puts "-" * 35
|
370
|
+
puts "Demonstrating model-level querying methods..."
|
371
|
+
|
372
|
+
# Get current log
|
373
|
+
current = demo.active_model_logs.newest(1).first
|
374
|
+
puts "š Current log: #{current&.message} (#{current&.metadata&.dig('category')})"
|
375
|
+
|
376
|
+
# Get root log for a specific chain (using oldest scope)
|
377
|
+
root_log = demo.logs(log_chain: "process_b_123").oldest(1).first
|
378
|
+
puts "š Root log for process_b_123: #{root_log&.message}"
|
379
|
+
|
380
|
+
# Get logs with custom limit
|
381
|
+
recent_five = demo.logs(limit: 5)
|
382
|
+
puts "š Recent 5 logs: #{recent_five.count}"
|
383
|
+
|
384
|
+
# Get logs for specific chain
|
385
|
+
chain_logs = demo.logs(log_chain: "process_b_123")
|
386
|
+
puts "š Process B chain logs: #{chain_logs.count}"
|
387
|
+
|
388
|
+
# Demonstrate ordering scopes
|
389
|
+
puts "š Oldest 3 logs: #{demo.active_model_logs.oldest(3).pluck(:message).join(', ')}"
|
390
|
+
puts "š Newest 3 logs: #{demo.active_model_logs.newest(3).pluck(:message).join(', ')}"
|
391
|
+
|
392
|
+
# Demonstrate with_data scope with hash parameter
|
393
|
+
puts "\nš Data Querying Examples:"
|
394
|
+
puts "š Logs with data: #{demo.active_model_logs.with_data.count}"
|
395
|
+
puts "š Logs with user_id 123: #{demo.active_model_logs.with_data({ user_id: 123 }).count}"
|
396
|
+
puts "š Logs with order_id 456: #{demo.active_model_logs.with_data({ order_id: 456 }).count}"
|
397
|
+
|
398
|
+
# Demonstrate with_keys scope
|
399
|
+
puts "\nš Key Querying Examples:"
|
400
|
+
puts "š Logs with user_id key: #{demo.active_model_logs.with_keys('user_id').count}"
|
401
|
+
puts "š Logs with category key: #{demo.active_model_logs.with_keys('category').count}"
|
402
|
+
puts "š Logs with both user_id and category: #{demo.active_model_logs.with_keys('user_id', 'category').count}"
|
403
|
+
|
404
|
+
puts ""
|
405
|
+
|
406
|
+
# Demo 13: Configuration Options
|
407
|
+
puts "š Demo 13: Configuration Options"
|
408
|
+
puts "-" * 35
|
409
|
+
puts "Demonstrating different configuration options..."
|
410
|
+
|
411
|
+
# Create a model with custom configuration
|
412
|
+
class CustomDemoModel < ActiveRecord::Base
|
413
|
+
include ActiveModelLogger::Loggable
|
414
|
+
|
415
|
+
# Custom configuration
|
416
|
+
configure_loggable(
|
417
|
+
default_visible_to: "system",
|
418
|
+
default_log_level: "debug",
|
419
|
+
stdout_logging: false # Disable stdout for this demo
|
420
|
+
)
|
421
|
+
end
|
422
|
+
|
423
|
+
custom_demo = CustomDemoModel.create!(id: 2)
|
424
|
+
|
425
|
+
# Test custom configuration
|
426
|
+
custom_demo.log("System process started")
|
427
|
+
custom_demo.log("System process completed", metadata: { status: "success" })
|
428
|
+
|
429
|
+
puts "š Custom model logs: #{custom_demo.logs.count}"
|
430
|
+
puts "š Custom model visibility: #{custom_demo.logs.first.metadata['visible_to']}"
|
431
|
+
puts "š Custom model log level: #{custom_demo.logs.first.metadata['log_level']}"
|
432
|
+
|
433
|
+
puts ""
|
434
|
+
|
435
|
+
# Summary
|
436
|
+
puts "š Comprehensive Demo Complete!"
|
437
|
+
puts "=" * 30
|
438
|
+
puts ""
|
439
|
+
puts "š ActiveModelLogger Features Demonstrated:"
|
440
|
+
puts ""
|
441
|
+
puts "š¦ Core Logging:"
|
442
|
+
puts "⢠ā
Individual logging with metadata"
|
443
|
+
puts "⢠ā
Batch logging for performance"
|
444
|
+
puts "⢠ā
Log block for atomic operations"
|
445
|
+
puts "⢠ā
Automatic log chain management"
|
446
|
+
puts "⢠ā
Custom configuration per model"
|
447
|
+
puts ""
|
448
|
+
puts "š Advanced Querying:"
|
449
|
+
puts "⢠ā
Query by log level (debug, info, warn, error, fatal)"
|
450
|
+
puts "⢠ā
Query by category, status, type"
|
451
|
+
puts "⢠ā
Query by log chain for related operations"
|
452
|
+
puts "⢠ā
Query logs with data/metadata"
|
453
|
+
puts "⢠ā
Recent logs with custom limits"
|
454
|
+
puts "⢠ā
Time-based range queries"
|
455
|
+
puts ""
|
456
|
+
puts "ā” Performance Features:"
|
457
|
+
puts "⢠ā
Batch insertion with insert_all (ActiveRecord 6.0+)"
|
458
|
+
puts "⢠ā
Automatic log cleanup"
|
459
|
+
puts "⢠ā
Efficient scopes for large datasets"
|
460
|
+
puts "⢠ā
Database-agnostic JSON queries"
|
461
|
+
puts ""
|
462
|
+
puts "š ļø Developer Experience:"
|
463
|
+
puts "⢠ā
Stdout logging with formatted output"
|
464
|
+
puts "⢠ā
Error handling and validation"
|
465
|
+
puts "⢠ā
Nested log blocks support"
|
466
|
+
puts "⢠ā
Flexible metadata system"
|
467
|
+
puts "⢠ā
Model-level querying methods"
|
468
|
+
puts ""
|
469
|
+
puts "šÆ Perfect for:"
|
470
|
+
puts "⢠š E-commerce order processing"
|
471
|
+
puts "⢠š User authentication and authorization"
|
472
|
+
puts "⢠š Data processing pipelines"
|
473
|
+
puts "⢠š Background job execution"
|
474
|
+
puts "⢠š§ Admin operations and maintenance"
|
475
|
+
puts "⢠š Comprehensive audit trails"
|
476
|
+
puts "⢠š Application debugging and monitoring"
|
477
|
+
puts "⢠š Performance tracking and analytics"
|
478
|
+
puts ""
|
479
|
+
puts "š Getting Started:"
|
480
|
+
puts "1. Include ActiveModelLogger::Loggable in your models"
|
481
|
+
puts "2. Configure logging options per model"
|
482
|
+
puts "3. Use log_block for grouping related operations"
|
483
|
+
puts "4. Query logs using powerful scopes and methods"
|
484
|
+
puts "5. Set up log cleanup for production environments"
|
485
|
+
puts ""
|
486
|
+
puts "š For more information, see the gem documentation and examples!"
|
487
|
+
puts ""
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# This example demonstrates the stdout logging functionality of ActiveModelLogger
|
5
|
+
# Run this script to see logs being output to both database and standard output
|
6
|
+
#
|
7
|
+
# Note: This example requires a Rails application with the gem installed.
|
8
|
+
# For a working demo, see the active_model_logger_demo project.
|
9
|
+
|
10
|
+
puts "=== ActiveModelLogger Stdout Logging Demo ==="
|
11
|
+
puts "This demo shows logs being sent to both database and standard output."
|
12
|
+
puts ""
|
13
|
+
puts "To see this in action, run the demo project:"
|
14
|
+
puts " cd active_model_logger_demo"
|
15
|
+
puts " bundle install"
|
16
|
+
puts " rails db:migrate"
|
17
|
+
puts " rails server"
|
18
|
+
puts " # Then visit http://localhost:3000 and click 'Create Demo Data'"
|
19
|
+
puts ""
|
20
|
+
puts "Or run the test script:"
|
21
|
+
puts " ruby test_logging.rb"
|
22
|
+
puts ""
|
23
|
+
puts "The stdout logging feature provides:"
|
24
|
+
puts "⢠Formatted log messages sent to standard output"
|
25
|
+
puts "⢠Configurable logging levels (debug, info, warn, error, fatal)"
|
26
|
+
puts "⢠Log chain information in the output"
|
27
|
+
puts "⢠Metadata display in the logs"
|
28
|
+
puts "⢠Custom logger support"
|
29
|
+
puts "⢠Ability to disable stdout logging per model"
|
30
|
+
puts ""
|
31
|
+
puts "Example output format:"
|
32
|
+
puts "[2025-09-05 20:58:15] INFO User#123 [chain:abc-123-def] - User logged in " \
|
33
|
+
"(status=success, category=authentication)"
|
34
|
+
puts "[2025-09-05 20:58:16] WARN Order#456 [chain:order-789] - Payment processing started (amount=99.99)"
|
35
|
+
puts "[2025-09-05 20:58:17] ERROR User#123 [chain:abc-123-def] - Payment failed (error=insufficient_funds)"
|
data/identifier.sqlite
ADDED
File without changes
|