smart_message 0.0.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a7c214ec62b411d8f3bbf0925d6547fa135233684ac22483e028ffc76cc6cbe
4
- data.tar.gz: f80ce67e2ea59172a36a8c7b675864c93573bf1f2b94e294124bdf2bbb28ae73
3
+ metadata.gz: de5fce8e9cb793850301df5fdb9ad8a6954cf3a481cadc2deb625c373706723a
4
+ data.tar.gz: 0cc8067011377f0d574bc7f9bf1168ac2176fad7c7981cbd43f708e622a98fa0
5
5
  SHA512:
6
- metadata.gz: da70af3b299ef64e94d8cefd87b3bb25b0a50dd3b835d4765a6f26231c65d0fa69b2ccf3d204d8de666aca2e241dcb37e396dcd064aaeae895881885e8c1ea21
7
- data.tar.gz: fd2da658b323102bcb93e73f9b5d0ae843bd6afc7a8f031be7ebc206d89231f3304092d83de79524d7fd337f09a0bafad7b7bfc782e9f7a9820d32568c65e252
6
+ metadata.gz: bf7d1fc90d41bdbd3a8661f1f3e294915d29f267a68c13869926a4f829a00338f3878b03e14f26a7ccc9b248dc55b566e9988cb67aca7f6de596b94a51b5e885
7
+ data.tar.gz: 51c784d4183fe12862ff9250389a57233718604442e50303cdb941265971978e291fe7c3c1fec92509e6fa32bcc67b6b2fe8813b3cc1d06fa9d1f16645b181f3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_message (0.0.3)
4
+ smart_message (0.0.4)
5
5
  activesupport
6
6
  concurrent-ruby
7
7
  hashie
data/docs/README.md CHANGED
@@ -18,6 +18,7 @@ Welcome to the comprehensive documentation for SmartMessage, a Ruby gem that abs
18
18
  - [Property System](properties.md)
19
19
  - [Transport Layer](transports.md)
20
20
  - [Serializers](serializers.md)
21
+ - [Logging System](logging.md)
21
22
  - [Dispatcher & Routing](dispatcher.md)
22
23
  - [Message Headers](headers.md)
