smart_message 0.0.8 → 0.0.10

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.irbrc +24 -0
  4. data/CHANGELOG.md +119 -0
  5. data/Gemfile.lock +6 -1
  6. data/README.md +389 -17
  7. data/docs/README.md +3 -1
  8. data/docs/addressing.md +119 -13
  9. data/docs/architecture.md +184 -46
  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_deduplication.md +488 -0
  16. data/docs/message_filtering.md +451 -0
  17. data/examples/01_point_to_point_orders.rb +54 -53
  18. data/examples/02_publish_subscribe_events.rb +14 -10
  19. data/examples/03_many_to_many_chat.rb +16 -8
  20. data/examples/04_redis_smart_home_iot.rb +20 -10
  21. data/examples/05_proc_handlers.rb +12 -11
  22. data/examples/06_custom_logger_example.rb +95 -100
  23. data/examples/07_error_handling_scenarios.rb +4 -2
  24. data/examples/08_entity_addressing_basic.rb +18 -6
  25. data/examples/08_entity_addressing_with_filtering.rb +27 -9
  26. data/examples/09_dead_letter_queue_demo.rb +559 -0
  27. data/examples/09_regex_filtering_microservices.rb +407 -0
  28. data/examples/10_header_block_configuration.rb +263 -0
  29. data/examples/10_message_deduplication.rb +209 -0
  30. data/examples/11_global_configuration_example.rb +219 -0
  31. data/examples/README.md +102 -0
  32. data/examples/dead_letters.jsonl +12 -0
  33. data/examples/performance_metrics/benchmark_results_ractor_20250818_205603.json +135 -0
  34. data/examples/performance_metrics/benchmark_results_ractor_20250818_205831.json +135 -0
  35. data/examples/performance_metrics/benchmark_results_test_20250818_204942.json +130 -0
  36. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204942.json +130 -0
  37. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204959.json +130 -0
  38. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205044.json +130 -0
  39. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205109.json +130 -0
  40. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205252.json +130 -0
  41. data/examples/performance_metrics/benchmark_results_unknown_20250819_172852.json +130 -0
  42. data/examples/performance_metrics/compare_benchmarks.rb +519 -0
  43. data/examples/performance_metrics/dead_letters.jsonl +3100 -0
  44. data/examples/performance_metrics/performance_benchmark.rb +344 -0
  45. data/examples/show_logger.rb +367 -0
  46. data/examples/show_me.rb +145 -0
  47. data/examples/temp.txt +94 -0
  48. data/examples/tmux_chat/bot_agent.rb +4 -2
  49. data/examples/tmux_chat/human_agent.rb +4 -2
  50. data/examples/tmux_chat/room_monitor.rb +4 -2
  51. data/examples/tmux_chat/shared_chat_system.rb +6 -3
  52. data/lib/smart_message/addressing.rb +259 -0
  53. data/lib/smart_message/base.rb +123 -599
  54. data/lib/smart_message/circuit_breaker.rb +2 -1
  55. data/lib/smart_message/configuration.rb +199 -0
  56. data/lib/smart_message/ddq/base.rb +71 -0
  57. data/lib/smart_message/ddq/memory.rb +109 -0
  58. data/lib/smart_message/ddq/redis.rb +168 -0
  59. data/lib/smart_message/ddq.rb +31 -0
  60. data/lib/smart_message/dead_letter_queue.rb +27 -10
  61. data/lib/smart_message/deduplication.rb +174 -0
  62. data/lib/smart_message/dispatcher.rb +259 -61
  63. data/lib/smart_message/header.rb +5 -0
  64. data/lib/smart_message/logger/base.rb +21 -1
  65. data/lib/smart_message/logger/default.rb +88 -138
  66. data/lib/smart_message/logger/lumberjack.rb +324 -0
  67. data/lib/smart_message/logger/null.rb +81 -0
  68. data/lib/smart_message/logger.rb +17 -9
  69. data/lib/smart_message/messaging.rb +100 -0
  70. data/lib/smart_message/plugins.rb +132 -0
  71. data/lib/smart_message/serializer/base.rb +25 -8
  72. data/lib/smart_message/serializer/json.rb +5 -4
  73. data/lib/smart_message/subscription.rb +196 -0
  74. data/lib/smart_message/transport/base.rb +72 -41
  75. data/lib/smart_message/transport/memory_transport.rb +7 -5
  76. data/lib/smart_message/transport/redis_transport.rb +15 -45
  77. data/lib/smart_message/transport/stdout_transport.rb +18 -8
  78. data/lib/smart_message/transport.rb +1 -34
  79. data/lib/smart_message/utilities.rb +142 -0
  80. data/lib/smart_message/version.rb +1 -1
  81. data/lib/smart_message/versioning.rb +85 -0
  82. data/lib/smart_message/wrapper.rb.bak +132 -0
  83. data/lib/smart_message.rb +74 -28
  84. data/smart_message.gemspec +3 -0
  85. metadata +83 -3
  86. data/lib/smart_message/serializer.rb +0 -10
  87. data/lib/smart_message/wrapper.rb +0 -43
