smart_message 0.0.2 ā 0.0.4
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 +31 -1
- data/Gemfile.lock +6 -1
- data/README.md +92 -14
- data/docs/README.md +1 -0
- data/docs/architecture.md +41 -8
- data/docs/dispatcher.md +52 -16
- data/docs/getting-started.md +64 -2
- data/docs/logging.md +452 -0
- data/docs/message_processing.md +423 -0
- data/docs/proc_handlers_summary.md +247 -0
- data/docs/transports.md +202 -8
- data/examples/.gitignore +2 -0
- data/examples/04_redis_smart_home_iot.rb +649 -0
- data/examples/05_proc_handlers.rb +181 -0
- data/examples/06_custom_logger_example.rb +620 -0
- data/examples/README.md +118 -3
- data/examples/smart_home_iot_dataflow.md +257 -0
- data/lib/smart_message/base.rb +94 -4
- data/lib/smart_message/dispatcher.rb +22 -6
- data/lib/smart_message/logger/default.rb +217 -0
- data/lib/smart_message/logger.rb +9 -1
- data/lib/smart_message/transport/redis_transport.rb +190 -0
- data/lib/smart_message/transport/registry.rb +1 -0
- data/lib/smart_message/transport.rb +1 -0
- data/lib/smart_message/version.rb +1 -1
- data/smart_message.gemspec +1 -0
- metadata +25 -1
@@ -0,0 +1,620 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/06_custom_logger_example.rb
|
3
|
+
#
|
4
|
+
# Custom Logger Example: Comprehensive Message Logging
|
5
|
+
#
|
6
|
+
# This example demonstrates how to implement and use custom loggers in the SmartMessage
|
7
|
+
# framework. It shows different logging strategies including file logging, structured
|
8
|
+
# logging, and audit trails for message processing workflows.
|
9
|
+
#
|
10
|
+
# IMPORTANT: Using the Default Logger or Custom Loggers
|
11
|
+
# ====================================================================
|
12
|
+
# SmartMessage now includes a DEFAULT LOGGER that automatically detects your environment:
|
13
|
+
# - Uses Rails.logger if running in a Rails application
|
14
|
+
# - Uses Ruby's standard Logger otherwise (logs to log/smart_message.log)
|
15
|
+
#
|
16
|
+
# To use the default logger (EASIEST OPTION):
|
17
|
+
# config do
|
18
|
+
# logger SmartMessage::Logger::Default.new
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# To use the default logger with custom settings:
|
22
|
+
# config do
|
23
|
+
# logger SmartMessage::Logger::Default.new(
|
24
|
+
# log_file: 'custom/path.log',
|
25
|
+
# level: Logger::DEBUG
|
26
|
+
# )
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# To log to STDOUT (useful for Docker/Kubernetes):
|
30
|
+
# config do
|
31
|
+
# logger SmartMessage::Logger::Default.new(
|
32
|
+
# log_file: STDOUT,
|
33
|
+
# level: Logger::INFO
|
34
|
+
# )
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# To create your own custom logger:
|
38
|
+
# 1. Create a wrapper class that inherits from SmartMessage::Logger::Base
|
39
|
+
# 2. Store the Ruby logger instance in your wrapper
|
40
|
+
# 3. Implement the SmartMessage logging methods using your Ruby logger
|
41
|
+
#
|
42
|
+
# To use Rails.logger directly (without the default logger):
|
43
|
+
# 1. Create a wrapper that delegates to Rails.logger
|
44
|
+
# 2. Configure it at the class level: logger SmartMessage::Logger::RailsLogger.new
|
45
|
+
# 3. All messages will be logged to your Rails application logs
|
46
|
+
|
47
|
+
require_relative '../lib/smart_message'
|
48
|
+
require 'logger'
|
49
|
+
require 'json'
|
50
|
+
require 'fileutils'
|
51
|
+
|
52
|
+
puts "=== SmartMessage Example: Custom Logger Implementation ==="
|
53
|
+
puts
|
54
|
+
|
55
|
+
# Custom File Logger Implementation
|
56
|
+
# This wrapper shows how to integrate Ruby's standard Logger class with SmartMessage.
|
57
|
+
# The same pattern works for Rails.logger, Semantic Logger, or any Ruby logger.
|
58
|
+
class SmartMessage::Logger::FileLogger < SmartMessage::Logger::Base
|
59
|
+
attr_reader :log_file_path, :logger
|
60
|
+
|
61
|
+
def initialize(log_file_path, level: Logger::INFO)
|
62
|
+
@log_file_path = log_file_path
|
63
|
+
|
64
|
+
# Ensure log directory exists
|
65
|
+
FileUtils.mkdir_p(File.dirname(@log_file_path))
|
66
|
+
|
67
|
+
# This is Ruby's standard Logger class from the 'logger' library
|
68
|
+
# You could replace this with Rails.logger or any other logger:
|
69
|
+
# @logger = Rails.logger # For Rails applications
|
70
|
+
# @logger = SemanticLogger['SmartMessage'] # For Semantic Logger
|
71
|
+
# @logger = $stdout.sync = Logger.new($stdout) # For stdout logging
|
72
|
+
@logger = Logger.new(@log_file_path)
|
73
|
+
@logger.level = level
|
74
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
75
|
+
"[#{datetime.strftime('%Y-%m-%d %H:%M:%S.%3N')}] #{severity}: #{msg}\n"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def log_message_created(message)
|
80
|
+
@logger.info("MESSAGE_CREATED: #{message.class.name} - #{message.to_h}")
|
81
|
+
end
|
82
|
+
|
83
|
+
def log_message_published(message, transport)
|
84
|
+
@logger.info("MESSAGE_PUBLISHED: #{message.class.name} via #{transport.class.name}")
|
85
|
+
end
|
86
|
+
|
87
|
+
def log_message_received(message_class, payload)
|
88
|
+
@logger.info("MESSAGE_RECEIVED: #{message_class.name} - #{payload}")
|
89
|
+
end
|
90
|
+
|
91
|
+
def log_message_processed(message_class, result)
|
92
|
+
@logger.info("MESSAGE_PROCESSED: #{message_class.name} - Result: #{result}")
|
93
|
+
end
|
94
|
+
|
95
|
+
def log_error(message, error)
|
96
|
+
@logger.error("MESSAGE_ERROR: #{message} - #{error.class.name}: #{error.message}")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Structured JSON Logger Implementation
|
101
|
+
class SmartMessage::Logger::JSONLogger < SmartMessage::Logger::Base
|
102
|
+
attr_reader :log_file_path
|
103
|
+
|
104
|
+
def initialize(log_file_path)
|
105
|
+
@log_file_path = log_file_path
|
106
|
+
|
107
|
+
# Ensure log directory exists
|
108
|
+
FileUtils.mkdir_p(File.dirname(@log_file_path))
|
109
|
+
end
|
110
|
+
|
111
|
+
def log_message_created(message)
|
112
|
+
write_log_entry({
|
113
|
+
event: 'message_created',
|
114
|
+
message_class: message.class.name,
|
115
|
+
message_id: message._sm_header&.message_id,
|
116
|
+
timestamp: Time.now.iso8601,
|
117
|
+
data: message.to_h
|
118
|
+
})
|
119
|
+
end
|
120
|
+
|
121
|
+
def log_message_published(message, transport)
|
122
|
+
write_log_entry({
|
123
|
+
event: 'message_published',
|
124
|
+
message_class: message.class.name,
|
125
|
+
message_id: message._sm_header&.message_id,
|
126
|
+
transport: transport.class.name,
|
127
|
+
timestamp: Time.now.iso8601
|
128
|
+
})
|
129
|
+
end
|
130
|
+
|
131
|
+
def log_message_received(message_class, payload)
|
132
|
+
write_log_entry({
|
133
|
+
event: 'message_received',
|
134
|
+
message_class: message_class.name,
|
135
|
+
payload_size: payload.length,
|
136
|
+
timestamp: Time.now.iso8601
|
137
|
+
})
|
138
|
+
end
|
139
|
+
|
140
|
+
def log_message_processed(message_class, result)
|
141
|
+
write_log_entry({
|
142
|
+
event: 'message_processed',
|
143
|
+
message_class: message_class.name,
|
144
|
+
result: result.to_s,
|
145
|
+
timestamp: Time.now.iso8601
|
146
|
+
})
|
147
|
+
end
|
148
|
+
|
149
|
+
def log_error(message, error)
|
150
|
+
write_log_entry({
|
151
|
+
event: 'error',
|
152
|
+
message: message.to_s,
|
153
|
+
error_class: error.class.name,
|
154
|
+
error_message: error.message,
|
155
|
+
backtrace: error.backtrace&.first(5),
|
156
|
+
timestamp: Time.now.iso8601
|
157
|
+
})
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def write_log_entry(data)
|
163
|
+
File.open(@log_file_path, 'a') do |file|
|
164
|
+
file.puts(JSON.generate(data))
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Console Logger with Emoji Implementation
|
170
|
+
class SmartMessage::Logger::EmojiConsoleLogger < SmartMessage::Logger::Base
|
171
|
+
def log_message_created(message)
|
172
|
+
puts "šļø Created: #{message.class.name} with data: #{message.to_h}"
|
173
|
+
end
|
174
|
+
|
175
|
+
def log_message_published(message, transport)
|
176
|
+
puts "š¤ Published: #{message.class.name} via #{transport.class.name}"
|
177
|
+
end
|
178
|
+
|
179
|
+
def log_message_received(message_class, payload)
|
180
|
+
puts "š„ Received: #{message_class.name} (#{payload.length} bytes)"
|
181
|
+
end
|
182
|
+
|
183
|
+
def log_message_processed(message_class, result)
|
184
|
+
puts "āļø Processed: #{message_class.name} ā #{result}"
|
185
|
+
end
|
186
|
+
|
187
|
+
def log_error(message, error)
|
188
|
+
puts "ā Error: #{message} ā #{error.class.name}: #{error.message}"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Example: Simple Ruby Logger Wrapper
|
193
|
+
# This demonstrates the minimal wrapper needed for Ruby's standard Logger.
|
194
|
+
# Use this pattern when you want to integrate with existing logging infrastructure.
|
195
|
+
class SmartMessage::Logger::RubyLoggerWrapper < SmartMessage::Logger::Base
|
196
|
+
def initialize(ruby_logger = nil)
|
197
|
+
# Accept any Ruby logger instance, or create a default one
|
198
|
+
@logger = ruby_logger || Logger.new(STDOUT)
|
199
|
+
end
|
200
|
+
|
201
|
+
def log_message_created(message)
|
202
|
+
@logger.debug { "SmartMessage created: #{message.class.name} ID: #{message._sm_header&.message_id}" }
|
203
|
+
end
|
204
|
+
|
205
|
+
def log_message_published(message, transport)
|
206
|
+
@logger.info { "SmartMessage published: #{message.class.name} via #{transport.class.name}" }
|
207
|
+
end
|
208
|
+
|
209
|
+
def log_message_received(message_class, payload)
|
210
|
+
@logger.info { "SmartMessage received: #{message_class.name}" }
|
211
|
+
end
|
212
|
+
|
213
|
+
def log_message_processed(message_class, result)
|
214
|
+
@logger.info { "SmartMessage processed: #{message_class.name}" }
|
215
|
+
end
|
216
|
+
|
217
|
+
def log_error(message, error)
|
218
|
+
@logger.error { "SmartMessage error: #{message} - #{error.message}" }
|
219
|
+
@logger.debug { error.backtrace.join("\n") }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Example: Rails Logger Wrapper (for Rails applications)
|
224
|
+
# Uncomment and use this in your Rails application
|
225
|
+
# class SmartMessage::Logger::RailsLogger < SmartMessage::Logger::Base
|
226
|
+
# def log_message_created(message)
|
227
|
+
# Rails.logger.tagged('SmartMessage', message.class.name) do
|
228
|
+
# Rails.logger.info "Message created with ID: #{message._sm_header&.message_id}"
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# def log_message_published(message, transport)
|
233
|
+
# Rails.logger.tagged('SmartMessage', message.class.name) do
|
234
|
+
# Rails.logger.info "Message published via #{transport.class.name}"
|
235
|
+
# end
|
236
|
+
# end
|
237
|
+
#
|
238
|
+
# def log_message_received(message_class, payload)
|
239
|
+
# Rails.logger.tagged('SmartMessage', message_class.name) do
|
240
|
+
# Rails.logger.info "Message received (#{payload.length} bytes)"
|
241
|
+
# end
|
242
|
+
# end
|
243
|
+
#
|
244
|
+
# def log_message_processed(message_class, result)
|
245
|
+
# Rails.logger.tagged('SmartMessage', message_class.name) do
|
246
|
+
# Rails.logger.info "Message processed successfully"
|
247
|
+
# end
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
# def log_error(message, error)
|
251
|
+
# Rails.logger.tagged('SmartMessage') do
|
252
|
+
# Rails.logger.error "Error: #{message}"
|
253
|
+
# Rails.logger.error "#{error.class.name}: #{error.message}"
|
254
|
+
# Rails.logger.debug error.backtrace.join("\n")
|
255
|
+
# end
|
256
|
+
# end
|
257
|
+
# end
|
258
|
+
|
259
|
+
# Multi-logger that broadcasts to multiple loggers
|
260
|
+
class SmartMessage::Logger::MultiLogger < SmartMessage::Logger::Base
|
261
|
+
def initialize(*loggers)
|
262
|
+
@loggers = loggers
|
263
|
+
end
|
264
|
+
|
265
|
+
def log_message_created(message)
|
266
|
+
@loggers.each { |logger| logger.log_message_created(message) }
|
267
|
+
end
|
268
|
+
|
269
|
+
def log_message_published(message, transport)
|
270
|
+
@loggers.each { |logger| logger.log_message_published(message, transport) }
|
271
|
+
end
|
272
|
+
|
273
|
+
def log_message_received(message_class, payload)
|
274
|
+
@loggers.each { |logger| logger.log_message_received(message_class, payload) }
|
275
|
+
end
|
276
|
+
|
277
|
+
def log_message_processed(message_class, result)
|
278
|
+
@loggers.each { |logger| logger.log_message_processed(message_class, result) }
|
279
|
+
end
|
280
|
+
|
281
|
+
def log_error(message, error)
|
282
|
+
@loggers.each { |logger| logger.log_error(message, error) }
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# Sample message class with comprehensive logging
|
287
|
+
class OrderProcessingMessage < SmartMessage::Base
|
288
|
+
property :order_id
|
289
|
+
property :customer_id
|
290
|
+
property :amount
|
291
|
+
property :status
|
292
|
+
property :items
|
293
|
+
|
294
|
+
config do
|
295
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
296
|
+
serializer SmartMessage::Serializer::JSON.new
|
297
|
+
|
298
|
+
# Configure multi-logger to demonstrate different logging approaches
|
299
|
+
logger SmartMessage::Logger::MultiLogger.new(
|
300
|
+
SmartMessage::Logger::EmojiConsoleLogger.new,
|
301
|
+
SmartMessage::Logger::FileLogger.new('logs/order_processing.log', level: Logger::DEBUG),
|
302
|
+
SmartMessage::Logger::JSONLogger.new('logs/order_processing.json')
|
303
|
+
)
|
304
|
+
end
|
305
|
+
|
306
|
+
def self.process(message_header, message_payload)
|
307
|
+
# Simulate the logger being called during processing
|
308
|
+
if logger
|
309
|
+
logger.log_message_received(self, message_payload)
|
310
|
+
end
|
311
|
+
|
312
|
+
# Process the message
|
313
|
+
order_data = JSON.parse(message_payload)
|
314
|
+
result = "Order #{order_data['order_id']} processed successfully"
|
315
|
+
|
316
|
+
puts "š¼ OrderProcessing: #{result}"
|
317
|
+
|
318
|
+
# Log processing completion
|
319
|
+
if logger
|
320
|
+
logger.log_message_processed(self, result)
|
321
|
+
end
|
322
|
+
|
323
|
+
result
|
324
|
+
end
|
325
|
+
|
326
|
+
# Override publish to demonstrate logging hooks
|
327
|
+
def publish
|
328
|
+
# Log message creation
|
329
|
+
logger_instance = logger || self.class.logger
|
330
|
+
if logger_instance
|
331
|
+
logger_instance.log_message_created(self)
|
332
|
+
end
|
333
|
+
|
334
|
+
# Log publishing
|
335
|
+
transport_instance = transport || self.class.transport
|
336
|
+
if logger_instance
|
337
|
+
logger_instance.log_message_published(self, transport_instance)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Call original publish method
|
341
|
+
super
|
342
|
+
rescue => error
|
343
|
+
# Log any errors during publishing
|
344
|
+
if logger_instance
|
345
|
+
logger_instance.log_error("Failed to publish #{self.class.name}", error)
|
346
|
+
end
|
347
|
+
raise
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# Notification message with different logger configuration
|
352
|
+
class NotificationMessage < SmartMessage::Base
|
353
|
+
property :recipient
|
354
|
+
property :subject
|
355
|
+
property :body
|
356
|
+
property :priority
|
357
|
+
|
358
|
+
config do
|
359
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
360
|
+
serializer SmartMessage::Serializer::JSON.new
|
361
|
+
|
362
|
+
# Use only file logger for notifications
|
363
|
+
logger SmartMessage::Logger::FileLogger.new('logs/notifications.log', level: Logger::WARN)
|
364
|
+
end
|
365
|
+
|
366
|
+
def self.process(message_header, message_payload)
|
367
|
+
if logger
|
368
|
+
logger.log_message_received(self, message_payload)
|
369
|
+
end
|
370
|
+
|
371
|
+
notification_data = JSON.parse(message_payload)
|
372
|
+
result = "Notification sent to #{notification_data['recipient']}"
|
373
|
+
|
374
|
+
puts "š¬ Notification: #{result}"
|
375
|
+
|
376
|
+
if logger
|
377
|
+
logger.log_message_processed(self, result)
|
378
|
+
end
|
379
|
+
|
380
|
+
result
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# Example: Message class using standard Ruby logger
|
385
|
+
# This demonstrates how to use Ruby's standard Logger in production code
|
386
|
+
class StandardLoggerMessage < SmartMessage::Base
|
387
|
+
property :content
|
388
|
+
property :level
|
389
|
+
|
390
|
+
config do
|
391
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
392
|
+
serializer SmartMessage::Serializer::JSON.new
|
393
|
+
|
394
|
+
# Example 1: Using Ruby's standard Logger directly
|
395
|
+
# Create a standard Ruby logger that logs to STDOUT
|
396
|
+
ruby_logger = Logger.new(STDOUT)
|
397
|
+
ruby_logger.level = Logger::INFO
|
398
|
+
ruby_logger.progname = 'SmartMessage'
|
399
|
+
|
400
|
+
# Wrap it in our adapter
|
401
|
+
logger SmartMessage::Logger::RubyLoggerWrapper.new(ruby_logger)
|
402
|
+
|
403
|
+
# Example 2: Using a file-based Ruby logger (commented out)
|
404
|
+
# file_logger = Logger.new('application.log', 'daily') # Rotate daily
|
405
|
+
# logger SmartMessage::Logger::RubyLoggerWrapper.new(file_logger)
|
406
|
+
|
407
|
+
# Example 3: In Rails, you would use Rails.logger (commented out)
|
408
|
+
# logger SmartMessage::Logger::RubyLoggerWrapper.new(Rails.logger)
|
409
|
+
end
|
410
|
+
|
411
|
+
def self.process(message_header, message_payload)
|
412
|
+
data = JSON.parse(message_payload)
|
413
|
+
puts "š Processing: #{data['content']}"
|
414
|
+
"Processed"
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
# Example: Message using the built-in Default Logger
|
419
|
+
class DefaultLoggerMessage < SmartMessage::Base
|
420
|
+
property :message
|
421
|
+
property :level
|
422
|
+
|
423
|
+
config do
|
424
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
425
|
+
serializer SmartMessage::Serializer::JSON.new
|
426
|
+
|
427
|
+
# Use the built-in default logger - simplest option!
|
428
|
+
logger SmartMessage::Logger::Default.new
|
429
|
+
end
|
430
|
+
|
431
|
+
def self.process(message_header, message_payload)
|
432
|
+
data = JSON.parse(message_payload)
|
433
|
+
puts "šÆ DefaultLogger: Processing #{data['message']}"
|
434
|
+
"Processed with default logger"
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
# Service that uses instance-level logger override
|
439
|
+
class PriorityOrderService
|
440
|
+
def initialize
|
441
|
+
puts "š PriorityOrderService: Starting with custom logger..."
|
442
|
+
|
443
|
+
# Create a priority-specific logger
|
444
|
+
@priority_logger = SmartMessage::Logger::FileLogger.new(
|
445
|
+
'logs/priority_orders.log',
|
446
|
+
level: Logger::DEBUG
|
447
|
+
)
|
448
|
+
end
|
449
|
+
|
450
|
+
def process_priority_order(order_data)
|
451
|
+
# Create message with instance-level logger override
|
452
|
+
message = OrderProcessingMessage.new(**order_data)
|
453
|
+
|
454
|
+
# Override the logger at instance level
|
455
|
+
message.logger(@priority_logger)
|
456
|
+
|
457
|
+
puts "ā” Processing priority order with dedicated logger"
|
458
|
+
message.publish
|
459
|
+
|
460
|
+
message
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
# Demo runner
|
465
|
+
class LoggerDemo
|
466
|
+
def run
|
467
|
+
puts "š Starting Custom Logger Demo\n"
|
468
|
+
|
469
|
+
# Clean up any existing log files for a fresh demo
|
470
|
+
FileUtils.rm_rf('logs') if Dir.exist?('logs')
|
471
|
+
|
472
|
+
# Subscribe to messages
|
473
|
+
OrderProcessingMessage.subscribe
|
474
|
+
NotificationMessage.subscribe
|
475
|
+
|
476
|
+
puts "\n" + "="*70
|
477
|
+
puts "Demonstrating Different Logger Configurations"
|
478
|
+
puts "="*70
|
479
|
+
|
480
|
+
# Demo 1: Using the built-in Default Logger (NEW!)
|
481
|
+
puts "\n--- Demo 1: Using SmartMessage Default Logger ---"
|
482
|
+
puts "The Default logger automatically uses Rails.logger or Ruby Logger"
|
483
|
+
|
484
|
+
# Use the DefaultLoggerMessage class defined above
|
485
|
+
DefaultLoggerMessage.subscribe
|
486
|
+
default_msg = DefaultLoggerMessage.new(
|
487
|
+
message: "Testing the built-in default logger",
|
488
|
+
level: "info"
|
489
|
+
)
|
490
|
+
default_msg.publish
|
491
|
+
sleep(0.5)
|
492
|
+
|
493
|
+
# Demo 2: Standard order with multi-logger
|
494
|
+
puts "\n--- Demo 2: Standard Order (Multi-Logger) ---"
|
495
|
+
order1 = OrderProcessingMessage.new(
|
496
|
+
order_id: "ORD-001",
|
497
|
+
customer_id: "CUST-123",
|
498
|
+
amount: 99.99,
|
499
|
+
status: "pending",
|
500
|
+
items: ["Widget A", "Widget B"]
|
501
|
+
)
|
502
|
+
order1.publish
|
503
|
+
sleep(0.5)
|
504
|
+
|
505
|
+
# Demo 3: Notification with file-only logger
|
506
|
+
puts "\n--- Demo 3: Notification (File Logger Only) ---"
|
507
|
+
notification = NotificationMessage.new(
|
508
|
+
recipient: "customer@example.com",
|
509
|
+
subject: "Order Confirmation",
|
510
|
+
body: "Your order has been received",
|
511
|
+
priority: "normal"
|
512
|
+
)
|
513
|
+
notification.publish
|
514
|
+
sleep(0.5)
|
515
|
+
|
516
|
+
# Demo 4: Priority order with instance-level logger override
|
517
|
+
puts "\n--- Demo 4: Priority Order (Instance Logger Override) ---"
|
518
|
+
priority_service = PriorityOrderService.new
|
519
|
+
priority_order = priority_service.process_priority_order(
|
520
|
+
order_id: "ORD-PRIORITY-001",
|
521
|
+
customer_id: "VIP-456",
|
522
|
+
amount: 299.99,
|
523
|
+
status: "urgent",
|
524
|
+
items: ["Premium Widget", "Express Shipping"]
|
525
|
+
)
|
526
|
+
sleep(0.5)
|
527
|
+
|
528
|
+
# Demo 5: Using standard Ruby logger
|
529
|
+
puts "\n--- Demo 5: Using Standard Ruby Logger ---"
|
530
|
+
|
531
|
+
# Use the StandardLoggerMessage class that demonstrates Ruby's standard logger
|
532
|
+
StandardLoggerMessage.subscribe
|
533
|
+
|
534
|
+
# Create and send a message - watch for the Ruby logger output
|
535
|
+
msg = StandardLoggerMessage.new(
|
536
|
+
content: "Testing with Ruby's standard logger",
|
537
|
+
level: "info"
|
538
|
+
)
|
539
|
+
|
540
|
+
# The logger will output to STDOUT using Ruby's standard format
|
541
|
+
msg.publish
|
542
|
+
sleep(0.5)
|
543
|
+
|
544
|
+
puts "\nNote: The above used Ruby's standard Logger class wrapped for SmartMessage"
|
545
|
+
puts "You can use ANY Ruby logger this way: Logger.new, Rails.logger, etc."
|
546
|
+
|
547
|
+
# Demo 6: Error handling with logging
|
548
|
+
puts "\n--- Demo 6: Error Handling with Logging ---"
|
549
|
+
begin
|
550
|
+
# Create a message that will cause an error
|
551
|
+
faulty_order = OrderProcessingMessage.new(
|
552
|
+
order_id: nil, # This might cause issues
|
553
|
+
customer_id: "ERROR-TEST",
|
554
|
+
amount: "invalid_amount",
|
555
|
+
status: "error_demo"
|
556
|
+
)
|
557
|
+
|
558
|
+
# Simulate an error during processing
|
559
|
+
if OrderProcessingMessage.logger
|
560
|
+
OrderProcessingMessage.logger.log_error(
|
561
|
+
"Simulated error for demo",
|
562
|
+
StandardError.new("Invalid order data provided")
|
563
|
+
)
|
564
|
+
end
|
565
|
+
|
566
|
+
rescue => error
|
567
|
+
puts "š Caught demonstration error: #{error.message}"
|
568
|
+
end
|
569
|
+
|
570
|
+
# Show log file contents
|
571
|
+
puts "\n" + "="*70
|
572
|
+
puts "š Log File Contents"
|
573
|
+
puts "="*70
|
574
|
+
|
575
|
+
show_log_contents
|
576
|
+
|
577
|
+
puts "\n⨠Demo completed!"
|
578
|
+
puts "\nThis example demonstrated:"
|
579
|
+
puts "⢠SmartMessage::Logger::Default - Built-in logger that auto-detects Rails/Ruby"
|
580
|
+
puts "⢠Integration with Ruby's standard Logger class"
|
581
|
+
puts "⢠How to wrap Rails.logger or any Ruby logger for SmartMessage"
|
582
|
+
puts "⢠Custom logger implementations (File, JSON, Console, Multi-logger)"
|
583
|
+
puts "⢠Class-level and instance-level logger configuration"
|
584
|
+
puts "⢠Different logging strategies for different message types"
|
585
|
+
puts "⢠Error logging and message lifecycle logging"
|
586
|
+
puts "⢠Log file management and structured logging formats"
|
587
|
+
puts "\nKEY TAKEAWAY: Use SmartMessage::Logger::Default.new for instant logging!"
|
588
|
+
puts "It automatically uses Rails.logger in Rails or creates a Ruby Logger otherwise."
|
589
|
+
end
|
590
|
+
|
591
|
+
private
|
592
|
+
|
593
|
+
def show_log_contents
|
594
|
+
log_files = Dir.glob('logs/*.log') + Dir.glob('logs/*.json')
|
595
|
+
|
596
|
+
log_files.each do |log_file|
|
597
|
+
next unless File.exist?(log_file)
|
598
|
+
|
599
|
+
puts "\nš #{log_file}:"
|
600
|
+
puts "-" * 50
|
601
|
+
|
602
|
+
content = File.read(log_file)
|
603
|
+
if content.length > 500
|
604
|
+
puts content[0..500] + "\n... (truncated, #{content.length} total characters)"
|
605
|
+
else
|
606
|
+
puts content
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
if log_files.empty?
|
611
|
+
puts "ā ļø No log files found (they may not have been created yet)"
|
612
|
+
end
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
# Run the demo if this file is executed directly
|
617
|
+
if __FILE__ == $0
|
618
|
+
demo = LoggerDemo.new
|
619
|
+
demo.run
|
620
|
+
end
|