23
24
 
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).
@@ -0,0 +1,2 @@
1
+ /log/
2
+ *.log
@@ -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
@@ -0,0 +1,217 @@
1
+ # lib/smart_message/logger/default.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: true
4
+
5
+ require 'logger'
6
+ require 'fileutils'
7
+ require 'stringio'
8
+
9
+ module SmartMessage
10
+ module Logger
11
+ # Default logger implementation for SmartMessage
12
+ #
13
+ # This logger automatically detects and uses the best available logging option:
14
+ # - Rails.logger if running in a Rails application
15
+ # - Standard Ruby Logger writing to log/smart_message.log otherwise
16
+ #
17
+ # Usage:
18
+ # # In your message class
19
+ # config do
20
+ # logger SmartMessage::Logger::Default.new
21
+ # end
22
+ #
23
+ # # Or with custom options
24
+ # config do
25
+ # logger SmartMessage::Logger::Default.new(
26
+ # log_file: 'custom/path.log', # File path
27
+ # level: Logger::DEBUG
28
+ # )
29
+ # end
30
+ #
31
+ # # To log to STDOUT instead of a file
32
+ # config do
33
+ # logger SmartMessage::Logger::Default.new(
34
+ # log_file: STDOUT, # STDOUT or STDERR
35
+ # level: Logger::INFO
36
+ # )
37
+ # end
38
+ class Default < Base
39
+ attr_reader :logger, :log_file, :level
40
+
41
+ def initialize(log_file: nil, level: nil)
42
+ @log_file = log_file || default_log_file
43
+ @level = level || default_log_level
44
+
45
+ @logger = setup_logger
46
+ end
47
+
48
+ # Message lifecycle logging methods
49
+
50
+ def log_message_created(message)
51
+ logger.debug { "[SmartMessage] Created: #{message.class.name} - #{message_summary(message)}" }
52
+ end
53
+
54
+ def log_message_published(message, transport)
55
+ logger.info { "[SmartMessage] Published: #{message.class.name} via #{transport.class.name.split('::').last}" }
56
+ end
57
+
58
+ def log_message_received(message_class, payload)
59
+ logger.info { "[SmartMessage] Received: #{message_class.name} (#{payload.bytesize} bytes)" }
60
+ end
61
+
62
+ def log_message_processed(message_class, result)
63
+ logger.info { "[SmartMessage] Processed: #{message_class.name} - #{truncate(result.to_s, 100)}" }
64
+ end
65
+
66
+ def log_message_subscribe(message_class, handler = nil)
67
+ handler_desc = handler ? " with handler: #{handler}" : ""
68
+ logger.info { "[SmartMessage] Subscribed: #{message_class.name}#{handler_desc}" }
69
+ end
70
+
71
+ def log_message_unsubscribe(message_class)
72
+ logger.info { "[SmartMessage] Unsubscribed: #{message_class.name}" }
73
+ end
74
+
75
+ # Error logging
76
+
77
+ def log_error(context, error)
78
+ logger.error { "[SmartMessage] Error in #{context}: #{error.class.name} - #{error.message}" }
79
+ logger.debug { "[SmartMessage] Backtrace:\n#{error.backtrace.join("\n")}" } if error.backtrace
80
+ end
81
+
82
+ def log_warning(message)
83
+ logger.warn { "[SmartMessage] Warning: #{message}" }
84
+ end
85
+
86
+ # General purpose logging methods matching Ruby's Logger interface
87
+
88
+ def debug(message = nil, &block)
89
+ logger.debug(message, &block)
90
+ end
91
+
92
+ def info(message = nil, &block)
93
+ logger.info(message, &block)
94
+ end
95
+
96
+ def warn(message = nil, &block)
97
+ logger.warn(message, &block)
98
+ end
99
+
100
+ def error(message = nil, &block)
101
+ logger.error(message, &block)
102
+ end
103
+
104
+ def fatal(message = nil, &block)
105
+ logger.fatal(message, &block)
106
+ end
107
+
108
+ private
109
+
110
+ def setup_logger
111
+ if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
112
+ # Use Rails logger if available
113
+ setup_rails_logger
114
+ else
115
+ # Use standard Ruby logger
116
+ setup_ruby_logger
117
+ end
118
+ end
119
+
120
+ def setup_rails_logger
121
+ # Wrap Rails.logger to ensure our messages are properly tagged
122
+ RailsLoggerWrapper.new(Rails.logger, level: @level)
123
+ end
124
+
125
+ def setup_ruby_logger
126
+ # Handle IO objects (STDOUT, STDERR) vs file paths
127
+ if @log_file.is_a?(IO) || @log_file.is_a?(StringIO)
128
+ # For STDOUT/STDERR, don't use rotation
129
+ ruby_logger = ::Logger.new(@log_file)
130
+ else
131
+ # For file paths, ensure directory exists and use rotation
132
+ FileUtils.mkdir_p(File.dirname(@log_file))
133
+
134
+ ruby_logger = ::Logger.new(
135
+ @log_file,
136
+ 10, # Keep 10 old log files
137
+ 10_485_760 # Rotate when file reaches 10MB
138
+ )
139
+ end
140
+
141
+ ruby_logger.level = @level
142
+
143
+ # Set a clean formatter
144
+ ruby_logger.formatter = proc do |severity, datetime, progname, msg|
145
+ timestamp = datetime.strftime('%Y-%m-%d %H:%M:%S.%3N')
146
+ "[#{timestamp}] #{severity.ljust(5)} -- : #{msg}\n"
147
+ end
148
+
149
+ ruby_logger
150
+ end
151
+
152
+ def default_log_file
153
+ if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
154
+ Rails.root.join('log', 'smart_message.log').to_s
155
+ else
156
+ 'log/smart_message.log'
157
+ end
158
+ end
159
+
160
+ def default_log_level
161
+ if defined?(Rails) && Rails.respond_to?(:env)
162
+ case Rails.env
163
+ when 'production'
164
+ ::Logger::INFO
165
+ when 'test'
166
+ ::Logger::ERROR
167
+ else
168
+ ::Logger::DEBUG
169
+ end
170
+ else
171
+ # Default to INFO for non-Rails environments
172
+ ::Logger::INFO
173
+ end
174
+ end
175
+
176
+ def message_summary(message)
177
+ # Create a brief summary of the message for logging
178
+ if message.respond_to?(:to_h)
179
+ data = message.to_h
180
+ # Remove internal header for cleaner logs
181
+ data.delete(:_sm_header)
182
+ data.delete('_sm_header')
183
+ truncate(data.inspect, 200)
184
+ else
185
+ truncate(message.inspect, 200)
186
+ end
187
+ end
188
+
189
+ def truncate(string, max_length)
190
+ return string if string.length <= max_length
191
+ "#{string[0...max_length]}..."
192
+ end
193
+
194
+ # Internal wrapper for Rails.logger to handle tagged logging
195
+ class RailsLoggerWrapper
196
+ def initialize(rails_logger, level: nil)
197
+ @rails_logger = rails_logger
198
+ @rails_logger.level = level if level
199
+ end
200
+
201
+ def method_missing(method, *args, &block)
202
+ if @rails_logger.respond_to?(:tagged)
203
+ @rails_logger.tagged('SmartMessage') do
204
+ @rails_logger.send(method, *args, &block)
205
+ end
206
+ else
207
+ @rails_logger.send(method, *args, &block)
208
+ end
209
+ end
210
+
211
+ def respond_to_missing?(method, include_private = false)
212
+ @rails_logger.respond_to?(method, include_private)
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -3,5 +3,13 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  module SmartMessage::Logger
6
- # TODO: write this
6
+ # Logger module provides logging capabilities for SmartMessage
7
+ # The Default logger automatically uses Rails.logger if available,
8
+ # otherwise falls back to a standard Ruby Logger
7
9
  end # module SmartMessage::Logger
