cmdx 0.4.0 → 1.0.0
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 +4 -4
- data/.DS_Store +0 -0
- data/.cursor/rules/cursor-instructions.mdc +6 -0
- data/.rubocop.yml +16 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +42 -1
- data/README.md +72 -25
- data/docs/ai_prompts.md +309 -0
- data/docs/basics/call.md +225 -14
- data/docs/basics/chain.md +271 -0
- data/docs/basics/context.md +232 -33
- data/docs/basics/setup.md +76 -12
- data/docs/callbacks.md +273 -0
- data/docs/configuration.md +158 -28
- data/docs/getting_started.md +134 -22
- data/docs/interruptions/exceptions.md +189 -11
- data/docs/interruptions/faults.md +187 -44
- data/docs/interruptions/halt.md +179 -35
- data/docs/logging.md +194 -53
- data/docs/middlewares.md +735 -0
- data/docs/outcomes/result.md +296 -10
- data/docs/outcomes/states.md +212 -19
- data/docs/outcomes/statuses.md +284 -18
- data/docs/parameters/coercions.md +402 -29
- data/docs/parameters/defaults.md +249 -25
- data/docs/parameters/definitions.md +238 -72
- data/docs/parameters/namespacing.md +250 -27
- data/docs/parameters/validations.md +193 -168
- data/docs/testing.md +550 -0
- data/docs/tips_and_tricks.md +95 -43
- data/docs/workflows.md +319 -0
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callback.rb +69 -0
- data/lib/cmdx/callback_registry.rb +106 -0
- data/lib/cmdx/chain.rb +190 -0
- data/lib/cmdx/chain_inspector.rb +149 -0
- data/lib/cmdx/chain_serializer.rb +175 -0
- data/lib/cmdx/coercions/array.rb +37 -0
- data/lib/cmdx/coercions/big_decimal.rb +33 -0
- data/lib/cmdx/coercions/boolean.rb +41 -1
- data/lib/cmdx/coercions/complex.rb +31 -0
- data/lib/cmdx/coercions/date.rb +39 -0
- data/lib/cmdx/coercions/date_time.rb +39 -0
- data/lib/cmdx/coercions/float.rb +31 -0
- data/lib/cmdx/coercions/hash.rb +42 -0
- data/lib/cmdx/coercions/integer.rb +32 -0
- data/lib/cmdx/coercions/rational.rb +31 -0
- data/lib/cmdx/coercions/string.rb +31 -0
- data/lib/cmdx/coercions/time.rb +39 -0
- data/lib/cmdx/coercions/virtual.rb +31 -0
- data/lib/cmdx/configuration.rb +217 -9
- data/lib/cmdx/context.rb +173 -2
- data/lib/cmdx/core_ext/hash.rb +72 -0
- data/lib/cmdx/core_ext/module.rb +94 -0
- data/lib/cmdx/core_ext/object.rb +105 -0
- data/lib/cmdx/correlator.rb +217 -0
- data/lib/cmdx/error.rb +210 -8
- data/lib/cmdx/errors.rb +256 -1
- data/lib/cmdx/fault.rb +177 -2
- data/lib/cmdx/faults.rb +158 -2
- data/lib/cmdx/immutator.rb +121 -2
- data/lib/cmdx/lazy_struct.rb +261 -18
- data/lib/cmdx/log_formatters/json.rb +46 -0
- data/lib/cmdx/log_formatters/key_value.rb +46 -0
- data/lib/cmdx/log_formatters/line.rb +54 -0
- data/lib/cmdx/log_formatters/logstash.rb +64 -0
- data/lib/cmdx/log_formatters/pretty_json.rb +57 -0
- data/lib/cmdx/log_formatters/pretty_key_value.rb +51 -0
- data/lib/cmdx/log_formatters/pretty_line.rb +60 -0
- data/lib/cmdx/log_formatters/raw.rb +54 -0
- data/lib/cmdx/logger.rb +85 -0
- data/lib/cmdx/logger_ansi.rb +93 -7
- data/lib/cmdx/logger_serializer.rb +116 -0
- data/lib/cmdx/middleware.rb +74 -0
- data/lib/cmdx/middleware_registry.rb +106 -0
- data/lib/cmdx/middlewares/correlate.rb +266 -0
- data/lib/cmdx/middlewares/timeout.rb +232 -0
- data/lib/cmdx/parameter.rb +228 -1
- data/lib/cmdx/parameter_inspector.rb +61 -0
- data/lib/cmdx/parameter_registry.rb +125 -0
- data/lib/cmdx/parameter_serializer.rb +83 -0
- data/lib/cmdx/parameter_validator.rb +62 -0
- data/lib/cmdx/parameter_value.rb +109 -1
- data/lib/cmdx/parameters_inspector.rb +59 -0
- data/lib/cmdx/parameters_serializer.rb +102 -0
- data/lib/cmdx/railtie.rb +123 -3
- data/lib/cmdx/result.rb +399 -20
- data/lib/cmdx/result_ansi.rb +105 -9
- data/lib/cmdx/result_inspector.rb +76 -0
- data/lib/cmdx/result_logger.rb +90 -3
- data/lib/cmdx/result_serializer.rb +137 -0
- data/lib/cmdx/rspec/result_matchers.rb +917 -0
- data/lib/cmdx/rspec/task_matchers.rb +570 -0
- data/lib/cmdx/task.rb +409 -34
- data/lib/cmdx/task_serializer.rb +74 -2
- data/lib/cmdx/utils/ansi_color.rb +95 -0
- data/lib/cmdx/utils/log_timestamp.rb +48 -0
- data/lib/cmdx/utils/monotonic_runtime.rb +71 -4
- data/lib/cmdx/utils/name_affix.rb +78 -0
- data/lib/cmdx/validators/custom.rb +82 -0
- data/lib/cmdx/validators/exclusion.rb +94 -0
- data/lib/cmdx/validators/format.rb +102 -8
- data/lib/cmdx/validators/inclusion.rb +104 -0
- data/lib/cmdx/validators/length.rb +128 -0
- data/lib/cmdx/validators/numeric.rb +128 -0
- data/lib/cmdx/validators/presence.rb +93 -7
- data/lib/cmdx/version.rb +7 -1
- data/lib/cmdx/workflow.rb +394 -0
- data/lib/cmdx.rb +25 -64
- data/lib/generators/cmdx/install_generator.rb +37 -1
- data/lib/generators/cmdx/task_generator.rb +69 -1
- data/lib/generators/cmdx/templates/install.rb +8 -12
- data/lib/generators/cmdx/workflow_generator.rb +109 -0
- metadata +54 -15
- data/docs/basics/run.md +0 -34
- data/docs/batch.md +0 -53
- data/docs/example.md +0 -82
- data/docs/hooks.md +0 -59
- data/lib/cmdx/batch.rb +0 -43
- data/lib/cmdx/parameters.rb +0 -34
- data/lib/cmdx/run.rb +0 -38
- data/lib/cmdx/run_inspector.rb +0 -26
- data/lib/cmdx/run_serializer.rb +0 -16
- data/lib/cmdx/task_hook.rb +0 -18
- data/lib/generators/cmdx/batch_generator.rb +0 -30
- /data/lib/generators/cmdx/templates/{batch.rb.tt → workflow.rb.tt} +0 -0
data/docs/logging.md
CHANGED
@@ -1,104 +1,245 @@
|
|
1
1
|
# Logging
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
-
|
10
|
-
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
3
|
+
CMDx provides comprehensive automatic logging for task execution with structured data, customizable formatters, and intelligent severity mapping. All task results are logged after completion with rich metadata for debugging and monitoring.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
- [Log Formatters](#log-formatters)
|
7
|
+
- [Standard Formatters](#standard-formatters)
|
8
|
+
- [Stylized Formatters (ANSI Colors)](#stylized-formatters-ansi-colors)
|
9
|
+
- [Sample Output](#sample-output)
|
10
|
+
- [Success Result](#success-result)
|
11
|
+
- [Skipped Result](#skipped-result)
|
12
|
+
- [Failed Result](#failed-result)
|
13
|
+
- [Failure Chain (Workflow Workflows)](#failure-chain-workflow-workflows)
|
14
|
+
- [Configuration](#configuration)
|
15
|
+
- [Global Configuration](#global-configuration)
|
16
|
+
- [Task-Specific Configuration](#task-specific-configuration)
|
17
|
+
- [Environment-Specific Configuration](#environment-specific-configuration)
|
18
|
+
- [Severity Mapping](#severity-mapping)
|
19
|
+
- [Manual Logging](#manual-logging)
|
20
|
+
- [Advanced Formatter Usage](#advanced-formatter-usage)
|
21
|
+
- [Custom Formatter](#custom-formatter)
|
22
|
+
- [Multi-Destination Logging](#multi-destination-logging)
|
23
|
+
- [Log Data Structure](#log-data-structure)
|
24
|
+
|
25
|
+
## Log Formatters
|
26
|
+
|
27
|
+
CMDx provides 8 built-in log formatters organized into standard and stylized categories:
|
28
|
+
|
29
|
+
### Standard Formatters
|
30
|
+
- **`Line`** - Traditional single-line format similar to Ruby's Logger
|
31
|
+
- **`Json`** - Compact single-line JSON for structured logging systems
|
32
|
+
- **`KeyValue`** - Space-separated key=value pairs for easy parsing
|
33
|
+
- **`Logstash`** - ELK stack compatible JSON with @version and @timestamp fields
|
34
|
+
- **`Raw`** - Minimal output containing only the message content
|
35
|
+
|
36
|
+
### Stylized Formatters (ANSI Colors)
|
37
|
+
|
38
|
+
> [!NOTE]
|
39
|
+
> Stylized formatters include ANSI color codes for terminal readability and are best suited for development environments.
|
40
|
+
|
41
|
+
- **`PrettyLine`** - Colorized line format (default)
|
42
|
+
- **`PrettyJson`** - Human-readable multi-line JSON with syntax highlighting
|
43
|
+
- **`PrettyKeyValue`** - Colorized key=value pairs for terminal readability
|
44
|
+
|
45
|
+
## Sample Output
|
46
|
+
|
47
|
+
### Success Result
|
18
48
|
```txt
|
19
|
-
|
49
|
+
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
|
20
50
|
```
|
21
51
|
|
22
|
-
|
52
|
+
### Skipped Result
|
23
53
|
```txt
|
24
|
-
|
54
|
+
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
|
25
55
|
```
|
26
56
|
|
27
|
-
|
57
|
+
### Failed Result
|
28
58
|
```txt
|
29
|
-
E, [2022-07-17T18:43:15.000000 #3784] ERROR --
|
59
|
+
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
|
30
60
|
```
|
31
61
|
|
32
|
-
|
62
|
+
### Failure Chain (Workflow Workflows)
|
33
63
|
```txt
|
34
|
-
E, [2022-07-17T18:43:15.000000 #3784] ERROR --
|
64
|
+
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
|
35
65
|
```
|
36
66
|
|
37
|
-
##
|
67
|
+
## Configuration
|
38
68
|
|
39
|
-
|
40
|
-
[stdlib documentation](http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html).
|
69
|
+
### Global Configuration
|
41
70
|
|
42
|
-
|
71
|
+
Configure logging globally in your CMDx initializer:
|
43
72
|
|
44
73
|
```ruby
|
45
74
|
CMDx.configure do |config|
|
46
|
-
|
47
|
-
config.logger = Logger
|
48
|
-
|
49
|
-
# Multiline declarations:
|
50
|
-
config.logger = Rails.logger
|
51
|
-
config.logger.formatter = CMDx::LogFormatters::Line.new
|
52
|
-
config.logger.level = Logger::WARN
|
75
|
+
config.logger = Logger.new("log/cmdx.log", formatter: CMDx::LogFormatters::Json.new)
|
76
|
+
config.logger.level = Logger::INFO
|
53
77
|
end
|
54
78
|
```
|
55
79
|
|
56
|
-
|
80
|
+
### Task-Specific Configuration
|
57
81
|
|
58
|
-
|
59
|
-
class ProcessOrderTask < CMDx::Task
|
82
|
+
Override logging settings for individual tasks:
|
60
83
|
|
61
|
-
|
84
|
+
```ruby
|
85
|
+
class SendEmailTask < CMDx::Task
|
86
|
+
task_settings!(
|
87
|
+
logger: Rails.logger,
|
88
|
+
log_formatter: CMDx::LogFormatters::Json.new,
|
89
|
+
log_level: Logger::WARN
|
90
|
+
)
|
62
91
|
|
63
92
|
def call
|
64
|
-
#
|
93
|
+
# Task implementation
|
65
94
|
end
|
95
|
+
end
|
66
96
|
|
97
|
+
# Base class with shared logging configuration
|
98
|
+
class ApplicationTask < CMDx::Task
|
99
|
+
task_settings!(
|
100
|
+
logger: Logger.new("log/tasks.log"),
|
101
|
+
log_formatter: CMDx::LogFormatters::Logstash.new,
|
102
|
+
log_level: Logger::INFO
|
103
|
+
)
|
67
104
|
end
|
68
105
|
```
|
69
106
|
|
70
|
-
|
71
|
-
|
72
|
-
>
|
107
|
+
## Severity Mapping
|
108
|
+
|
109
|
+
> [!IMPORTANT]
|
110
|
+
> CMDx automatically maps result statuses to appropriate log severity levels. Manual log level overrides are not recommended.
|
111
|
+
|
112
|
+
| Result Status | Log Level | Use Case |
|
113
|
+
| ------------- | --------- | -------- |
|
114
|
+
| `success` | `INFO` | Normal successful completion |
|
115
|
+
| `skipped` | `WARN` | Intentional skip (business logic) |
|
116
|
+
| `failed` | `ERROR` | Task failure or exception |
|
73
117
|
|
74
|
-
##
|
118
|
+
## Manual Logging
|
75
119
|
|
76
|
-
|
120
|
+
Access the configured logger within tasks for custom log messages:
|
77
121
|
|
78
122
|
```ruby
|
79
123
|
class ProcessOrderTask < CMDx::Task
|
80
|
-
|
81
124
|
def call
|
82
|
-
logger.info "
|
83
|
-
|
125
|
+
logger.info "Starting order processing", order_id: context.order_id
|
126
|
+
|
127
|
+
# Performance-optimized debug logging
|
128
|
+
logger.debug { "Order details: #{context.order.inspect}" }
|
129
|
+
|
130
|
+
# Structured logging
|
131
|
+
logger.info "Payment processed", {
|
132
|
+
order_id: context.order_id,
|
133
|
+
amount: context.order.total,
|
134
|
+
payment_method: context.payment_method
|
135
|
+
}
|
136
|
+
|
137
|
+
# Exception handling with logging
|
138
|
+
begin
|
139
|
+
validate_inventory
|
140
|
+
rescue StandardError => e
|
141
|
+
logger.error "Inventory validation failed: #{e.message}", {
|
142
|
+
exception: e.class.name,
|
143
|
+
order_id: context.order_id
|
144
|
+
}
|
145
|
+
raise
|
146
|
+
end
|
84
147
|
end
|
85
|
-
|
86
148
|
end
|
87
149
|
```
|
88
150
|
|
89
|
-
##
|
151
|
+
## Advanced Formatter Usage
|
90
152
|
|
91
|
-
|
153
|
+
### Custom Formatter
|
154
|
+
|
155
|
+
Create custom formatters for specific output requirements:
|
92
156
|
|
93
157
|
```ruby
|
94
|
-
class
|
158
|
+
class SlackLogFormatter
|
95
159
|
def call(severity, time, task, message)
|
96
|
-
|
160
|
+
emoji = case severity
|
161
|
+
when 'INFO' then '✅'
|
162
|
+
when 'WARN' then '⚠️'
|
163
|
+
when 'ERROR' then '❌'
|
164
|
+
else '📝'
|
165
|
+
end
|
166
|
+
|
167
|
+
"#{emoji} #{task.class.name}: #{message}\n"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class SendNotificationTask < CMDx::Task
|
172
|
+
task_settings!(
|
173
|
+
logger: Logger.new("log/notifications.log", formatter: SlackLogFormatter.new)
|
174
|
+
)
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
### Multi-Destination Logging
|
179
|
+
|
180
|
+
> [!TIP]
|
181
|
+
> Use multi-destination logging to send output to both console and files simultaneously during development.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class MultiLogger
|
185
|
+
def initialize(*loggers)
|
186
|
+
@loggers = loggers
|
187
|
+
end
|
188
|
+
|
189
|
+
%w[debug info warn error fatal].each do |level|
|
190
|
+
define_method(level) do |message = nil, &block|
|
191
|
+
@loggers.each { |logger| logger.send(level, message, &block) }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def formatter=(formatter)
|
196
|
+
@loggers.each { |logger| logger.formatter = formatter }
|
197
|
+
end
|
198
|
+
|
199
|
+
def level=(level)
|
200
|
+
@loggers.each { |logger| logger.level = level }
|
97
201
|
end
|
98
202
|
end
|
203
|
+
|
204
|
+
# Usage
|
205
|
+
CMDx.configure do |config|
|
206
|
+
config.logger = MultiLogger.new(
|
207
|
+
Logger.new(STDOUT, formatter: CMDx::LogFormatters::PrettyLine.new),
|
208
|
+
Logger.new("log/cmdx.log", formatter: CMDx::LogFormatters::Json.new)
|
209
|
+
)
|
210
|
+
end
|
99
211
|
```
|
100
212
|
|
213
|
+
## Log Data Structure
|
214
|
+
|
215
|
+
CMDx logs contain comprehensive execution metadata:
|
216
|
+
|
217
|
+
#### Standard Fields
|
218
|
+
- `severity` - Log level (INFO, WARN, ERROR)
|
219
|
+
- `pid` - Process ID for multi-process debugging
|
220
|
+
- `timestamp` - ISO 8601 formatted execution time
|
221
|
+
- `origin` - Always "CMDx" for filtering
|
222
|
+
|
223
|
+
#### Task Identification
|
224
|
+
- `index` - Position in execution sequence
|
225
|
+
- `chain_id` - Unique identifier for execution chain
|
226
|
+
- `type` - Task or Workflow
|
227
|
+
- `class` - Task class name
|
228
|
+
- `id` - Unique task instance identifier
|
229
|
+
- `tags` - Custom tags for categorization
|
230
|
+
|
231
|
+
#### Execution Information
|
232
|
+
- `state` - Execution lifecycle state (initialized, executing, complete, interrupted)
|
233
|
+
- `status` - Business logic outcome (success, skipped, failed)
|
234
|
+
- `outcome` - Final result classification
|
235
|
+
- `metadata` - Custom data from skip!/fail! calls
|
236
|
+
- `runtime` - Execution time in seconds
|
237
|
+
|
238
|
+
#### Failure Chain (Complex Workflows)
|
239
|
+
- `caused_failure` - Original failing task information
|
240
|
+
- `threw_failure` - Task that propagated the failure
|
241
|
+
|
101
242
|
---
|
102
243
|
|
103
|
-
- **Prev:** [
|
104
|
-
- **Next:** [
|
244
|
+
- **Prev:** [Workflows](workflows.md)
|
245
|
+
- **Next:** [Testing](testing.md)
|