smart_message 0.0.7 → 0.0.9

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.irbrc +24 -0
  4. data/CHANGELOG.md +143 -0
  5. data/Gemfile.lock +6 -1
  6. data/README.md +289 -15
  7. data/docs/README.md +3 -1
  8. data/docs/addressing.md +119 -13
  9. data/docs/architecture.md +68 -0
  10. data/docs/dead_letter_queue.md +673 -0
  11. data/docs/dispatcher.md +87 -0
  12. data/docs/examples.md +59 -1
  13. data/docs/getting-started.md +8 -1
  14. data/docs/logging.md +382 -326
  15. data/docs/message_filtering.md +451 -0
  16. data/examples/01_point_to_point_orders.rb +54 -53
  17. data/examples/02_publish_subscribe_events.rb +14 -10
  18. data/examples/03_many_to_many_chat.rb +16 -8
  19. data/examples/04_redis_smart_home_iot.rb +20 -10
  20. data/examples/05_proc_handlers.rb +12 -11
  21. data/examples/06_custom_logger_example.rb +95 -100
  22. data/examples/07_error_handling_scenarios.rb +4 -2
  23. data/examples/08_entity_addressing_basic.rb +18 -6
  24. data/examples/08_entity_addressing_with_filtering.rb +27 -9
  25. data/examples/09_dead_letter_queue_demo.rb +559 -0
  26. data/examples/09_regex_filtering_microservices.rb +407 -0
  27. data/examples/10_header_block_configuration.rb +263 -0
  28. data/examples/11_global_configuration_example.rb +219 -0
  29. data/examples/README.md +102 -0
  30. data/examples/dead_letters.jsonl +12 -0
  31. data/examples/performance_metrics/benchmark_results_ractor_20250818_205603.json +135 -0
  32. data/examples/performance_metrics/benchmark_results_ractor_20250818_205831.json +135 -0
  33. data/examples/performance_metrics/benchmark_results_test_20250818_204942.json +130 -0
  34. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204942.json +130 -0
  35. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204959.json +130 -0
  36. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205044.json +130 -0
  37. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205109.json +130 -0
  38. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205252.json +130 -0
  39. data/examples/performance_metrics/benchmark_results_unknown_20250819_172852.json +130 -0
  40. data/examples/performance_metrics/compare_benchmarks.rb +519 -0
  41. data/examples/performance_metrics/dead_letters.jsonl +3100 -0
  42. data/examples/performance_metrics/performance_benchmark.rb +344 -0
  43. data/examples/show_logger.rb +367 -0
  44. data/examples/show_me.rb +145 -0
  45. data/examples/temp.txt +94 -0
  46. data/examples/tmux_chat/bot_agent.rb +4 -2
  47. data/examples/tmux_chat/human_agent.rb +4 -2
  48. data/examples/tmux_chat/room_monitor.rb +4 -2
  49. data/examples/tmux_chat/shared_chat_system.rb +6 -3
  50. data/lib/smart_message/addressing.rb +259 -0
  51. data/lib/smart_message/base.rb +121 -599
  52. data/lib/smart_message/circuit_breaker.rb +23 -6
  53. data/lib/smart_message/configuration.rb +199 -0
  54. data/lib/smart_message/dead_letter_queue.rb +361 -0
  55. data/lib/smart_message/dispatcher.rb +90 -49
  56. data/lib/smart_message/header.rb +5 -0
  57. data/lib/smart_message/logger/base.rb +21 -1
  58. data/lib/smart_message/logger/default.rb +88 -138
  59. data/lib/smart_message/logger/lumberjack.rb +324 -0
  60. data/lib/smart_message/logger/null.rb +81 -0
  61. data/lib/smart_message/logger.rb +17 -9
  62. data/lib/smart_message/messaging.rb +100 -0
  63. data/lib/smart_message/plugins.rb +132 -0
  64. data/lib/smart_message/serializer/base.rb +25 -8
  65. data/lib/smart_message/serializer/json.rb +5 -4
  66. data/lib/smart_message/subscription.rb +193 -0
  67. data/lib/smart_message/transport/base.rb +84 -53
  68. data/lib/smart_message/transport/memory_transport.rb +7 -5
  69. data/lib/smart_message/transport/redis_transport.rb +15 -45
  70. data/lib/smart_message/transport/stdout_transport.rb +18 -8
  71. data/lib/smart_message/transport.rb +1 -34
  72. data/lib/smart_message/utilities.rb +142 -0
  73. data/lib/smart_message/version.rb +1 -1
  74. data/lib/smart_message/versioning.rb +85 -0
  75. data/lib/smart_message/wrapper.rb.bak +132 -0
  76. data/lib/smart_message.rb +74 -27
  77. data/smart_message.gemspec +3 -0
  78. metadata +77 -3
  79. data/lib/smart_message/serializer.rb +0 -10
  80. data/lib/smart_message/wrapper.rb +0 -43
