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.
data/docs/logging.md ADDED
@@ -0,0 +1,452 @@
1
+ # Logging in SmartMessage
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.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Default Logger](#default-logger)
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)
14
+ - [Examples](#examples)
15
+
16
+ ## Default Logger
17
+
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
24
+
25
+ ```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
34
+ end
35
+ ```
36
+
37
+ ## Configuration Options
38
+
39
+ The default logger accepts several configuration options:
40
+
41
+ ### Basic Configuration
42
+
43
+ ```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
+ )
51
+
52
+ # Custom log level
53
+ logger SmartMessage::Logger::Default.new(
54
+ level: Logger::DEBUG
55
+ )
56
+
57
+ # Both custom file and level
58
+ logger SmartMessage::Logger::Default.new(
59
+ log_file: 'logs/custom.log',
60
+ level: Logger::WARN
61
+ )
62
+ ```
63
+
64
+ ## Output Destinations
65
+
66
+ The default logger supports multiple output destinations:
67
+
68
+ ### File Logging (Default)
69
+
70
+ ```ruby
71
+ # Default file location (Rails convention)
72
+ logger SmartMessage::Logger::Default.new
73
+ # → log/smart_message.log
74
+
75
+ # Custom file path
76
+ logger SmartMessage::Logger::Default.new(
77
+ log_file: '/var/log/application/messages.log'
78
+ )
79
+ ```
80
+
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
87
+
88
+ Perfect for containerized applications (Docker, Kubernetes):
89
+
90
+ ```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:
100
+
101
+ ```ruby
102
+ logger SmartMessage::Logger::Default.new(
103
+ log_file: STDERR,
104
+ level: Logger::WARN
105
+ )
106
+ ```
107
+
108
+ ### In-Memory Logging (Testing)
109
+
110
+ ```ruby
111
+ require 'stringio'
112
+
113
+ logger SmartMessage::Logger::Default.new(
114
+ log_file: StringIO.new,
115
+ level: Logger::DEBUG
116
+ )
117
+ ```
118
+
119
+ ## Log Levels
120
+
121
+ The default logger supports all standard Ruby log levels:
122
+
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 |
130
+
131
+ ### Environment-Based Defaults
132
+
133
+ The default logger automatically sets appropriate log levels based on your environment:
134
+
135
+ - **Rails Production**: `Logger::INFO`
136
+ - **Rails Test**: `Logger::ERROR`
137
+ - **Rails Development**: `Logger::DEBUG`
138
+ - **Non-Rails**: `Logger::INFO`
139
+
140
+ ## Message Lifecycle Logging
141
+
142
+ The default logger automatically logs key events in the message lifecycle:
143
+
144
+ ### Message Creation
145
+
146
+ ```ruby
147
+ # Logged at DEBUG level
148
+ message = MyMessage.new(content: "Hello")
149
+ # → [DEBUG] [SmartMessage] Created: MyMessage - {content: "Hello"}
150
+ ```
151
+
152
+ ### Message Publishing
153
+
154
+ ```ruby
155
+ # Logged at INFO level
156
+ message.publish
157
+ # → [INFO] [SmartMessage] Published: MyMessage via StdoutTransport
158
+ ```
159
+
160
+ ### Message Reception
161
+
162
+ ```ruby
163
+ # Logged at INFO level when message is received
164
+ # → [INFO] [SmartMessage] Received: MyMessage (45 bytes)
165
+ ```
166
+
167
+ ### Message Processing
168
+
169
+ ```ruby
170
+ # Logged at INFO level after processing
171
+ # → [INFO] [SmartMessage] Processed: MyMessage - Success
172
+ ```
173
+
174
+ ### Subscription Management
175
+
176
+ ```ruby
177
+ # Logged at INFO level
178
+ MyMessage.subscribe
179
+ # → [INFO] [SmartMessage] Subscribed: MyMessage
180
+
181
+ MyMessage.unsubscribe
182
+ # → [INFO] [SmartMessage] Unsubscribed: MyMessage
183
+ ```
184
+
185
+ ### Error Logging
186
+
187
+ ```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: ...
191
+ ```
192
+
193
+ ## Rails Integration
194
+
195
+ When running in a Rails application, the default logger provides enhanced integration:
196
+
197
+ ### Automatic Detection
198
+
199
+ ```ruby
200
+ # Automatically uses Rails.logger when available
201
+ logger SmartMessage::Logger::Default.new
202
+ ```
203
+
204
+ ### Tagged Logging
205
+
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
+ ```
212
+
213
+ ### Rails Log File Location
214
+
215
+ ```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')
219
+ ```
220
+
221
+ ### Rails Environment Handling
222
+
223
+ The logger respects Rails environment settings:
224
+
225
+ - **Production**: INFO level, structured logging
226
+ - **Development**: DEBUG level, verbose output
227
+ - **Test**: ERROR level, minimal output
228
+
229
+ ## Custom Loggers
230
+
231
+ You can create custom loggers by inheriting from `SmartMessage::Logger::Base`:
232
+
233
+ ### Basic Custom Logger
234
+
235
+ ```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...
250
+ end
251
+ ```
252
+
253
+ ### Wrapper for Third-Party Loggers
254
+
255
+ ```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
269
+ end
270
+ ```
271
+
272
+ ### Multi-Logger (Broadcast)
273
+
274
+ ```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...
285
+ end
286
+
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)
292
+ )
293
+ ```
294
+
295
+ ## Examples
296
+
297
+ ### Development Setup
298
+
299
+ ```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
+ )
314
+ 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
327
+ end
328
+ end
329
+ ```
330
+
331
+ ### Production Setup
332
+
333
+ ```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
350
+ ```
351
+
352
+ ### Docker/Kubernetes Setup
353
+
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
+ ```
373
+
374
+ ### Testing Setup
375
+
376
+ ```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
392
+ ```
393
+
394
+ ### Instance-Level Logger Override
395
+
396
+ ```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
407
+ end
408
+
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
+ )
414
+
415
+ urgent_message = PriorityMessage.new(priority: 'urgent', data: {...})
416
+ urgent_message.logger(priority_logger) # Override for this instance
417
+ urgent_message.publish
418
+ ```
419
+
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).