data/docs/logging.md CHANGED
@@ -1,452 +1,508 @@
1
1
  # Logging in SmartMessage
2
2
 
3
- SmartMessage provides flexible logging capabilities through its plugin architecture. This document covers the built-in default logger as well as how to create custom loggers.
3
+ SmartMessage provides comprehensive logging capabilities with support for multiple output formats, colorization, structured logging, and file rolling. Built on the Lumberjack logging framework, it offers production-ready features with flexible configuration options.
4
4
 
5
5
  ## Table of Contents
6
6
 
7
- - [Default Logger](#default-logger)
7
+ - [Quick Start](#quick-start)
8
8
  - [Configuration Options](#configuration-options)
9
- - [Output Destinations](#output-destinations)
10
- - [Log Levels](#log-levels)
11
- - [Message Lifecycle Logging](#message-lifecycle-logging)
12
- - [Rails Integration](#rails-integration)
13
- - [Custom Loggers](#custom-loggers)
9
+ - [Output Formats](#output-formats)
10
+ - [Colorized Console Output](#colorized-console-output)
11
+ - [File Rolling](#file-rolling)
12
+ - [Structured Logging](#structured-logging)
13
+ - [Application Integration](#application-integration)
14
+ - [SmartMessage Integration](#smartmessage-integration)
14
15
  - [Examples](#examples)
16
+ - [Best Practices](#best-practices)
15
17
 
16
- ## Default Logger
18
+ ## Quick Start
17
19
 
18
- SmartMessage includes a built-in `SmartMessage::Logger::Default` class that automatically detects your environment and chooses the best logging approach:
19
-
20
- - **Rails Applications**: Uses `Rails.logger` with tagged logging
21
- - **Standalone Ruby**: Uses Ruby's standard `Logger` class with file output
22
-
23
- ### Quick Start
20
+ Configure SmartMessage logging through the global configuration block:
24
21
 
25
22
  ```ruby
26
- class MyMessage < SmartMessage::Base
27
- property :content
28
-
29
- config do
30
- transport SmartMessage::Transport::StdoutTransport.new
31
- serializer SmartMessage::Serializer::JSON.new
32
- logger SmartMessage::Logger::Default.new # Zero configuration!
33
- end
23
+ SmartMessage.configure do |config|
24
+ config.logger = STDOUT # Output destination
25
+ config.log_level = :info # Log level
26
+ config.log_format = :text # Format
27
+ config.log_colorize = true # Enable colors
34
28
  end
29
+
30
+ # Access the logger in your application
31
+ logger = SmartMessage.configuration.default_logger
32
+ logger.info("Application started", component: "main")
35
33
  ```
36
34
 
37
35
  ## Configuration Options
38
36
 
39
- The default logger accepts several configuration options:
37
+ ### Global Configuration
40
38
 
41
- ### Basic Configuration
39
+ All logging configuration is done through the `SmartMessage.configure` block:
42
40
 
43
41
  ```ruby
44
- # Use defaults (Rails.logger or log/smart_message.log)
45
- logger SmartMessage::Logger::Default.new
46
-
47
- # Custom log file path
48
- logger SmartMessage::Logger::Default.new(
49
- log_file: '/var/log/my_app/messages.log'
50
- )
42
+ SmartMessage.configure do |config|
43
+ # Required: Output destination
44
+ config.logger = STDOUT # or file path, STDERR
45
+
46
+ # Optional: Logging behavior
47
+ config.log_level = :info # :debug, :info, :warn, :error, :fatal
48
+ config.log_format = :text # :text, :json
49
+ config.log_colorize = true # Enable colorized console output
50
+ config.log_include_source = false # Include file/line information
51
+ config.log_structured_data = false # Enable structured metadata
52
+
53
+ # Optional: File rolling options
54
+ config.log_options = {
55
+ roll_by_size: true,
56
+ max_file_size: 10 * 1024 * 1024, # 10 MB
57
+ keep_files: 5, # Keep 5 old files
58
+ roll_by_date: false, # Alternative: date-based rolling
59
+ date_pattern: '%Y-%m-%d' # Daily pattern
60
+ }
61
+ end
62
+ ```
51
63
 
52
- # Custom log level
53
- logger SmartMessage::Logger::Default.new(
54
- level: Logger::DEBUG
55
- )
64
+ ### Configuration Details
56
65
 
57
- # Both custom file and level
58
- logger SmartMessage::Logger::Default.new(
59
- log_file: 'logs/custom.log',
60
- level: Logger::WARN
61
- )
62
- ```
66
+ | Option | Type | Default | Description |
67
+ |--------|------|---------|-------------|
68
+ | `logger` | String/IO | Required | Output destination (file path, STDOUT, STDERR) |
69
+ | `log_level` | Symbol | `:info` | Log level (`:debug`, `:info`, `:warn`, `:error`, `:fatal`) |
70
+ | `log_format` | Symbol | `:text` | Output format (`:text`, `:json`) |
71
+ | `log_colorize` | Boolean | `false` | Enable colorized console output |
72
+ | `log_include_source` | Boolean | `false` | Include source file and line information |
73
+ | `log_structured_data` | Boolean | `false` | Enable structured data logging |
74
+ | `log_options` | Hash | `{}` | Additional Lumberjack options |
63
75
 
64
- ## Output Destinations
76
+ ## Output Formats
65
77
 
66
- The default logger supports multiple output destinations:
78
+ ### Text Format (Default)
67
79
 
68
- ### File Logging (Default)
80
+ Human-readable text output with optional colorization:
69
81
 
70
82
  ```ruby
71
- # Default file location (Rails convention)
72
- logger SmartMessage::Logger::Default.new
73
- # log/smart_message.log
83
+ SmartMessage.configure do |config|
84
+ config.logger = STDOUT
85
+ config.log_format = :text
86
+ config.log_colorize = true
87
+ end
74
88
 
75
- # Custom file path
76
- logger SmartMessage::Logger::Default.new(
77
- log_file: '/var/log/application/messages.log'
78
- )
89
+ logger = SmartMessage.configuration.default_logger
90
+ logger.info("User login successful", user_id: 12345)
91
+ # Output: 2025-01-15 10:30:45 [INFO] User login successful user_id=12345
79
92
  ```
80
93
 
81
- **Features:**
82
- - Automatic log rotation (10 files, 10MB each)
83
- - Directory creation if needed
84
- - Timestamped entries with clean formatting
85
-
86
- ### STDOUT Logging
94
+ ### JSON Format
87
95
 
88
- Perfect for containerized applications (Docker, Kubernetes):
96
+ Machine-readable structured JSON output:
89
97
 
90
98
  ```ruby
91
- logger SmartMessage::Logger::Default.new(
92
- log_file: STDOUT,
93
- level: Logger::INFO
94
- )
95
- ```
96
-
97
- ### STDERR Logging
98
-
99
- For error-focused logging:
99
+ SmartMessage.configure do |config|
100
+ config.logger = "log/application.log"
101
+ config.log_format = :json
102
+ config.log_structured_data = true
103
+ config.log_include_source = true
104
+ end
100
105
 
101
- ```ruby
102
- logger SmartMessage::Logger::Default.new(
103
- log_file: STDERR,
104
- level: Logger::WARN
105
- )
106
+ logger = SmartMessage.configuration.default_logger
107
+ logger.info("User action", user_id: 12345, action: "login")
108
+ # Output: {"timestamp":"2025-01-15T10:30:45.123Z","level":"INFO","message":"User action","user_id":12345,"action":"login","source":"app.rb:42:in `authenticate`"}
106
109
  ```
107
110
 
108
- ### In-Memory Logging (Testing)
111
+ ## Colorized Console Output
112
+
113
+ SmartMessage provides colorized console output for improved readability during development:
109
114
 
110
115
  ```ruby
111
- require 'stringio'
116
+ SmartMessage.configure do |config|
117
+ config.logger = STDOUT
118
+ config.log_format = :text
119
+ config.log_colorize = true
120
+ end
112
121
 
113
- logger SmartMessage::Logger::Default.new(
114
- log_file: StringIO.new,
115
- level: Logger::DEBUG
116
- )
122
+ logger = SmartMessage.configuration.default_logger
123
+ logger.debug("Debug message") # Green background, black text, bold
124
+ logger.info("Info message") # Bright white text
125
+ logger.warn("Warning message") # Yellow background, white bold text
126
+ logger.error("Error message") # Light red background, white bold text
127
+ logger.fatal("Fatal message") # Light red background, yellow bold text
117
128
  ```
118
129
 
119
- ## Log Levels
130
+ ### Color Scheme
120
131
 
121
- The default logger supports all standard Ruby log levels:
132
+ | Level | Foreground | Background | Style |
133
+ |-------|------------|------------|-------|
134
+ | DEBUG | Black | Green | Bold |
135
+ | INFO | Bright White | None | None |
136
+ | WARN | White | Yellow | Bold |
137
+ | ERROR | White | Light Red | Bold |
138
+ | FATAL | Yellow | Light Red | Bold |
122
139
 
123
- | Level | Numeric Value | Description |
124
- |-------|--------------|-------------|
125
- | `Logger::DEBUG` | 0 | Detailed debugging information |
126
- | `Logger::INFO` | 1 | General information messages |
127
- | `Logger::WARN` | 2 | Warning messages |
128
- | `Logger::ERROR` | 3 | Error messages |
129
- | `Logger::FATAL` | 4 | Fatal error messages |
140
+ **Note:** Colorization is automatically disabled for file output to keep log files clean.
130
141
 
131
- ### Environment-Based Defaults
142
+ ## File Rolling
132
143
 
133
- The default logger automatically sets appropriate log levels based on your environment:
144
+ SmartMessage supports both size-based and date-based log file rolling:
134
145
 
135
- - **Rails Production**: `Logger::INFO`
136
- - **Rails Test**: `Logger::ERROR`
137
- - **Rails Development**: `Logger::DEBUG`
138
- - **Non-Rails**: `Logger::INFO`
146
+ ### Size-Based Rolling
139
147
 
140
- ## Message Lifecycle Logging
148
+ ```ruby
149
+ SmartMessage.configure do |config|
150
+ config.logger = "log/application.log"
151
+ config.log_options = {
152
+ roll_by_size: true,
153
+ max_file_size: 10 * 1024 * 1024, # 10 MB
154
+ keep_files: 5 # Keep 5 old files
155
+ }
156
+ end
157
+ ```
141
158
 
142
- The default logger automatically logs key events in the message lifecycle:
159
+ Files are named: `application.log`, `application.log.1`, `application.log.2`, etc.
143
160
 
144
- ### Message Creation
161
+ ### Date-Based Rolling
145
162
 
146
163
  ```ruby
147
- # Logged at DEBUG level
148
- message = MyMessage.new(content: "Hello")
149
- # [DEBUG] [SmartMessage] Created: MyMessage - {content: "Hello"}
164
+ SmartMessage.configure do |config|
165
+ config.logger = "log/application.log"
166
+ config.log_options = {
167
+ roll_by_date: true,
168
+ date_pattern: '%Y-%m-%d' # Daily rolling
169
+ }
170
+ end
150
171
  ```
151
172
 
152
- ### Message Publishing
173
+ Files are named: `application.log.2025-01-15`, `application.log.2025-01-14`, etc.
153
174
 
154
- ```ruby
155
- # Logged at INFO level
156
- message.publish
157
- # → [INFO] [SmartMessage] Published: MyMessage via StdoutTransport
158
- ```
175
+ ### Rolling Options
159
176
 
160
- ### Message Reception
177
+ | Option | Type | Description |
178
+ |--------|------|-------------|
179
+ | `roll_by_size` | Boolean | Enable size-based rolling |
180
+ | `max_file_size` | Integer | Maximum file size in bytes |
181
+ | `keep_files` | Integer | Number of old files to keep |
182
+ | `roll_by_date` | Boolean | Enable date-based rolling |
183
+ | `date_pattern` | String | Date format pattern |
161
184
 
162
- ```ruby
163
- # Logged at INFO level when message is received
164
- # → [INFO] [SmartMessage] Received: MyMessage (45 bytes)
165
- ```
185
+ ## Structured Logging
166
186
 
167
- ### Message Processing
187
+ Enable structured data logging to include metadata with your log entries:
168
188
 
169
189
  ```ruby
170
- # Logged at INFO level after processing
171
- # [INFO] [SmartMessage] Processed: MyMessage - Success
190
+ SmartMessage.configure do |config|
191
+ config.logger = "log/application.log"
192
+ config.log_format = :json
193
+ config.log_structured_data = true
194
+ config.log_include_source = true
195
+ end
196
+
197
+ logger = SmartMessage.configuration.default_logger
198
+
199
+ # Log with structured data
200
+ logger.info("User registration",
201
+ user_id: "user123",
202
+ email: "user@example.com",
203
+ registration_source: "web",
204
+ timestamp: Time.now.iso8601)
205
+
206
+ # Log with block for conditional data
207
+ logger.warn("Database slow query") do
208
+ {
209
+ query: "SELECT * FROM users WHERE status = ?",
210
+ duration_ms: 1500,
211
+ table: "users",
212
+ slow_query: true
213
+ }
214
+ end
172
215
  ```
173
216
 
174
- ### Subscription Management
217
+ ## Application Integration
218
+
219
+ ### Accessing the Logger
220
+
221
+ The configured logger is available globally:
175
222
 
176
223
  ```ruby
177
- # Logged at INFO level
178
- MyMessage.subscribe
179
- # → [INFO] [SmartMessage] Subscribed: MyMessage
224
+ # Get the globally configured logger
225
+ logger = SmartMessage.configuration.default_logger
180
226
 
181
- MyMessage.unsubscribe
182
- # [INFO] [SmartMessage] Unsubscribed: MyMessage
227
+ # Use in your application
228
+ logger.info("Application starting", version: "1.0.0")
229
+ logger.warn("Configuration missing", config_key: "database_url")
230
+ logger.error("Service unavailable", service: "payment_gateway")
183
231
  ```
184
232
 
185
- ### Error Logging
233
+ ### Class-Level Integration
186
234
 
187
235
  ```ruby
188
- # Logged at ERROR level with full stack trace (DEBUG level)
189
- # → [ERROR] [SmartMessage] Error in message processing: RuntimeError - Something went wrong
190
- # [DEBUG] [SmartMessage] Backtrace: ...
236
+ class OrderService
237
+ def initialize
238
+ @logger = SmartMessage.configuration.default_logger
239
+ end
240
+
241
+ def process_order(order)
242
+ @logger.info("Processing order",
243
+ order_id: order.id,
244
+ customer_id: order.customer_id,
245
+ amount: order.amount)
246
+
247
+ begin
248
+ # Process order logic
249
+ result = perform_processing(order)
250
+
251
+ @logger.info("Order completed",
252
+ order_id: order.id,
253
+ status: "success",
254
+ processing_time_ms: result[:duration])
255
+
256
+ rescue StandardError => e
257
+ @logger.error("Order processing failed",
258
+ order_id: order.id,
259
+ error: e.message,
260
+ error_class: e.class.name)
261
+ raise
262
+ end
263
+ end
264
+ end
191
265
  ```
192
266
 
193
- ## Rails Integration
267
+ ## SmartMessage Integration
194
268
 
195
- When running in a Rails application, the default logger provides enhanced integration:
196
-
197
- ### Automatic Detection
269
+ SmartMessage classes automatically use the configured logger:
198
270
 
199
271
  ```ruby
200
- # Automatically uses Rails.logger when available
201
- logger SmartMessage::Logger::Default.new
272
+ class OrderMessage < SmartMessage::Base
273
+ property :order_id, required: true
274
+ property :customer_id, required: true
275
+ property :amount, required: true
276
+
277
+ config do
278
+ transport SmartMessage::Transport::StdoutTransport.new
279
+ serializer SmartMessage::Serializer::Json.new
280
+ from 'order-service'
281
+ end
282
+
283
+ def process
284
+ # Logger is automatically available
285
+ logger.info("Processing order message",
286
+ message_id: _sm_header.uuid,
287
+ order_id: order_id,
288
+ customer_id: customer_id,
289
+ amount: amount)
290
+
291
+ # Log the complete message structure
292
+ logger.debug("Message details",
293
+ header: _sm_header.to_h,
294
+ payload: _sm_payload,
295
+ full_message: to_h)
296
+
297
+ # Process the order
298
+ case amount
299
+ when 0..100
300
+ logger.info("Small order processed", order_id: order_id)
301
+ when 101..1000
302
+ logger.warn("Medium order requires review", order_id: order_id)
303
+ else
304
+ logger.error("Large order requires manual approval",
305
+ order_id: order_id,
306
+ amount: amount)
307
+ end
308
+ end
309
+ end
202
310
  ```
203
311
 
204
- ### Tagged Logging
312
+ ## Examples
205
313
 
206
- ```ruby
207
- # In Rails, all SmartMessage logs are tagged
208
- Rails.logger.tagged('SmartMessage') do
209
- # All SmartMessage logging happens here
210
- end
211
- ```
314
+ ### Development Configuration
212
315
 
213
- ### Rails Log File Location
316
+ Perfect for local development with colorized console output:
214
317
 
215
318
  ```ruby
216
- # Uses Rails.root/log/smart_message.log when Rails is detected
217
- logger SmartMessage::Logger::Default.new
218
- # Rails.root.join('log', 'smart_message.log')
319
+ SmartMessage.configure do |config|
320
+ config.logger = STDOUT
321
+ config.log_level = :debug
322
+ config.log_format = :text
323
+ config.log_colorize = true
324
+ config.log_include_source = true
325
+ end
219
326
  ```
220
327
 
221
- ### Rails Environment Handling
328
+ ### Production Configuration
222
329
 
223
- The logger respects Rails environment settings:
330
+ Production setup with JSON logging and file rolling:
224
331
 
225
- - **Production**: INFO level, structured logging
226
- - **Development**: DEBUG level, verbose output
227
- - **Test**: ERROR level, minimal output
228
-
229
- ## Custom Loggers
332
+ ```ruby
333
+ SmartMessage.configure do |config|
334
+ config.logger = "/var/log/app/smartmessage.log"
335
+ config.log_level = :info
336
+ config.log_format = :json
337
+ config.log_colorize = false
338
+ config.log_structured_data = true
339
+ config.log_include_source = false
340
+ config.log_options = {
341
+ roll_by_size: true,
342
+ max_file_size: 50 * 1024 * 1024, # 50 MB
343
+ keep_files: 10
344
+ }
345
+ end
346
+ ```
230
347
 
231
- You can create custom loggers by inheriting from `SmartMessage::Logger::Base`:
348
+ ### Docker/Container Configuration
232
349
 
233
- ### Basic Custom Logger
350
+ Container-friendly setup with structured STDOUT logging:
234
351
 
235
352
  ```ruby
236
- class SmartMessage::Logger::MyCustomLogger < SmartMessage::Logger::Base
237
- def initialize(external_logger)
238
- @logger = external_logger
239
- end
240
-
241
- def log_message_created(message)
242
- @logger.debug "Created message: #{message.class.name}"
243
- end
244
-
245
- def log_message_published(message, transport)
246
- @logger.info "Published #{message.class.name} via #{transport.class.name}"
247
- end
248
-
249
- # Implement other lifecycle methods as needed...
353
+ SmartMessage.configure do |config|
354
+ config.logger = STDOUT
355
+ config.log_level = ENV['LOG_LEVEL']&.downcase&.to_sym || :info
356
+ config.log_format = :json
357
+ config.log_colorize = false
358
+ config.log_structured_data = true
359
+ config.log_include_source = true
250
360
  end
251
361
  ```
252
362
 
253
- ### Wrapper for Third-Party Loggers
363
+ ### Testing Configuration
364
+
365
+ Minimal logging for test environments:
254
366
 
255
367
  ```ruby
256
- # Semantic Logger example
257
- class SmartMessage::Logger::SemanticLogger < SmartMessage::Logger::Base
258
- def initialize(semantic_logger = nil)
259
- @logger = semantic_logger || SemanticLogger['SmartMessage']
260
- end
261
-
262
- def log_message_created(message)
263
- @logger.debug "Message created", message_class: message.class.name
264
- end
265
-
266
- def log_error(context, error)
267
- @logger.error "Error in #{context}", exception: error
268
- end
368
+ SmartMessage.configure do |config|
369
+ config.logger = STDERR
370
+ config.log_level = :error
371
+ config.log_format = :text
372
+ config.log_colorize = false
269
373
  end
270
374
  ```
271
375
 
272
- ### Multi-Logger (Broadcast)
376
+ ### Multiple Logger Configurations
377
+
378
+ You can create multiple logger instances for different purposes:
273
379
 
274
380
  ```ruby
275
- class SmartMessage::Logger::MultiLogger < SmartMessage::Logger::Base
276
- def initialize(*loggers)
277
- @loggers = loggers
278
- end
279
-
280
- def log_message_created(message)
281
- @loggers.each { |logger| logger.log_message_created(message) }
282
- end
283
-
284
- # Other methods follow same pattern...
381
+ # Configure global logger
382
+ SmartMessage.configure do |config|
383
+ config.logger = "log/application.log"
384
+ config.log_level = :info
385
+ config.log_format = :json
285
386
  end
286
387
 
287
- # Usage
288
- logger SmartMessage::Logger::MultiLogger.new(
289
- SmartMessage::Logger::Default.new(log_file: 'app.log'),
290
- SmartMessage::Logger::Default.new(log_file: STDOUT),
291
- SmartMessage::Logger::MyCustomLogger.new(external_system)
388
+ # Create additional loggers for specific needs
389
+ console_logger = SmartMessage::Logger::Lumberjack.new(
390
+ log_file: STDERR,
391
+ level: :warn,
392
+ format: :text,
393
+ colorize: true
394
+ )
395
+
396
+ debug_logger = SmartMessage::Logger::Lumberjack.new(
397
+ log_file: "log/debug.log",
398
+ level: :debug,
399
+ format: :text,
400
+ include_source: true
292
401
  )
402
+
403
+ # Use in application
404
+ console_logger.warn("Service degraded")
405
+ debug_logger.debug("Detailed debugging info", state: app_state)
293
406
  ```
294
407
 
295
- ## Examples
408
+ ## Best Practices
409
+
410
+ ### 1. Environment-Based Configuration
296
411
 
297
- ### Development Setup
412
+ Configure logging based on your environment:
298
413
 
299
414
  ```ruby
300
- class OrderMessage < SmartMessage::Base
301
- property :order_id, String, required: true
302
- property :customer_id, String, required: true
303
- property :amount, Float, required: true
304
-
305
- config do
306
- transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
307
- serializer SmartMessage::Serializer::JSON.new
308
-
309
- # Verbose logging for development
310
- logger SmartMessage::Logger::Default.new(
311
- log_file: STDOUT,
312
- level: Logger::DEBUG
313
- )
415
+ case ENV['RAILS_ENV'] || ENV['ENVIRONMENT']
416
+ when 'production'
417
+ SmartMessage.configure do |config|
418
+ config.logger = "/var/log/app/smartmessage.log"
419
+ config.log_level = :info
420
+ config.log_format = :json
421
+ config.log_structured_data = true
422
+ config.log_options = { roll_by_size: true, max_file_size: 50.megabytes, keep_files: 10 }
314
423
  end
315
-
316
- def self.process(message_header, message_payload)
317
- data = JSON.parse(message_payload)
318
-
319
- # Logger is available in process method
320
- logger.info "Processing order #{data['order_id']}"
321
-
322
- # Business logic here
323
- result = process_order(data)
324
-
325
- logger.info "Order #{data['order_id']} completed: #{result}"
326
- result
424
+ when 'development'
425
+ SmartMessage.configure do |config|
426
+ config.logger = STDOUT
427
+ config.log_level = :debug
428
+ config.log_format = :text
429
+ config.log_colorize = true
430
+ config.log_include_source = true
431
+ end
432
+ when 'test'
433
+ SmartMessage.configure do |config|
434
+ config.logger = STDERR
435
+ config.log_level = :error
436
+ config.log_format = :text
327
437
  end
328
438
  end
329
439
  ```
330
440
 
331
- ### Production Setup
441
+ ### 2. Structured Data
442
+
443
+ Use structured data for better log analysis:
332
444
 
333
445
  ```ruby
334
- class NotificationMessage < SmartMessage::Base
335
- property :recipient, String, required: true
336
- property :subject, String, required: true
337
- property :body, String, required: true
338
-
339
- config do
340
- transport SmartMessage::Transport::RedisTransport.new
341
- serializer SmartMessage::Serializer::JSON.new
342
-
343
- # Production logging with file rotation
344
- logger SmartMessage::Logger::Default.new(
345
- log_file: '/var/log/app/notifications.log',
346
- level: Logger::INFO
347
- )
348
- end
349
- end
446
+ # Good: Structured data
447
+ logger.info("User action",
448
+ user_id: user.id,
449
+ action: "login",
450
+ ip_address: request.ip,
451
+ user_agent: request.user_agent)
452
+
453
+ # Avoid: String interpolation
454
+ logger.info("User #{user.id} logged in from #{request.ip}")
350
455
  ```
351
456
 
352
- ### Docker/Kubernetes Setup
457
+ ### 3. Appropriate Log Levels
353
458
 
354
- ```ruby
355
- class EventMessage < SmartMessage::Base
356
- property :event_type, String, required: true
357
- property :data, Hash, required: true
358
-
359
- config do
360
- transport SmartMessage::Transport::RedisTransport.new(
361
- redis_url: ENV['REDIS_URL']
362
- )
363
- serializer SmartMessage::Serializer::JSON.new
364
-
365
- # Container-friendly STDOUT logging
366
- logger SmartMessage::Logger::Default.new(
367
- log_file: STDOUT,
368
- level: ENV['LOG_LEVEL']&.upcase&.to_sym || Logger::INFO
369
- )
370
- end
371
- end
372
- ```
459
+ Use log levels appropriately:
460
+
461
+ - **DEBUG**: Detailed information for diagnosing problems
462
+ - **INFO**: General information about program execution
463
+ - **WARN**: Something unexpected happened, but the application is still working
464
+ - **ERROR**: A serious problem occurred, but the application can continue
465
+ - **FATAL**: A very serious error occurred, application may not be able to continue
466
+
467
+ ### 4. Performance Considerations
468
+
469
+ - Use appropriate log levels in production (avoid DEBUG)
470
+ - Consider async logging for high-volume applications
471
+ - Use structured data instead of string concatenation
472
+ - Be mindful of log volume and storage costs
373
473
 
374
- ### Testing Setup
474
+ ### 5. Security
475
+
476
+ - Never log sensitive data (passwords, tokens, credit card numbers)
477
+ - Sanitize user input before logging
478
+ - Use structured data to avoid log injection attacks
375
479
 
376
480
  ```ruby
377
- # In test_helper.rb or similar
378
- class TestMessage < SmartMessage::Base
379
- property :test_data, Hash
380
-
381
- config do
382
- transport SmartMessage::Transport::MemoryTransport.new
383
- serializer SmartMessage::Serializer::JSON.new
384
-
385
- # Minimal logging for tests
386
- logger SmartMessage::Logger::Default.new(
387
- log_file: StringIO.new,
388
- level: Logger::FATAL # Only fatal errors in tests
389
- )
390
- end
391
- end
481
+ # Good: Structured data prevents injection
482
+ logger.info("User input received", user_input: params[:query])
483
+
484
+ # Avoid: Direct string interpolation
485
+ logger.info("User searched for: #{params[:query]}")
392
486
  ```
393
487
 
394
- ### Instance-Level Logger Override
488
+ ### 6. Testing
489
+
490
+ Test your logging configuration:
395
491
 
396
492
  ```ruby
397
- # Different logger for specific instances
398
- class PriorityMessage < SmartMessage::Base
399
- property :priority, String
400
- property :data, Hash
401
-
402
- config do
403
- transport SmartMessage::Transport::RedisTransport.new
404
- serializer SmartMessage::Serializer::JSON.new
405
- logger SmartMessage::Logger::Default.new # Default logger
406
- end
493
+ # Test that logs are being generated
494
+ require 'stringio'
495
+
496
+ log_output = StringIO.new
497
+ SmartMessage.configure do |config|
498
+ config.logger = log_output
499
+ config.log_level = :debug
407
500
  end
408
501
 
409
- # Override logger for high-priority messages
410
- priority_logger = SmartMessage::Logger::Default.new(
411
- log_file: '/var/log/priority.log',
412
- level: Logger::DEBUG
413
- )
502
+ logger = SmartMessage.configuration.default_logger
503
+ logger.info("Test message")
414
504
 
415
- urgent_message = PriorityMessage.new(priority: 'urgent', data: {...})
416
- urgent_message.logger(priority_logger) # Override for this instance
417
- urgent_message.publish
505
+ assert_includes log_output.string, "Test message"
418
506
  ```
419
507
 
420
- ## Best Practices
421
-
422
- 1. **Use the default logger** unless you have specific requirements
423
- 2. **Log to STDOUT** in containerized environments
424
- 3. **Use appropriate log levels** - avoid DEBUG in production
425
- 4. **Tag your logs** for better searchability
426
- 5. **Consider structured logging** for production systems
427
- 6. **Test your logging** - ensure logs are helpful for debugging
428
- 7. **Monitor log volume** - excessive logging can impact performance
429
- 8. **Rotate log files** to prevent disk space issues (default logger handles this)
430
-
431
- ## Troubleshooting
432
-
433
- ### No logs appearing
434
- - Check log level settings
435
- - Verify file permissions
436
- - Ensure logger is configured
437
-
438
- ### Too much logging
439
- - Increase log level (DEBUG → INFO → WARN → ERROR)
440
- - Consider filtering in production
441
-
442
- ### Performance issues
443
- - Lower log level in production
444
- - Use asynchronous logging for high-volume systems
445
- - Consider structured logging formats
446
-
447
- ### Rails integration not working
448
- - Ensure Rails is loaded before SmartMessage
449
- - Check that `Rails.logger` is available
450
- - Verify Rails environment is set correctly
451
-
452
- For more troubleshooting tips, see the [Troubleshooting Guide](troubleshooting.md).
508
+ For more information, see the comprehensive logging example at `examples/show_logger.rb`.