@@ -0,0 +1,344 @@
1
+ #!/usr/bin/env ruby
2
+ # performance_benchmark.rb
3
+ #
4
+ # A comprehensive performance measurement tool to compare implementation subjects
5
+
6
+ SUBJECT = ARGV.shift || "unknown"
7
+
8
+
9
+ require 'bundler/setup'
10
+ require 'benchmark'
11
+ require 'json'
12
+ require 'fileutils'
13
+ require_relative '../../lib/smart_message'
14
+
15
+ class PerformanceBenchmark
16
+ SCENARIOS = {
17
+ cpu_light: { name: "CPU Light", iterations: 1000, sleep: 0 },
18
+ cpu_heavy: { name: "CPU Heavy", iterations: 500, computation: 10000 },
19
+ io_light: { name: "I/O Light", iterations: 800, sleep: 0.001 },
20
+ io_heavy: { name: "I/O Heavy", iterations: 200, sleep: 0.01 },
21
+ mixed: { name: "Mixed Load", iterations: 600, computation: 5000, sleep: 0.005 }
22
+ }.freeze
23
+
24
+ def initialize
25
+ @results = {}
26
+ @start_time = nil
27
+ @memory_before = nil
28
+ @dispatcher = SmartMessage::Dispatcher.new
29
+ setup_test_messages
30
+ end
31
+
32
+ def run_all_scenarios
33
+ puts "🚀 Starting SmartMessage Performance Benchmark"
34
+ puts "Ruby Version: #{RUBY_VERSION}"
35
+ puts "Platform: #{RUBY_PLATFORM}"
36
+ puts "Processor Count: #{processor_count}"
37
+ puts "=" * 60
38
+
39
+ @start_time = Time.now
40
+ @memory_before = memory_usage
41
+
42
+ SCENARIOS.each do |scenario_key, config|
43
+ puts "\n📊 Running scenario: #{config[:name]}"
44
+ run_scenario(scenario_key, config)
45
+ end
46
+
47
+ generate_report
48
+ save_results
49
+ end
50
+
51
+ private
52
+
53
+ def setup_test_messages
54
+ # Define test message classes for different scenarios
55
+
56
+ # CPU Light - Simple message processing
57
+ define_message_class(:CpuLightMessage, :process_cpu_light)
58
+
59
+ # CPU Heavy - Computation-intensive processing
60
+ define_message_class(:CpuHeavyMessage, :process_cpu_heavy)
61
+
62
+ # I/O Light - Short sleep simulation
63
+ define_message_class(:IoLightMessage, :process_io_light)
64
+
65
+ # I/O Heavy - Longer I/O simulation
66
+ define_message_class(:IoHeavyMessage, :process_io_heavy)
67
+
68
+ # Mixed - Both CPU and I/O
69
+ define_message_class(:MixedMessage, :process_mixed)
70
+ end
71
+
72
+ def define_message_class(class_name, processor_method)
73
+ message_class = Class.new(SmartMessage::Base) do
74
+ property :scenario_id, required: true
75
+ property :message_id, required: true
76
+ property :timestamp, required: true
77
+ property :computation_cycles
78
+ property :sleep_duration
79
+
80
+ def process
81
+ # This gets called by the processor methods
82
+ end
83
+ end
84
+
85
+ # Set the class name first
86
+ Object.const_set(class_name, message_class)
87
+
88
+ # Now set the from address after the class has a name
89
+ message_class.from('benchmark-service')
90
+
91
+ # Configure transport and serializer - need to capture dispatcher reference
92
+ dispatcher = @dispatcher
93
+ message_class.config do
94
+ transport SmartMessage::Transport::MemoryTransport.new(dispatcher: dispatcher, auto_process: true)
95
+ serializer SmartMessage::Serializer::JSON.new
96
+ end
97
+
98
+ # Register processor with dispatcher
99
+ @dispatcher.add(class_name.to_s, "PerformanceBenchmark.#{processor_method}")
100
+ end
101
+
102
+ def run_scenario(scenario_key, config)
103
+ scenario_start = Time.now
104
+ processed_count = 0
105
+ errors = 0
106
+
107
+ # Setup monitoring
108
+ completed_before = @dispatcher.completed_task_count rescue 0
109
+
110
+ # Generate and publish messages
111
+ messages = generate_messages(scenario_key, config)
112
+
113
+ publish_start = Time.now
114
+ messages.each do |message|
115
+ begin
116
+ message.publish
117
+ rescue => e
118
+ errors += 1
119
+ puts "Error publishing message: #{e.message}" if errors < 5
120
+ end
121
+ end
122
+ publish_time = Time.now - publish_start
123
+
124
+ # Wait for processing to complete
125
+ target_completed = completed_before + config[:iterations] - errors
126
+ processing_start = Time.now
127
+
128
+ wait_for_completion(target_completed, config[:iterations])
129
+ processing_time = Time.now - processing_start
130
+
131
+ completed_after = @dispatcher.completed_task_count rescue target_completed
132
+ actually_processed = completed_after - completed_before
133
+
134
+ scenario_time = Time.now - scenario_start
135
+
136
+ # Store results
137
+ @results[scenario_key] = {
138
+ name: config[:name],
139
+ messages_generated: config[:iterations],
140
+ messages_published: config[:iterations] - errors,
141
+ messages_processed: actually_processed,
142
+ errors: errors,
143
+ times: {
144
+ total: scenario_time,
145
+ publish: publish_time,
146
+ processing: processing_time
147
+ },
148
+ throughput: {
149
+ messages_per_second: actually_processed / scenario_time,
150
+ publish_rate: (config[:iterations] - errors) / publish_time
151
+ },
152
+ dispatcher_stats: @dispatcher.status
153
+ }
154
+
155
+ puts " ✅ Processed #{actually_processed}/#{config[:iterations]} messages in #{scenario_time.round(3)}s"
156
+ puts " 📈 Throughput: #{(actually_processed / scenario_time).round(1)} msg/sec"
157
+ puts " 🚀 Publish rate: #{((config[:iterations] - errors) / publish_time).round(1)} msg/sec"
158
+ puts " ❌ Errors: #{errors}" if errors > 0
159
+ end
160
+
161
+ def generate_messages(scenario_key, config)
162
+ message_class = Object.const_get(scenario_class_name(scenario_key))
163
+
164
+ config[:iterations].times.map do |i|
165
+ message_class.new(
166
+ scenario_id: scenario_key.to_s,
167
+ message_id: "#{scenario_key}_#{i}",
168
+ timestamp: Time.now.to_f,
169
+ computation_cycles: config[:computation],
170
+ sleep_duration: config[:sleep]
171
+ )
172
+ end
173
+ end
174
+
175
+ def scenario_class_name(scenario_key)
176
+ case scenario_key
177
+ when :cpu_light then :CpuLightMessage
178
+ when :cpu_heavy then :CpuHeavyMessage
179
+ when :io_light then :IoLightMessage
180
+ when :io_heavy then :IoHeavyMessage
181
+ when :mixed then :MixedMessage
182
+ end
183
+ end
184
+
185
+ def wait_for_completion(target_completed, max_iterations)
186
+ timeout = 60 # seconds
187
+ start_wait = Time.now
188
+
189
+ while (Time.now - start_wait) < timeout
190
+ current_completed = @dispatcher.completed_task_count rescue 0
191
+
192
+ if current_completed >= target_completed
193
+ break
194
+ end
195
+
196
+ # Check if dispatcher is still running
197
+ unless @dispatcher.running?
198
+ puts " ⚠️ Dispatcher stopped running"
199
+ break
200
+ end
201
+
202
+ sleep 0.1
203
+ end
204
+
205
+ if (Time.now - start_wait) >= timeout
206
+ puts " ⚠️ Timeout waiting for message processing"
207
+ end
208
+ end
209
+
210
+
211
+ def generate_report
212
+ puts "\n" + "=" * 60
213
+ puts "📋 PERFORMANCE BENCHMARK REPORT"
214
+ puts "=" * 60
215
+
216
+ total_time = Time.now - @start_time
217
+ memory_after = memory_usage
218
+ memory_used = memory_after - @memory_before
219
+
220
+ puts "\n📊 Overall Stats:"
221
+ puts " Total runtime: #{total_time.round(3)}s"
222
+ puts " Memory used: #{memory_used.round(2)} MB"
223
+ puts " Implementation Subject: #{SUBJECT}"
224
+
225
+ puts "\n📈 Scenario Results:"
226
+ @results.each do |scenario_key, data|
227
+ puts "\n #{data[:name]}:"
228
+ puts " Messages: #{data[:messages_processed]}/#{data[:messages_generated]}"
229
+ puts " Total time: #{data[:times][:total].round(3)}s"
230
+ puts " Throughput: #{data[:throughput][:messages_per_second].round(1)} msg/sec"
231
+ puts " Publish rate: #{data[:throughput][:publish_rate].round(1)} msg/sec"
232
+ puts " Errors: #{data[:errors]}" if data[:errors] > 0
233
+ end
234
+
235
+ puts "\n🏆 Best Performing Scenarios:"
236
+ sorted_by_throughput = @results.sort_by { |k, v| -v[:throughput][:messages_per_second] }
237
+ sorted_by_throughput.first(3).each_with_index do |(scenario_key, data), index|
238
+ puts " #{index + 1}. #{data[:name]}: #{data[:throughput][:messages_per_second].round(1)} msg/sec"
239
+ end
240
+ end
241
+
242
+ def save_results
243
+ timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
244
+ filename = "benchmark_results_#{SUBJECT}_#{timestamp}.json"
245
+
246
+ report_data = {
247
+ benchmark_info: {
248
+ timestamp: Time.now.iso8601,
249
+ subject: SUBJECT,
250
+ ruby_version: RUBY_VERSION,
251
+ platform: RUBY_PLATFORM,
252
+ processors: processor_count
253
+ },
254
+ overall_stats: {
255
+ total_runtime: Time.now - @start_time,
256
+ memory_used_mb: memory_usage - @memory_before
257
+ },
258
+ scenario_results: @results
259
+ }
260
+
261
+ File.write(filename, JSON.pretty_generate(report_data))
262
+ puts "\n💾 Results saved to: #{filename}"
263
+ end
264
+
265
+ def memory_usage
266
+ `ps -o rss= -p #{Process.pid}`.to_i / 1024.0 # Convert KB to MB
267
+ rescue
268
+ 0
269
+ end
270
+
271
+ def processor_count
272
+ case RUBY_PLATFORM
273
+ when /linux/
274
+ `nproc`.to_i
275
+ when /darwin/
276
+ `sysctl -n hw.ncpu`.to_i
277
+ else
278
+ `echo $NUMBER_OF_PROCESSORS`.to_i
279
+ end
280
+ rescue
281
+ 4 # fallback
282
+ end
283
+
284
+ # Processor methods called by the dispatcher
285
+
286
+ def self.process_cpu_light(message_header, encoded_message)
287
+ # Simple processing - just decode
288
+ message_data = JSON.parse(encoded_message)
289
+ message_data['processed_at'] = Time.now.to_f
290
+ end
291
+
292
+ def self.process_cpu_heavy(message_header, encoded_message)
293
+ message_data = JSON.parse(encoded_message)
294
+
295
+ # CPU-intensive computation
296
+ cycles = message_data['computation_cycles'] || 10000
297
+ result = 0
298
+ cycles.times { |i| result += Math.sqrt(i) * Math.sin(i) }
299
+
300
+ message_data['processed_at'] = Time.now.to_f
301
+ message_data['computation_result'] = result
302
+ end
303
+
304
+ def self.process_io_light(message_header, encoded_message)
305
+ message_data = JSON.parse(encoded_message)
306
+
307
+ # Light I/O simulation
308
+ sleep_time = message_data['sleep_duration'] || 0.001
309
+ sleep(sleep_time)
310
+
311
+ message_data['processed_at'] = Time.now.to_f
312
+ end
313
+
314
+ def self.process_io_heavy(message_header, encoded_message)
315
+ message_data = JSON.parse(encoded_message)
316
+
317
+ # Heavy I/O simulation
318
+ sleep_time = message_data['sleep_duration'] || 0.01
319
+ sleep(sleep_time)
320
+
321
+ message_data['processed_at'] = Time.now.to_f
322
+ end
323
+
324
+ def self.process_mixed(message_header, encoded_message)
325
+ message_data = JSON.parse(encoded_message)
326
+
327
+ # Combined CPU and I/O
328
+ cycles = message_data['computation_cycles'] || 5000
329
+ sleep_time = message_data['sleep_duration'] || 0.005
330
+
331
+ result = 0
332
+ cycles.times { |i| result += Math.sqrt(i) }
333
+ sleep(sleep_time)
334
+
335
+ message_data['processed_at'] = Time.now.to_f
336
+ message_data['computation_result'] = result
337
+ end
338
+ end
339
+
340
+ # Run the benchmark if called directly
341
+ if __FILE__ == $0
342
+ benchmark = PerformanceBenchmark.new
343
+ benchmark.run_all_scenarios
344
+ end
@@ -0,0 +1,367 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/show_logger.rb
3
+ #
4
+ # Demonstrates the various features of the SmartMessage default logger
5
+ # and shows how applications can use the logger directly.
6
+
7
+ require_relative '../lib/smart_message'
8
+
9
+ puts "=" * 80
10
+ puts "SmartMessage Logger Feature Demonstration"
11
+ puts "=" * 80
12
+
13
+ # Example 1: Basic Logger Configuration
14
+ puts "\n1. Basic Logger Configuration"
15
+ puts "-" * 40
16
+
17
+ SmartMessage.configure do |config|
18
+ config.logger = STDOUT
19
+ config.log_level = :info
20
+ config.log_format = :text
21
+ config.log_colorize = true
22
+ end
23
+
24
+ # Get the configured logger for direct use
25
+ logger = SmartMessage.configuration.default_logger
26
+ puts "✓ Logger type: #{logger.class}"
27
+ puts "✓ Log level: #{logger.level}"
28
+ puts "✓ Format: #{logger.format}"
29
+ puts "✓ Colorized: #{logger.colorize}"
30
+
31
+ # Demonstrate different log levels with colors
32
+ puts "\nTesting different log levels (should show colors):"
33
+ logger.debug("This is a debug message - appears in light gray")
34
+ logger.info("This is an info message - appears in white")
35
+ logger.warn("This is a warning message - appears in yellow")
36
+ logger.error("This is an error message - appears in red")
37
+ logger.fatal("This is a fatal message - appears in bold red")
38
+
39
+ # Example 2: JSON Format Logger
40
+ puts "\n\n2. JSON Format Logger"
41
+ puts "-" * 40
42
+
43
+ SmartMessage.reset_configuration!
44
+ SmartMessage.configure do |config|
45
+ config.logger = STDOUT
46
+ config.log_level = :info
47
+ config.log_format = :json
48
+ config.log_include_source = true
49
+ config.log_structured_data = true
50
+ config.log_colorize = false # No colors in JSON
51
+ end
52
+
53
+ json_logger = SmartMessage.configuration.default_logger
54
+ puts "✓ JSON Logger configured"
55
+
56
+ json_logger.info("JSON formatted message")
57
+ json_logger.warn("Warning with structured data",
58
+ component: "auth",
59
+ user_id: 12345,
60
+ action: "login_attempt")
61
+ json_logger.error("Error with context",
62
+ error_code: "AUTH_001",
63
+ timestamp: Time.now.iso8601,
64
+ severity: "high")
65
+
66
+ # Example 3: File Logger with Rolling
67
+ puts "\n\n3. File Logger with Size-based Rolling"
68
+ puts "-" * 40
69
+
70
+ SmartMessage.reset_configuration!
71
+ SmartMessage.configure do |config|
72
+ config.logger = "log/demo_app.log"
73
+ config.log_level = :debug
74
+ config.log_format = :text
75
+ config.log_include_source = true
76
+ config.log_colorize = false # No colors for file output
77
+ config.log_options = {
78
+ roll_by_size: true,
79
+ max_file_size: 1024, # Small size for demo (1KB)
80
+ keep_files: 3
81
+ }
82
+ end
83
+
84
+ file_logger = SmartMessage.configuration.default_logger
85
+ puts "✓ File logger with rolling configured"
86
+ puts "✓ Log file: #{file_logger.log_file}"
87
+ puts "✓ Rolling enabled: #{file_logger.respond_to?(:options) ? 'Yes' : 'No'}"
88
+
89
+ # Generate some log entries to trigger rolling
90
+ puts "\nGenerating log entries (check log/ directory)..."
91
+ 50.times do |i|
92
+ file_logger.info("Log entry #{i + 1} - generating content to trigger file rolling when size limit is reached")
93
+ file_logger.debug("Debug entry #{i + 1}", entry_number: i + 1, batch: "demo")
94
+ end
95
+
96
+ puts "✓ Generated 100 log entries to demonstrate file rolling"
97
+
98
+ # Example 4: Date-based Rolling Logger
99
+ puts "\n\n4. Date-based Rolling Logger"
100
+ puts "-" * 40
101
+
102
+ SmartMessage.reset_configuration!
103
+ SmartMessage.configure do |config|
104
+ config.logger = "log/daily_app.log"
105
+ config.log_level = :info
106
+ config.log_format = :text
107
+ config.log_options = {
108
+ roll_by_date: true,
109
+ date_pattern: '%Y-%m-%d'
110
+ }
111
+ end
112
+
113
+ date_logger = SmartMessage.configuration.default_logger
114
+ puts "✓ Date-based rolling logger configured"
115
+
116
+ date_logger.info("Application started", app_version: "1.2.3")
117
+ date_logger.info("Daily log rotation enabled")
118
+
119
+ # Example 5: Application Logger Pattern
120
+ puts "\n\n5. Application Logger Pattern"
121
+ puts "-" * 40
122
+
123
+ # Configure a production-like logger
124
+ SmartMessage.reset_configuration!
125
+ SmartMessage.configure do |config|
126
+ config.logger = "log/application.log"
127
+ config.log_level = :info
128
+ config.log_format = :json
129
+ config.log_include_source = true
130
+ config.log_structured_data = true
131
+ config.log_options = {
132
+ roll_by_size: true,
133
+ max_file_size: 10 * 1024 * 1024, # 10 MB
134
+ keep_files: 5,
135
+ roll_by_date: false
136
+ }
137
+ end
138
+
139
+ # Create an application class that uses the SmartMessage logger
140
+ class DemoApplication
141
+ def initialize
142
+ @logger = SmartMessage.configuration.default_logger
143
+ @logger.info("DemoApplication initialized", component: "app", pid: Process.pid)
144
+ end
145
+
146
+ def start
147
+ @logger.info("Starting application", action: "start")
148
+
149
+ # Simulate some application work
150
+ process_users
151
+ handle_requests
152
+
153
+ @logger.info("Application started successfully", action: "start", status: "success")
154
+ end
155
+
156
+ def stop
157
+ @logger.info("Stopping application", action: "stop")
158
+ @logger.info("Application stopped", action: "stop", status: "success")
159
+ end
160
+
161
+ private
162
+
163
+ def process_users
164
+ @logger.debug("Processing user data", action: "process_users")
165
+
166
+ users = [
167
+ { id: 1, name: "Alice", email: "alice@example.com" },
168
+ { id: 2, name: "Bob", email: "bob@example.com" },
169
+ { id: 3, name: "Charlie", email: "charlie@example.com" }
170
+ ]
171
+
172
+ users.each do |user|
173
+ @logger.info("Processing user",
174
+ action: "process_user",
175
+ user_id: user[:id],
176
+ user_name: user[:name])
177
+
178
+ # Simulate some processing time
179
+ sleep(0.1)
180
+ end
181
+
182
+ @logger.info("User processing completed",
183
+ action: "process_users",
184
+ status: "completed",
185
+ user_count: users.size)
186
+ end
187
+
188
+ def handle_requests
189
+ @logger.debug("Handling incoming requests", action: "handle_requests")
190
+
191
+ requests = [
192
+ { method: "GET", path: "/api/users", status: 200 },
193
+ { method: "POST", path: "/api/users", status: 201 },
194
+ { method: "GET", path: "/api/users/1", status: 200 },
195
+ { method: "DELETE", path: "/api/users/2", status: 404 }
196
+ ]
197
+
198
+ requests.each_with_index do |request, index|
199
+ level = request[:status] >= 400 ? :warn : :info
200
+
201
+ @logger.send(level, "HTTP request processed",
202
+ action: "http_request",
203
+ method: request[:method],
204
+ path: request[:path],
205
+ status_code: request[:status],
206
+ request_id: "req_#{index + 1}")
207
+ end
208
+
209
+ @logger.info("Request handling completed",
210
+ action: "handle_requests",
211
+ status: "completed",
212
+ request_count: requests.size)
213
+ end
214
+ end
215
+
216
+ puts "✓ Application logger configured for production use"
217
+
218
+ # Run the demo application
219
+ app = DemoApplication.new
220
+ app.start
221
+ sleep(0.5) # Simulate runtime
222
+ app.stop
223
+
224
+ # Example 6: Multiple Logger Configurations
225
+ puts "\n\n6. Multiple Logger Configurations"
226
+ puts "-" * 40
227
+
228
+ # You can create multiple logger instances with different configurations
229
+ console_logger = SmartMessage::Logger::Lumberjack.new(
230
+ log_file: STDERR,
231
+ level: :warn,
232
+ format: :text,
233
+ colorize: true,
234
+ include_source: false
235
+ )
236
+
237
+ file_logger_json = SmartMessage::Logger::Lumberjack.new(
238
+ log_file: "log/json_output.log",
239
+ level: :debug,
240
+ format: :json,
241
+ include_source: true,
242
+ structured_data: true
243
+ )
244
+
245
+ puts "✓ Console logger (STDERR, warnings only, colorized)"
246
+ puts "✓ File logger (JSON format, debug level)"
247
+
248
+ console_logger.warn("This appears on console in yellow")
249
+ console_logger.error("This appears on console in red")
250
+ console_logger.info("This won't appear (below warn level)")
251
+
252
+ file_logger_json.debug("Debug message to JSON file", module: "demo", test: true)
253
+ file_logger_json.info("Info message to JSON file", event: "demonstration")
254
+
255
+ # Example 7: Integration with SmartMessage Classes
256
+ puts "\n\n7. Integration with SmartMessage Classes"
257
+ puts "-" * 40
258
+
259
+ # Reset to a simple configuration for message examples
260
+ SmartMessage.reset_configuration!
261
+ SmartMessage.configure do |config|
262
+ config.logger = STDOUT
263
+ config.log_level = :debug
264
+ config.log_format = :text
265
+ config.log_colorize = true
266
+ end
267
+
268
+ # Define a sample message class
269
+ class DemoMessage < SmartMessage::Base
270
+ property :title, required: true
271
+ property :content
272
+ property :priority, default: 'normal'
273
+
274
+ config do
275
+ transport SmartMessage::Transport::StdoutTransport.new
276
+ serializer SmartMessage::Serializer::Json.new
277
+ from 'demo-logger-app'
278
+ end
279
+
280
+ def process
281
+ # Messages automatically use the configured SmartMessage logger
282
+ logger.info("Processing demo message",
283
+ message_id: _sm_header.uuid,
284
+ title: title,
285
+ priority: priority)
286
+
287
+ case priority
288
+ when 'high'
289
+ logger.warn("High priority message requires attention",
290
+ title: title,
291
+ priority: priority)
292
+ when 'critical'
293
+ logger.error("Critical message needs immediate action",
294
+ title: title,
295
+ priority: priority)
296
+ else
297
+ logger.info("Normal message processed",
298
+ title: title,
299
+ priority: priority)
300
+ end
301
+ end
302
+ end
303
+
304
+ puts "✓ SmartMessage classes automatically use the configured logger"
305
+
306
+ # Create and publish some demo messages
307
+ messages = [
308
+ { title: "Welcome Message", content: "Hello, World!", priority: "normal" },
309
+ { title: "System Alert", content: "High CPU usage detected", priority: "high" },
310
+ { title: "Security Breach", content: "Unauthorized access attempt", priority: "critical" }
311
+ ]
312
+
313
+ # Get the logger for demonstrating message instance logging
314
+ app_logger = SmartMessage.configuration.default_logger
315
+
316
+ messages.each do |msg_data|
317
+ begin
318
+ message = DemoMessage.new(
319
+ title: msg_data[:title],
320
+ content: msg_data[:content],
321
+ priority: msg_data[:priority]
322
+ )
323
+
324
+ puts "<<<>>>>>>>>"
325
+ # Example of logging an info message that contains the message instance
326
+ # Shows how to log SmartMessage structure: full message, header, and payload
327
+ app_logger.info({action: "Publishing SmartMessage instance",
328
+ message_class: message.class.name,
329
+ message_uuid: message._sm_header.uuid,
330
+ message_from: message._sm_header.from,
331
+ header: message._sm_header,
332
+ payload: message._sm_payload,
333
+ full_message: message})
334
+
335
+ puts "<<<<<<<<<<"
336
+
337
+ message.publish
338
+ sleep(0.2) # Small delay for demonstration
339
+ rescue => e
340
+ puts "Error creating/publishing message: #{e.message}"
341
+ end
342
+ end
343
+
344
+ puts "\n" + "=" * 80
345
+ puts "Logger Demonstration Complete!"
346
+ puts "=" * 80
347
+
348
+ puts "\nFiles created in log/ directory:"
349
+ log_files = Dir.glob("log/**/*").select { |f| File.file?(f) }
350
+ log_files.each do |file|
351
+ size = File.size(file)
352
+ puts " #{file} (#{size} bytes)"
353
+ end
354
+
355
+ puts "\nFeatures demonstrated:"
356
+ puts " ✓ Basic text logging with colors"
357
+ puts " ✓ JSON structured logging"
358
+ puts " ✓ File logging with size-based rolling"
359
+ puts " ✓ Date-based log rolling"
360
+ puts " ✓ Application integration patterns"
361
+ puts " ✓ Multiple logger configurations"
362
+ puts " ✓ SmartMessage class integration"
363
+ puts " ✓ Different log levels and formatting"
364
+ puts " ✓ Structured data logging"
365
+ puts " ✓ Source location tracking"
366
+
367
+ puts "\nTip: Check the generated log files to see the different output formats!"