cmdx 1.0.1 → 1.1.1

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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/docs.md +9 -0
  3. data/.cursor/prompts/rspec.md +21 -0
  4. data/.cursor/prompts/yardoc.md +13 -0
  5. data/.rubocop.yml +2 -0
  6. data/CHANGELOG.md +29 -3
  7. data/README.md +2 -1
  8. data/docs/ai_prompts.md +269 -195
  9. data/docs/basics/call.md +126 -60
  10. data/docs/basics/chain.md +190 -160
  11. data/docs/basics/context.md +242 -154
  12. data/docs/basics/setup.md +302 -32
  13. data/docs/callbacks.md +382 -119
  14. data/docs/configuration.md +211 -49
  15. data/docs/deprecation.md +245 -0
  16. data/docs/getting_started.md +161 -39
  17. data/docs/internationalization.md +590 -70
  18. data/docs/interruptions/exceptions.md +135 -118
  19. data/docs/interruptions/faults.md +152 -127
  20. data/docs/interruptions/halt.md +134 -80
  21. data/docs/logging.md +183 -120
  22. data/docs/middlewares.md +165 -392
  23. data/docs/outcomes/result.md +140 -112
  24. data/docs/outcomes/states.md +134 -99
  25. data/docs/outcomes/statuses.md +204 -146
  26. data/docs/parameters/coercions.md +251 -289
  27. data/docs/parameters/defaults.md +224 -169
  28. data/docs/parameters/definitions.md +289 -141
  29. data/docs/parameters/namespacing.md +250 -161
  30. data/docs/parameters/validations.md +247 -159
  31. data/docs/testing.md +196 -203
  32. data/docs/workflows.md +146 -101
  33. data/lib/cmdx/.DS_Store +0 -0
  34. data/lib/cmdx/callback.rb +39 -55
  35. data/lib/cmdx/callback_registry.rb +80 -73
  36. data/lib/cmdx/chain.rb +65 -122
  37. data/lib/cmdx/chain_inspector.rb +23 -116
  38. data/lib/cmdx/chain_serializer.rb +34 -146
  39. data/lib/cmdx/coercion.rb +57 -0
  40. data/lib/cmdx/coercion_registry.rb +113 -0
  41. data/lib/cmdx/coercions/array.rb +18 -36
  42. data/lib/cmdx/coercions/big_decimal.rb +21 -33
  43. data/lib/cmdx/coercions/boolean.rb +21 -40
  44. data/lib/cmdx/coercions/complex.rb +18 -31
  45. data/lib/cmdx/coercions/date.rb +20 -39
  46. data/lib/cmdx/coercions/date_time.rb +22 -39
  47. data/lib/cmdx/coercions/float.rb +19 -32
  48. data/lib/cmdx/coercions/hash.rb +22 -41
  49. data/lib/cmdx/coercions/integer.rb +20 -33
  50. data/lib/cmdx/coercions/rational.rb +20 -32
  51. data/lib/cmdx/coercions/string.rb +23 -31
  52. data/lib/cmdx/coercions/time.rb +24 -40
  53. data/lib/cmdx/coercions/virtual.rb +14 -31
  54. data/lib/cmdx/configuration.rb +101 -162
  55. data/lib/cmdx/context.rb +34 -166
  56. data/lib/cmdx/core_ext/hash.rb +42 -67
  57. data/lib/cmdx/core_ext/module.rb +35 -79
  58. data/lib/cmdx/core_ext/object.rb +63 -98
  59. data/lib/cmdx/correlator.rb +59 -154
  60. data/lib/cmdx/error.rb +37 -202
  61. data/lib/cmdx/errors.rb +153 -216
  62. data/lib/cmdx/fault.rb +68 -150
  63. data/lib/cmdx/faults.rb +26 -137
  64. data/lib/cmdx/immutator.rb +22 -110
  65. data/lib/cmdx/lazy_struct.rb +110 -186
  66. data/lib/cmdx/log_formatters/json.rb +14 -40
  67. data/lib/cmdx/log_formatters/key_value.rb +14 -40
  68. data/lib/cmdx/log_formatters/line.rb +14 -48
  69. data/lib/cmdx/log_formatters/logstash.rb +14 -57
  70. data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
  71. data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
  72. data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
  73. data/lib/cmdx/log_formatters/raw.rb +19 -49
  74. data/lib/cmdx/logger.rb +22 -79
  75. data/lib/cmdx/logger_ansi.rb +31 -72
  76. data/lib/cmdx/logger_serializer.rb +74 -103
  77. data/lib/cmdx/middleware.rb +56 -60
  78. data/lib/cmdx/middleware_registry.rb +82 -77
  79. data/lib/cmdx/middlewares/correlate.rb +41 -226
  80. data/lib/cmdx/middlewares/timeout.rb +46 -185
  81. data/lib/cmdx/parameter.rb +167 -183
  82. data/lib/cmdx/parameter_evaluator.rb +231 -0
  83. data/lib/cmdx/parameter_inspector.rb +37 -55
  84. data/lib/cmdx/parameter_registry.rb +65 -84
  85. data/lib/cmdx/parameter_serializer.rb +32 -76
  86. data/lib/cmdx/railtie.rb +24 -107
  87. data/lib/cmdx/result.rb +254 -259
  88. data/lib/cmdx/result_ansi.rb +28 -80
  89. data/lib/cmdx/result_inspector.rb +34 -70
  90. data/lib/cmdx/result_logger.rb +23 -77
  91. data/lib/cmdx/result_serializer.rb +59 -125
  92. data/lib/cmdx/rspec/matchers.rb +28 -0
  93. data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
  94. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
  95. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
  96. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
  97. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
  98. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
  99. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
  100. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
  101. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
  102. data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
  103. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
  104. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
  105. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
  106. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
  107. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
  108. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
  109. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
  110. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
  111. data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
  112. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
  113. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
  114. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
  115. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
  116. data/lib/cmdx/task.rb +336 -427
  117. data/lib/cmdx/task_deprecator.rb +52 -0
  118. data/lib/cmdx/task_processor.rb +246 -0
  119. data/lib/cmdx/task_serializer.rb +34 -69
  120. data/lib/cmdx/utils/ansi_color.rb +13 -89
  121. data/lib/cmdx/utils/log_timestamp.rb +13 -42
  122. data/lib/cmdx/utils/monotonic_runtime.rb +11 -63
  123. data/lib/cmdx/utils/name_affix.rb +21 -71
  124. data/lib/cmdx/validator.rb +57 -0
  125. data/lib/cmdx/validator_registry.rb +108 -0
  126. data/lib/cmdx/validators/exclusion.rb +55 -94
  127. data/lib/cmdx/validators/format.rb +31 -85
  128. data/lib/cmdx/validators/inclusion.rb +65 -110
  129. data/lib/cmdx/validators/length.rb +117 -133
  130. data/lib/cmdx/validators/numeric.rb +123 -130
  131. data/lib/cmdx/validators/presence.rb +38 -79
  132. data/lib/cmdx/version.rb +1 -7
  133. data/lib/cmdx/workflow.rb +58 -330
  134. data/lib/cmdx.rb +1 -1
  135. data/lib/generators/cmdx/install_generator.rb +14 -31
  136. data/lib/generators/cmdx/task_generator.rb +39 -55
  137. data/lib/generators/cmdx/templates/install.rb +24 -6
  138. data/lib/generators/cmdx/workflow_generator.rb +41 -66
  139. data/lib/locales/ar.yml +0 -1
  140. data/lib/locales/cs.yml +0 -1
  141. data/lib/locales/da.yml +0 -1
  142. data/lib/locales/de.yml +0 -1
  143. data/lib/locales/el.yml +0 -1
  144. data/lib/locales/en.yml +0 -1
  145. data/lib/locales/es.yml +0 -1
  146. data/lib/locales/fi.yml +0 -1
  147. data/lib/locales/fr.yml +0 -1
  148. data/lib/locales/he.yml +0 -1
  149. data/lib/locales/hi.yml +0 -1
  150. data/lib/locales/it.yml +0 -1
  151. data/lib/locales/ja.yml +0 -1
  152. data/lib/locales/ko.yml +0 -1
  153. data/lib/locales/nl.yml +0 -1
  154. data/lib/locales/no.yml +0 -1
  155. data/lib/locales/pl.yml +0 -1
  156. data/lib/locales/pt.yml +0 -1
  157. data/lib/locales/ru.yml +0 -1
  158. data/lib/locales/sv.yml +0 -1
  159. data/lib/locales/th.yml +0 -1
  160. data/lib/locales/tr.yml +0 -1
  161. data/lib/locales/vi.yml +0 -1
  162. data/lib/locales/zh.yml +0 -1
  163. metadata +36 -8
  164. data/lib/cmdx/parameter_validator.rb +0 -81
  165. data/lib/cmdx/parameter_value.rb +0 -244
  166. data/lib/cmdx/parameters_inspector.rb +0 -72
  167. data/lib/cmdx/parameters_serializer.rb +0 -115
  168. data/lib/cmdx/rspec/result_matchers.rb +0 -917
  169. data/lib/cmdx/rspec/task_matchers.rb +0 -570
  170. data/lib/cmdx/validators/custom.rb +0 -102