10
+
11
+ # Load the base class first
12
+ require_relative 'logger/base'
13
+
14
+ # Load the default logger implementation
15
+ require_relative 'logger/default'
@@ -3,5 +3,5 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  module SmartMessage
6
- VERSION = "0.0.3"
6
+ VERSION = '0.0.4'
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_message
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
@@ -204,17 +204,20 @@ files:
204
204
  - docs/examples.md
205
205
  - docs/getting-started.md
206
206
  - docs/ideas_to_think_about.md
207
+ - docs/logging.md
207
208
  - docs/message_processing.md
208
209
  - docs/proc_handlers_summary.md
209
210
  - docs/properties.md
210
211
  - docs/serializers.md
211
212
  - docs/transports.md
212
213
  - docs/troubleshooting.md
214
+ - examples/.gitignore
213
215
  - examples/01_point_to_point_orders.rb
214
216
  - examples/02_publish_subscribe_events.rb
215
217
  - examples/03_many_to_many_chat.rb
216
218
  - examples/04_redis_smart_home_iot.rb
217
219
  - examples/05_proc_handlers.rb
220
+ - examples/06_custom_logger_example.rb
218
221
  - examples/README.md
219
222
  - examples/smart_home_iot_dataflow.md
220
223
  - examples/tmux_chat/README.md
@@ -233,6 +236,7 @@ files:
233
236
  - lib/smart_message/header.rb
234
237
  - lib/smart_message/logger.rb
235
238
  - lib/smart_message/logger/base.rb
239
+ - lib/smart_message/logger/default.rb
236
240
  - lib/smart_message/property_descriptions.rb
237
241
  - lib/smart_message/serializer.rb
238
242
  - lib/smart_message/serializer/base.rb