data/docs/logging.md CHANGED
@@ -6,96 +6,109 @@ CMDx provides comprehensive automatic logging for task execution with structured
6
6
  - [TLDR](#tldr)
7
7
  - [Log Formatters](#log-formatters)
8
8
  - [Standard Formatters](#standard-formatters)
9
- - [Stylized Formatters (ANSI Colors)](#stylized-formatters-ansi-colors)
9
+ - [Stylized Formatters](#stylized-formatters)
10
10
  - [Sample Output](#sample-output)
11
- - [Success Result](#success-result)
12
- - [Skipped Result](#skipped-result)
13
- - [Failed Result](#failed-result)
14
- - [Failure Chain (Workflow Workflows)](#failure-chain-workflow-workflows)
15
11
  - [Configuration](#configuration)
16
12
  - [Global Configuration](#global-configuration)
17
13
  - [Task-Specific Configuration](#task-specific-configuration)
18
- - [Environment-Specific Configuration](#environment-specific-configuration)
19
14
  - [Severity Mapping](#severity-mapping)
20
15
  - [Manual Logging](#manual-logging)
21
- - [Advanced Formatter Usage](#advanced-formatter-usage)
22
- - [Custom Formatter](#custom-formatter)
16
+ - [Error Handling](#error-handling)
17
+ - [Advanced Usage](#advanced-usage)
18
+ - [Custom Formatters](#custom-formatters)
23
19
  - [Multi-Destination Logging](#multi-destination-logging)
24
20
  - [Log Data Structure](#log-data-structure)
25
21
 
26
22
  ## TLDR
27
23
 
28
- - **Automatic logging** - All task results logged after completion with structured data
29
- - **8 formatters** - Standard (Line, Json, KeyValue, Logstash, Raw) and Stylized (Pretty variants)
30
- - **Configuration** - Global via `CMDx.configure` or task-specific via `task_settings!`
31
- - **Severity mapping** - Success=INFO, Skipped=WARN, Failed=ERROR
32
- - **Rich metadata** - Includes runtime, chain_id, status, context, and failure chains
33
- - **Manual logging** - Access `logger` within tasks for custom messages
24
+ ```ruby
25
+ # Automatic logging - no setup required
26
+ class ProcessOrderTask < CMDx::Task
27
+ def call
28
+ # Task execution automatically logged with metadata
29
+ end
30
+ end
34
31
 
35
- ## Log Formatters
32
+ # Custom formatter
33
+ cmd_settings!(log_formatter: CMDx::LogFormatters::Json.new)
36
34
 
37
- CMDx provides 8 built-in log formatters organized into standard and stylized categories:
35
+ # Manual logging within tasks
36
+ logger.info "Processing order", order_id: context.order_id
38
37
 
39
- ### Standard Formatters
40
- - **`Line`** - Traditional single-line format similar to Ruby's Logger
41
- - **`Json`** - Compact single-line JSON for structured logging systems
42
- - **`KeyValue`** - Space-separated key=value pairs for easy parsing
43
- - **`Logstash`** - ELK stack compatible JSON with @version and @timestamp fields
44
- - **`Raw`** - Minimal output containing only the message content
38
+ # Global configuration
39
+ CMDx.configure do |config|
40
+ config.logger = Logger.new("log/cmdx.log")
41
+ config.log_formatter = CMDx::LogFormatters::Json.new
42
+ end
43
+ ```
45
44
 
46
- ### Stylized Formatters (ANSI Colors)
45
+ ## Log Formatters
47
46
 
48
47
  > [!NOTE]
49
- > Stylized formatters include ANSI color codes for terminal readability and are best suited for development environments.
48
+ > All formatters automatically include execution metadata. Choose based on your environment: stylized for development, standard for production.
50
49
 
51
- - **`PrettyLine`** - Colorized line format (default)
52
- - **`PrettyJson`** - Human-readable multi-line JSON with syntax highlighting
53
- - **`PrettyKeyValue`** - Colorized key=value pairs for terminal readability
50
+ ### Standard Formatters
54
51
 
55
- ## Sample Output
52
+ | Formatter | Use Case | Output Style |
53
+ |-----------|----------|--------------|
54
+ | `Line` | Traditional logging | Single-line format |
55
+ | `Json` | Structured systems | Compact JSON |
56
+ | `KeyValue` | Log parsing | `key=value` pairs |
57
+ | `Logstash` | ELK stack | JSON with @version/@timestamp |
58
+ | `Raw` | Minimal output | Message content only |
56
59
 
57
- ### Success Result
58
- ```txt
59
- I, [2022-07-17T18:43:15.000000 #3784] INFO -- CreateOrderTask: index=0 chain_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=CreateOrderTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=complete status=success outcome=success metadata={order_id: 123, confirmation: "ABC123"} runtime=0.45 origin=CMDx
60
- ```
60
+ ### Stylized Formatters
61
61
 
62
- ### Skipped Result
63
- ```txt
64
- W, [2022-07-17T18:43:15.000000 #3784] WARN -- ValidatePaymentTask: index=0 chain_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=ValidatePaymentTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=skipped outcome=skipped metadata={reason: "Order already processed"} runtime=0.02 origin=CMDx
65
- ```
62
+ > [!TIP]
63
+ > Stylized formatters include ANSI color codes for better terminal readability in development environments.
66
64
 
67
- ### Failed Result
68
- ```txt
69
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- ProcessPaymentTask: index=0 chain_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=ProcessPaymentTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=failed metadata={reason: "Payment declined", error_code: "INSUFFICIENT_FUNDS"} runtime=0.15 origin=CMDx
70
- ```
65
+ | Formatter | Description |
66
+ |-----------|-------------|
67
+ | `PrettyLine` | Colorized line format (default) |
68
+ | `PrettyJson` | Multi-line JSON with syntax highlighting |
69
+ | `PrettyKeyValue` | Colorized key=value pairs |
71
70
 
72
- ### Failure Chain (Workflow Workflows)
73
- ```txt
74
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- OrderCreationWorkflow: index=0 chain_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Workflow class=OrderCreationWorkflow id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=interrupted metadata={} runtime=0.75 caused_failure={index: 2, class: "ValidatePaymentTask", status: "failed"} threw_failure={index: 1, class: "ProcessPaymentTask", status: "failed"} origin=CMDx
71
+ ## Sample Output
72
+
73
+ ```ruby
74
+ # Success (INFO level)
75
+ I, [2022-07-17T18:43:15.000000 #3784] INFO -- CreateOrderTask:
76
+ index=0 chain_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task
77
+ class=CreateOrderTask status=success metadata={order_id: 123} runtime=0.45
78
+
79
+ # Skipped (WARN level)
80
+ W, [2022-07-17T18:43:15.000000 #3784] WARN -- ValidatePaymentTask:
81
+ index=1 status=skipped metadata={reason: "Order already processed"} runtime=0.02
82
+
83
+ # Failed (ERROR level)
84
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- ProcessPaymentTask:
85
+ index=2 status=failed metadata={error_code: "INSUFFICIENT_FUNDS"} runtime=0.15
86
+
87
+ # Workflow failure chain
88
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- OrderWorkflow:
89
+ caused_failure={index: 2, class: "ProcessPaymentTask", status: "failed"}
90
+ threw_failure={index: 1, class: "ValidatePaymentTask", status: "failed"}
75
91
  ```
76
92
 
77
93
  ## Configuration
78
94
 
79
95
  ### Global Configuration
80
96
 
81
- Configure logging globally in your CMDx initializer:
82
-
83
97
  ```ruby
84
98
  CMDx.configure do |config|
85
- config.logger = Logger.new("log/cmdx.log", formatter: CMDx::LogFormatters::Json.new)
86
- config.logger.level = Logger::INFO
99
+ config.logger = Logger.new("log/cmdx.log")
100
+ config.log_formatter = CMDx::LogFormatters::Json.new
101
+ config.log_level = Logger::INFO
87
102
  end
88
103
  ```
89
104
 
90
105
  ### Task-Specific Configuration
91
106
 
92
- Override logging settings for individual tasks:
93
-
94
107
  ```ruby
95
108
  class SendEmailTask < CMDx::Task
96
- task_settings!(
109
+ cmd_settings!(
97
110
  logger: Rails.logger,
98
- log_formatter: CMDx::LogFormatters::Json.new,
111
+ log_formatter: CMDx::LogFormatters::Logstash.new,
99
112
  log_level: Logger::WARN
100
113
  )
101
114
 
@@ -104,12 +117,11 @@ class SendEmailTask < CMDx::Task
104
117
  end
105
118
  end
106
119
 
107
- # Base class with shared logging configuration
120
+ # Base class configuration
108
121
  class ApplicationTask < CMDx::Task
109
- task_settings!(
122
+ cmd_settings!(
110
123
  logger: Logger.new("log/tasks.log"),
111
- log_formatter: CMDx::LogFormatters::Logstash.new,
112
- log_level: Logger::INFO
124
+ log_formatter: CMDx::LogFormatters::Json.new
113
125
  )
114
126
  end
115
127
  ```
@@ -117,55 +129,99 @@ end
117
129
  ## Severity Mapping
118
130
 
119
131
  > [!IMPORTANT]
120
- > CMDx automatically maps result statuses to appropriate log severity levels. Manual log level overrides are not recommended.
132
+ > CMDx automatically maps result statuses to log severity levels. Manual overrides are not recommended as they break monitoring conventions.
121
133
 
122
- | Result Status | Log Level | Use Case |
123
- | ------------- | --------- | -------- |
124
- | `success` | `INFO` | Normal successful completion |
125
- | `skipped` | `WARN` | Intentional skip (business logic) |
126
- | `failed` | `ERROR` | Task failure or exception |
134
+ | Status | Log Level | When Used |
135
+ |--------|-----------|-----------|
136
+ | `success` | `INFO` | Normal completion |
137
+ | `skipped` | `WARN` | Intentional skip via business logic |
138
+ | `failed` | `ERROR` | Task failure or exception |
127
139
 
128
140
  ## Manual Logging
129
141
 
130
- Access the configured logger within tasks for custom log messages:
131
-
132
142
  ```ruby
133
143
  class ProcessOrderTask < CMDx::Task
134
144
  def call
145
+ # Structured logging with metadata
135
146
  logger.info "Starting order processing", order_id: context.order_id
136
147
 
137
148
  # Performance-optimized debug logging
138
149
  logger.debug { "Order details: #{context.order.inspect}" }
139
150
 
140
- # Structured logging
141
- logger.info "Payment processed", {
142
- order_id: context.order_id,
143
- amount: context.order.total,
144
- payment_method: context.payment_method
145
- }
146
-
147
- # Exception handling with logging
151
+ # Exception context
148
152
  begin
149
153
  validate_inventory
150
154
  rescue StandardError => e
151
- logger.error "Inventory validation failed: #{e.message}", {
155
+ logger.error "Inventory validation failed", {
152
156
  exception: e.class.name,
153
- order_id: context.order_id
157
+ order_id: context.order_id,
158
+ message: e.message
154
159
  }
155
160
  raise
156
161
  end
162
+
163
+ # Success with metadata
164
+ logger.info "Order processed successfully", {
165
+ order_id: context.order_id,
166
+ amount: context.order.total
167
+ }
157
168
  end
158
169
  end
159
170
  ```
160
171
 
161
- ## Advanced Formatter Usage
172
+ ## Error Handling
162
173
 
163
- ### Custom Formatter
174
+ > [!WARNING]
175
+ > Logger configuration errors are handled gracefully, falling back to STDOUT with PrettyLine formatter to ensure execution continuity.
164
176
 
165
- Create custom formatters for specific output requirements:
177
+ ### Configuration Error Recovery
166
178
 
167
179
  ```ruby
168
- class SlackLogFormatter
180
+ # Invalid logger configuration
181
+ CMDx.configure do |config|
182
+ config.logger = Logger.new("/invalid/path/cmdx.log") # Permission denied
183
+ end
184
+
185
+ # CMDx automatically falls back to:
186
+ # Logger.new(STDOUT, formatter: CMDx::LogFormatters::PrettyLine.new)
187
+ ```
188
+
189
+ ### Formatter Error Handling
190
+
191
+ ```ruby
192
+ class BrokenFormatter
193
+ def call(severity, time, task, message)
194
+ raise StandardError, "Formatter error"
195
+ end
196
+ end
197
+
198
+ class TestTask < CMDx::Task
199
+ cmd_settings!(log_formatter: BrokenFormatter.new)
200
+
201
+ def call
202
+ # Execution continues with fallback formatter
203
+ # Error logged to STDERR for debugging
204
+ end
205
+ end
206
+ ```
207
+
208
+ ### Log Level Validation
209
+
210
+ ```ruby
211
+ # Invalid log levels default to INFO
212
+ CMDx.configure do |config|
213
+ config.log_level = "INVALID" # → Logger::INFO
214
+ end
215
+
216
+ # Valid levels: DEBUG, INFO, WARN, ERROR, FATAL
217
+ ```
218
+
219
+ ## Advanced Usage
220
+
221
+ ### Custom Formatters
222
+
223
+ ```ruby
224
+ class AlertFormatter
169
225
  def call(severity, time, task, message)
170
226
  emoji = case severity
171
227
  when 'INFO' then '✅'
@@ -174,21 +230,23 @@ class SlackLogFormatter
174
230
  else '📝'
175
231
  end
176
232
 
177
- "#{emoji} #{task.class.name}: #{message}\n"
233
+ "[#{time.strftime('%H:%M:%S')}] #{emoji} #{task.class.name}: #{message}\n"
178
234
  end
179
235
  end
180
236
 
181
- class SendNotificationTask < CMDx::Task
182
- task_settings!(
183
- logger: Logger.new("log/notifications.log", formatter: SlackLogFormatter.new)
184
- )
237
+ class NotificationTask < CMDx::Task
238
+ cmd_settings!(log_formatter: AlertFormatter.new)
239
+
240
+ def call
241
+ # Uses custom emoji-based formatting
242
+ end
185
243
  end
186
244
  ```
187
245
 
188
246
  ### Multi-Destination Logging
189
247
 
190
248
  > [!TIP]
191
- > Use multi-destination logging to send output to both console and files simultaneously during development.
249
+ > Combine multiple loggers to output to both console and files simultaneously during development.
192
250
 
193
251
  ```ruby
194
252
  class MultiLogger
@@ -197,21 +255,13 @@ class MultiLogger
197
255
  end
198
256
 
199
257
  %w[debug info warn error fatal].each do |level|
200
- define_method(level) do |message = nil, &block|
201
- @loggers.each { |logger| logger.send(level, message, &block) }
258
+ define_method(level) do |message = nil, **metadata, &block|
259
+ @loggers.each { |logger| logger.send(level, message, **metadata, &block) }
202
260
  end
203
261
  end
204
-
205
- def formatter=(formatter)
206
- @loggers.each { |logger| logger.formatter = formatter }
207
- end
208
-
209
- def level=(level)
210
- @loggers.each { |logger| logger.level = level }
211
- end
212
262
  end
213
263
 
214
- # Usage
264
+ # Configuration
215
265
  CMDx.configure do |config|
216
266
  config.logger = MultiLogger.new(
217
267
  Logger.new(STDOUT, formatter: CMDx::LogFormatters::PrettyLine.new),
@@ -222,32 +272,45 @@ end
222
272
 
223
273
  ## Log Data Structure
224
274
 
225
- CMDx logs contain comprehensive execution metadata:
226
-
227
- #### Standard Fields
228
- - `severity` - Log level (INFO, WARN, ERROR)
229
- - `pid` - Process ID for multi-process debugging
230
- - `timestamp` - ISO 8601 formatted execution time
231
- - `origin` - Always "CMDx" for filtering
232
-
233
- #### Task Identification
234
- - `index` - Position in execution sequence
235
- - `chain_id` - Unique identifier for execution chain
236
- - `type` - Task or Workflow
237
- - `class` - Task class name
238
- - `id` - Unique task instance identifier
239
- - `tags` - Custom tags for categorization
240
-
241
- #### Execution Information
242
- - `state` - Execution lifecycle state (initialized, executing, complete, interrupted)
243
- - `status` - Business logic outcome (success, skipped, failed)
244
- - `outcome` - Final result classification
245
- - `metadata` - Custom data from skip!/fail! calls
246
- - `runtime` - Execution time in seconds
247
-
248
- #### Failure Chain (Complex Workflows)
249
- - `caused_failure` - Original failing task information
250
- - `threw_failure` - Task that propagated the failure
275
+ > [!NOTE]
276
+ > All log entries include comprehensive execution metadata for debugging and monitoring. Field availability depends on the execution context.
277
+
278
+ ### Core Fields
279
+
280
+ | Field | Description | Example |
281
+ |-------|-------------|---------|
282
+ | `severity` | Log level | `INFO`, `WARN`, `ERROR` |
283
+ | `timestamp` | ISO 8601 execution time | `2022-07-17T18:43:15.000000` |
284
+ | `pid` | Process ID | `3784` |
285
+ | `origin` | Source identifier | `CMDx` |
286
+
287
+ ### Task Information
288
+
289
+ | Field | Description | Example |
290
+ |-------|-------------|---------|
291
+ | `index` | Execution sequence position | `0`, `1`, `2` |
292
+ | `chain_id` | Unique execution chain ID | `018c2b95-b764-7615...` |
293
+ | `type` | Execution unit type | `Task`, `Workflow` |
294
+ | `class` | Task class name | `ProcessOrderTask` |
295
+ | `id` | Unique task instance ID | `018c2b95-b764-7615...` |
296
+ | `tags` | Custom categorization | `["priority", "payment"]` |
297
+
298
+ ### Execution Data
299
+
300
+ | Field | Description | Example |
301
+ |-------|-------------|---------|
302
+ | `state` | Lifecycle state | `complete`, `interrupted` |
303
+ | `status` | Business outcome | `success`, `skipped`, `failed` |
304
+ | `outcome` | Final classification | `success`, `interrupted` |
305
+ | `metadata` | Custom task data | `{order_id: 123, amount: 99.99}` |
306
+ | `runtime` | Execution time (seconds) | `0.45` |
307
+
308
+ ### Failure Chain (Workflows)
309
+
310
+ | Field | Description |
311
+ |-------|-------------|
312
+ | `caused_failure` | Original failing task details |
313
+ | `threw_failure` | Task that propagated the failure |
251
314
 
252
315
  ---
253
316