cmdx 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aed549d510aee08ccdb114f75b51b7aefe1a9776905f53e75ec5c39477932350
4
- data.tar.gz: b57596b1393185082d94616f8c08494d030a2d78bb85610674363a365efa15f5
3
+ metadata.gz: da7809a9d556cc2cb4cc5734fe52790f4e964ccc437728e1c78cef2a6e2121ec
4
+ data.tar.gz: 9577047cd8a98bc19fe81c02366aebf70c295e738e3083c478ab670c8af55048
5
5
  SHA512:
6
- metadata.gz: 7d123c5a08fc89494b759eddea90e614858e55db733a3690e899de46b5e6e93e574a9bf2d9899f4f9c9c118686d5ff2f84cfd75b110ce242b79d7627ae3dfbd8
7
- data.tar.gz: 17e336e03307f3dddaf7dba53d4a201f031f54348bc0e43059a17ace90cf7f4a762ad6e97ec731b32d1064616c978948867e8aa746ff96f52e93996376828a7c
6
+ metadata.gz: 3101e89eafcaf552fa64db81fdc0547628e23636564097ae91fb5dc726cbe25bcfbb6c44a04619cbbfcfe41f29f9a42a658bcd045a1a035f85b0c098d20a6038
7
+ data.tar.gz: 97450b9d1018dfc80d73fac8b0072356c4a1e05f39fc377cbf517468a412c77041bb1376ae0b3a72fb34575709fa169115ebf69ae7285a75fe41d453b21ee247
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2025-03-07
3
+ ## [0.3.0] - 2025-03-14
4
+ ### Added
5
+ - Add `progname` to logger instances
6
+ - Add `LoggerSerializer` to standardize log output
7
+ ### Changed
8
+ - Revert default log formatter to `Line`
9
+ - Removed `pid` from result serializer
10
+ - Fix serialization of frozen run
11
+ - Fix `call!` not marking state of failure as interrupted
12
+
13
+ ## [0.2.0] - 2025-03-12
14
+ ### Added
15
+ - Add `PrettyJson` log formatter
16
+ - Add `PrettyKeyValue` log formatter
17
+ - Add `PrettyLine` log formatter
18
+ ### Changed
19
+ - Make `PrettyLine` the default log formatter
20
+ - Rename `MethodName` util to `NameAffix`
21
+ - Rename `DatetimeFormatter` util to `LogTimestamp`
22
+ - Rename `Runtime` util to `MonotonicRuntime`
23
+ - Fix logging non hash values from raising an error
24
+ - Fix bubbling of faults with nested halted calls
25
+ - Wrap result logger in a `Logger#with_logger` block
4
26
 
27
+ ## [0.1.0] - 2025-03-07
28
+ ### Added
5
29
  - Initial release
data/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  [![forthebadge](http://forthebadge.com/images/badges/made-with-ruby.svg)](http://forthebadge.com)
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/cmdx.svg)](https://badge.fury.io/rb/cmdx)
6
- [![CI](https://github.com/drexed/cmdx/actions/workflows/ruby.yml/badge.svg)](https://github.com/drexed/cmdx/actions/workflows/ruby.yml)
5
+ [![Gem Version](https://badge.fury.io/rb/cmdx.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/cmdx)
6
+ [![CI](https://github.com/drexed/cmdx/actions/workflows/ci.yml/badge.svg)](https://github.com/drexed/cmdx/actions/workflows/ci.yml)
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=shields)](http://makeapullrequest.com)
8
8
 
9
9
  `CMDx` is a framework for expressive processing of business logic. Design
data/docs/logging.md CHANGED
@@ -5,31 +5,33 @@ tasks executing concurrently so `CMDx` uses a custom logger to make debugging ea
5
5
 
6
6
  ## Output
7
7
 
8
- Built-in log formatters are: `Line` (default), `Json`, `KeyValue`, `Logstash`, `Raw`
8
+ Built-in log formatters are:
9
+ - Standard: `Line`, `Json`, `KeyValue`, `Logstash`, `Raw`
10
+ - Stylized: `PrettyLine` (default), `PrettyJson`, `PrettyKeyValue`
9
11
 
10
12
  #### Success:
11
13
  ```txt
12
- I, [2022-07-17T18:43:15.000000 #3784] INFO -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=complete status=success outcome=success metadata={} runtime=0 tags=[] pid=3784
14
+ I, [2022-07-17T18:43:15.000000 #3784] INFO -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task task=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=complete status=success outcome=success metadata={} runtime=0 origin=CMDx
13
15
  ```
14
16
 
15
17
  #### Skipped:
16
18
  ```txt
17
- W, [2022-07-17T18:43:15.000000 #3784] WARN -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=skipped outcome=skipped metadata={} runtime=0 tags=[] pid=3784
19
+ W, [2022-07-17T18:43:15.000000 #3784] WARN -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task task=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=skipped outcome=skipped metadata={} runtime=0 origin=CMDx
18
20
  ```
19
21
 
20
22
  #### Failed:
21
23
  ```txt
22
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=failed outcome=failed metadata={} runtime=0 tags=[] pid=3784
24
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task task=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=failed metadata={} runtime=0 origin=CMDx
23
25
  ```
24
26
 
25
27
  #### Level 1 subtask failure:
26
28
  ```txt
27
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=failed outcome=interrupted metadata={} runtime=0 tags=[] pid=3784 caused_failure={:index=>1, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"failed", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784} threw_failure={:index=>1, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"failed", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784}
29
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task task=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=interrupted metadata={} runtime=0 caused_failure={index: 1, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", task: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "failed", metadata: {}, runtime: 0} threw_failure={index: 1, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", task: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "failed", metadata: {}, runtime: 0} origin=CMDx
28
30
  ```
29
31
 
30
32
  #### Level 2+ subtask failure:
31
33
  ```txt
32
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=failed outcome=interrupted metadata={} runtime=0 tags=[] pid=3784 caused_failure={:index=>2, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"failed", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784} threw_failure={:index=>1, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"interrupted", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784}
34
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task task=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=interrupted metadata={} runtime=0 caused_failure={index: 2, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", task: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "failed", metadata: {}, runtime: 0} threw_failure={index: 1, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", task: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "interrupted", metadata: {}, runtime: 0} origin=CMDx
33
35
  ```
34
36
 
35
37
  ## Logger
@@ -90,7 +92,7 @@ Define a custom log formatter to match your expected output, for example one tha
90
92
 
91
93
  ```ruby
92
94
  class CustomCmdxLogFormat
93
- def call(severity, time, progname, message)
95
+ def call(severity, time, task, message)
94
96
  # Return string, hash, array, etc to output...
95
97
  end
96
98
  end
@@ -14,7 +14,7 @@ module CMDx
14
14
 
15
15
  def reset_configuration!
16
16
  @configuration = LazyStruct.new(
17
- logger: ::Logger.new($stdout, formatter: CMDx::LogFormatters::Line.new),
17
+ logger: ::Logger.new($stdout, formatter: CMDx::LogFormatters::Json.new),
18
18
  task_halt: CMDx::Result::FAILED,
19
19
  task_timeout: nil,
20
20
  batch_halt: CMDx::Result::FAILED,
@@ -6,7 +6,7 @@ module CMDx
6
6
 
7
7
  def __cmdx_attr_delegator(*methods, **options)
8
8
  methods.each do |method|
9
- method_name = Utils::MethodName.call(method, options.fetch(:to), options)
9
+ method_name = Utils::NameAffix.call(method, options.fetch(:to), options)
10
10
 
11
11
  define_method(method_name) do |*args, **kwargs, &block|
12
12
  object = (options[:to] == :class ? self.class : send(options[:to]))
@@ -4,8 +4,14 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Json
6
6
 
7
- def call(_severity, _time, _progname, message)
8
- JSON.dump(message)
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
+
14
+ JSON.dump(m) << "\n"
9
15
  end
10
16
 
11
17
  end
@@ -4,8 +4,15 @@ module CMDx
4
4
  module LogFormatters
5
5
  class KeyValue
6
6
 
7
- def call(_severity, _time, _progname, message)
8
- message.map { |k, v| "#{k}=#{v}" }.join(" ")
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
+
14
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
15
+ m << "\n"
9
16
  end
10
17
 
11
18
  end
@@ -4,9 +4,12 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Line
6
6
 
7
- def call(severity, time, progname, message)
8
- message = message.map { |k, v| "#{k}=#{v}" }.join(" ")
9
- "#{severity[0]}, [#{Utils::DatetimeFormatter.call(time.utc)} ##{Process.pid}] #{severity} -- #{progname || 'CMDx'}: #{message}"
7
+ def call(severity, time, task, message)
8
+ t = Utils::LogTimestamp.call(time.utc)
9
+ m = LoggerSerializer.call(severity, time, task, message)
10
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
11
+
12
+ "#{severity[0]}, [#{t} ##{Process.pid}] #{severity} -- #{task.class.name}: #{m}\n"
10
13
  end
11
14
 
12
15
  end
@@ -4,13 +4,15 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Logstash
6
6
 
7
- def call(_severity, time, _progname, message)
8
- if message.is_a?(Hash)
9
- message["@version"] ||= "1"
10
- message["@timestamp"] ||= Utils::DatetimeFormatter.call(time.utc)
11
- end
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ "@version" => "1",
12
+ "@timestamp" => Utils::LogTimestamp.call(time.utc)
13
+ )
12
14
 
13
- JSON.dump(message)
15
+ JSON.dump(m) << "\n"
14
16
  end
15
17
 
16
18
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LogFormatters
5
+ class PrettyJson
6
+
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
+
14
+ JSON.pretty_generate(m) << "\n"
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LogFormatters
5
+ class PrettyKeyValue
6
+
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message, ansi_colorize: true).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
+
14
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
15
+ m << "\n"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LogFormatters
5
+ class PrettyLine
6
+
7
+ def call(severity, time, task, message)
8
+ i = LoggerAnsi.call(severity[0])
9
+ s = LoggerAnsi.call(severity)
10
+ t = Utils::LogTimestamp.call(time.utc)
11
+ m = LoggerSerializer.call(severity, time, task, message, ansi_colorize: true)
12
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
13
+
14
+ "#{i}, [#{t} ##{Process.pid}] #{s} -- #{task.class.name}: #{m}\n"
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -4,8 +4,8 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Raw
6
6
 
7
- def call(_severity, _time, _progname, message)
8
- message
7
+ def call(_severity, _time, _task, message)
8
+ message.inspect << "\n"
9
9
  end
10
10
 
11
11
  end
data/lib/cmdx/logger.rb CHANGED
@@ -9,6 +9,7 @@ module CMDx
9
9
  logger = task.task_setting(:logger)
10
10
  logger.formatter = task.task_setting(:log_formatter) if task.task_setting?(:log_formatter)
11
11
  logger.level = task.task_setting(:log_level) if task.task_setting?(:log_level)
12
+ logger.progname = task
12
13
  logger
13
14
  end
14
15
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LoggerAnsi
5
+
6
+ SEVERITY_COLOR_CODES = {
7
+ "D" => 34, # DEBUG - Blue
8
+ "I" => 32, # INFO - Green
9
+ "W" => 33, # WARN - Yellow
10
+ "E" => 31, # ERROR - Red
11
+ "F" => 35 # FATAL - Magenta
12
+ }.freeze
13
+
14
+ module_function
15
+
16
+ def call(s)
17
+ c = SEVERITY_COLOR_CODES[s[0]] || 39 # Default
18
+ "\e[1;#{c}m#{s}\e[0m"
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LoggerSerializer
5
+
6
+ COLORED_KEYS = %i[
7
+ state status outcome
8
+ ].freeze
9
+
10
+ module_function
11
+
12
+ def call(_severity, _time, task, message, **options)
13
+ m = message.respond_to?(:to_h) ? message.to_h : {}
14
+
15
+ if options.delete(:ansi_colorize) && message.is_a?(Result)
16
+ COLORED_KEYS.each { |k| m[k] = ResultAnsi.call(m[k]) if m.key?(k) }
17
+ elsif !message.is_a?(Result)
18
+ m.merge!(
19
+ TaskSerializer.call(task),
20
+ message: message
21
+ )
22
+ end
23
+
24
+ m[:origin] ||= "CMDx"
25
+ m
26
+ end
27
+
28
+ end
29
+ end
@@ -60,7 +60,7 @@ module CMDx
60
60
  end
61
61
 
62
62
  def method_name
63
- @method_name ||= Utils::MethodName.call(name, method_source, options)
63
+ @method_name ||= Utils::NameAffix.call(name, method_source, options)
64
64
  end
65
65
 
66
66
  def method_source
data/lib/cmdx/result.rb CHANGED
@@ -28,6 +28,10 @@ module CMDx
28
28
  define_method(:"#{s}?") { state == s }
29
29
  end
30
30
 
31
+ def executed!
32
+ success? ? complete! : interrupt!
33
+ end
34
+
31
35
  def executed?
32
36
  complete? || interrupted?
33
37
  end
@@ -103,11 +107,13 @@ module CMDx
103
107
  raise Fault.build(self)
104
108
  end
105
109
 
106
- def throw!(result)
110
+ def throw!(result, local_metadata = {})
107
111
  raise ArgumentError, "must be a Result" unless result.is_a?(Result)
108
112
 
109
- skip!(**result.metadata) if result.skipped?
110
- fail!(**result.metadata) if result.failed?
113
+ md = result.metadata.merge(local_metadata)
114
+
115
+ skip!(**md) if result.skipped?
116
+ fail!(**md) if result.failed?
111
117
  end
112
118
 
113
119
  def caused_failure
@@ -154,7 +160,7 @@ module CMDx
154
160
  timeout_secs = task.task_setting(timeout_type)
155
161
 
156
162
  Timeout.timeout(timeout_secs, TimeoutError, "execution exceeded #{timeout_secs} seconds") do
157
- @runtime = Utils::Runtime.call(&block)
163
+ @runtime = Utils::MonotonicRuntime.call(&block)
158
164
  end
159
165
  end
160
166
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module ResultAnsi
5
+
6
+ STATE_COLOR_CODES = {
7
+ Result::INITIALIZED => 34, # Blue
8
+ Result::EXECUTING => 33, # Yellow
9
+ Result::COMPLETE => 32, # Green
10
+ Result::INTERRUPTED => 31 # Red
11
+ }.freeze
12
+ STATUS_COLOR_CODES = {
13
+ Result::SUCCESS => 32, # Green
14
+ Result::SKIPPED => 33, # Yellow
15
+ Result::FAILED => 31 # Red
16
+ }.freeze
17
+
18
+ module_function
19
+
20
+ def call(s)
21
+ c = STATE_COLOR_CODES[s] || STATUS_COLOR_CODES[s] || 39 # Default
22
+ "\e[1;#{c}m#{s}\e[0m"
23
+ end
24
+
25
+ end
26
+ end
@@ -4,7 +4,7 @@ module CMDx
4
4
  module ResultInspector
5
5
 
6
6
  ORDERED_KEYS = %i[
7
- class type index id state status outcome metadata
7
+ task type index id state status outcome metadata
8
8
  tags pid runtime caused_failure threw_failure
9
9
  ].freeze
10
10
 
@@ -17,10 +17,10 @@ module CMDx
17
17
  value = result[key]
18
18
 
19
19
  case key
20
- when :class
20
+ when :task
21
21
  "#{value}:"
22
22
  when :caused_failure, :threw_failure
23
- "#{key}=<[#{value[:index]}] #{value[:class]}: #{value[:id]}>"
23
+ "#{key}=<[#{value[:index]}] #{value[:task]}: #{value[:id]}>"
24
24
  else
25
25
  "#{key}=#{value}"
26
26
  end
@@ -3,7 +3,7 @@
3
3
  module CMDx
4
4
  module ResultLogger
5
5
 
6
- STATUS_TO_LEVEL = {
6
+ STATUS_TO_SEVERITY = {
7
7
  Result::SUCCESS => :info,
8
8
  Result::SKIPPED => :warn,
9
9
  Result::FAILED => :error
@@ -12,10 +12,12 @@ module CMDx
12
12
  module_function
13
13
 
14
14
  def call(result)
15
- logger = result.task.send(:logger)
16
- status = STATUS_TO_LEVEL[result.status]
15
+ logger = result.task.send(:logger)
16
+ severity = STATUS_TO_SEVERITY[result.status]
17
17
 
18
- logger.send(status) { result.to_h }
18
+ logger.with_level(severity) do
19
+ logger.send(severity) { result }
20
+ end
19
21
  end
20
22
 
21
23
  end
@@ -13,20 +13,15 @@ module CMDx
13
13
  module_function
14
14
 
15
15
  def call(result)
16
- {
17
- index: result.index,
18
- run_id: result.run.id,
19
- type: result.task.is_a?(Batch) ? "Batch" : "Task",
20
- class: result.task.class.name,
21
- id: result.task.id,
22
- state: result.state,
23
- status: result.status,
24
- outcome: result.outcome,
25
- metadata: result.metadata,
26
- runtime: result.runtime,
27
- tags: result.task.task_setting(:tags),
28
- pid: Process.pid
29
- }.tap do |hash|
16
+ TaskSerializer.call(result.task).tap do |hash|
17
+ hash.merge!(
18
+ state: result.state,
19
+ status: result.status,
20
+ outcome: result.outcome,
21
+ metadata: result.metadata,
22
+ runtime: result.runtime
23
+ )
24
+
30
25
  if result.failed?
31
26
  STRIP_FAILURE.call(hash, result, :caused_failure)
32
27
  STRIP_FAILURE.call(hash, result, :threw_failure)
data/lib/cmdx/run.rb CHANGED
@@ -13,6 +13,11 @@ module CMDx
13
13
  @results = Array(attributes[:results])
14
14
  end
15
15
 
16
+ def freeze
17
+ first_result
18
+ super
19
+ end
20
+
16
21
  def to_h
17
22
  RunSerializer.call(self)
18
23
  end
data/lib/cmdx/task.rb CHANGED
@@ -103,7 +103,6 @@ module CMDx
103
103
  end
104
104
 
105
105
  def after_call
106
- result.send(result.success? ? :complete! : :interrupt!)
107
106
  TaskHook.call(self, :"on_#{result.status}")
108
107
  TaskHook.call(self, :"on_#{result.state}")
109
108
 
@@ -121,9 +120,12 @@ module CMDx
121
120
  call
122
121
  rescue UndefinedCallError => e
123
122
  raise(e)
123
+ rescue Fault => e
124
+ throw!(e.result, original_exception: e) if Array(task_setting(:task_halt)).include?(e.result.status)
124
125
  rescue StandardError => e
125
- result.fail!(reason: "[#{e.class}] #{e.message}", original_exception: e) unless e.is_a?(Fault)
126
+ fail!(reason: "[#{e.class}] #{e.message}", original_exception: e)
126
127
  ensure
128
+ result.executed!
127
129
  after_call
128
130
  end
129
131
 
@@ -137,10 +139,12 @@ module CMDx
137
139
  rescue UndefinedCallError => e
138
140
  raise(e)
139
141
  rescue Fault => e
142
+ result.executed!
140
143
  raise(e) if Array(task_setting(:task_halt)).include?(e.result.status)
141
144
 
142
145
  after_call # HACK: treat as NO-OP
143
146
  else
147
+ result.executed!
144
148
  after_call # ELSE: treat as success
145
149
  end
146
150
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module TaskSerializer
5
+
6
+ module_function
7
+
8
+ def call(task)
9
+ {
10
+ index: task.result.index,
11
+ run_id: task.run.id,
12
+ type: task.is_a?(Batch) ? "Batch" : "Task",
13
+ task: task.class.name,
14
+ id: task.id,
15
+ tags: task.task_setting(:tags)
16
+ }
17
+ end
18
+
19
+ end
20
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CMDx
4
4
  module Utils
5
- module DatetimeFormatter
5
+ module LogTimestamp
6
6
 
7
7
  DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%6N"
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CMDx
4
4
  module Utils
5
- module Runtime
5
+ module MonotonicRuntime
6
6
 
7
7
  module_function
8
8
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  module CMDx
4
4
  module Utils
5
- module MethodName
5
+ module NameAffix
6
6
 
7
- ROOTFIX = proc do |o, &block|
7
+ AFFIX = proc do |o, &block|
8
8
  o == true ? block.call : o
9
9
  end.freeze
10
10
 
@@ -12,8 +12,8 @@ module CMDx
12
12
 
13
13
  def call(method_name, source, options = {})
14
14
  options[:as] || begin
15
- prefix = ROOTFIX.call(options[:prefix]) { "#{source}_" }
16
- suffix = ROOTFIX.call(options[:suffix]) { "_#{source}" }
15
+ prefix = AFFIX.call(options[:prefix]) { "#{source}_" }
16
+ suffix = AFFIX.call(options[:suffix]) { "_#{source}" }
17
17
 
18
18
  "#{prefix}#{method_name}#{suffix}".strip.to_sym
19
19
  end
data/lib/cmdx/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CMDx
4
4
 
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
 
7
7
  end
data/lib/cmdx.rb CHANGED
@@ -18,6 +18,9 @@ require_relative "cmdx/log_formatters/key_value"
18
18
  require_relative "cmdx/log_formatters/line"
19
19
  require_relative "cmdx/log_formatters/logstash"
20
20
  require_relative "cmdx/log_formatters/raw"
21
+ require_relative "cmdx/log_formatters/pretty_json"
22
+ require_relative "cmdx/log_formatters/pretty_key_value"
23
+ require_relative "cmdx/log_formatters/pretty_line"
21
24
  require_relative "cmdx/coercions/array"
22
25
  require_relative "cmdx/coercions/big_decimal"
23
26
  require_relative "cmdx/coercions/boolean"
@@ -38,13 +41,15 @@ require_relative "cmdx/validators/inclusion"
38
41
  require_relative "cmdx/validators/length"
39
42
  require_relative "cmdx/validators/numeric"
40
43
  require_relative "cmdx/validators/presence"
41
- require_relative "cmdx/utils/datetime_formatter"
42
- require_relative "cmdx/utils/method_name"
43
- require_relative "cmdx/utils/runtime"
44
+ require_relative "cmdx/utils/log_timestamp"
45
+ require_relative "cmdx/utils/name_affix"
46
+ require_relative "cmdx/utils/monotonic_runtime"
44
47
  require_relative "cmdx/error"
45
48
  require_relative "cmdx/errors"
46
49
  require_relative "cmdx/fault"
47
50
  require_relative "cmdx/faults"
51
+ require_relative "cmdx/logger_serializer"
52
+ require_relative "cmdx/logger_ansi"
48
53
  require_relative "cmdx/logger"
49
54
  require_relative "cmdx/lazy_struct"
50
55
  require_relative "cmdx/configuration"
@@ -63,9 +68,11 @@ require_relative "cmdx/parameters_inspector"
63
68
  require_relative "cmdx/result"
64
69
  require_relative "cmdx/result_serializer"
65
70
  require_relative "cmdx/result_inspector"
71
+ require_relative "cmdx/result_ansi"
66
72
  require_relative "cmdx/result_logger"
67
73
  require_relative "cmdx/task"
68
74
  require_relative "cmdx/task_hook"
75
+ require_relative "cmdx/task_serializer"
69
76
  require_relative "cmdx/batch"
70
77
  require_relative "cmdx/immutator"
71
78
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-08 00:00:00.000000000 Z
10
+ date: 2025-03-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal
@@ -219,8 +219,13 @@ files:
219
219
  - lib/cmdx/log_formatters/key_value.rb
220
220
  - lib/cmdx/log_formatters/line.rb
221
221
  - lib/cmdx/log_formatters/logstash.rb
222
+ - lib/cmdx/log_formatters/pretty_json.rb
223
+ - lib/cmdx/log_formatters/pretty_key_value.rb
224
+ - lib/cmdx/log_formatters/pretty_line.rb
222
225
  - lib/cmdx/log_formatters/raw.rb
223
226
  - lib/cmdx/logger.rb
227
+ - lib/cmdx/logger_ansi.rb
228
+ - lib/cmdx/logger_serializer.rb
224
229
  - lib/cmdx/parameter.rb
225
230
  - lib/cmdx/parameter_inspector.rb
226
231
  - lib/cmdx/parameter_serializer.rb
@@ -231,6 +236,7 @@ files:
231
236
  - lib/cmdx/parameters_serializer.rb
232
237
  - lib/cmdx/railtie.rb
233
238
  - lib/cmdx/result.rb
239
+ - lib/cmdx/result_ansi.rb
234
240
  - lib/cmdx/result_inspector.rb
235
241
  - lib/cmdx/result_logger.rb
236
242
  - lib/cmdx/result_serializer.rb
@@ -239,9 +245,10 @@ files:
239
245
  - lib/cmdx/run_serializer.rb
240
246
  - lib/cmdx/task.rb
241
247
  - lib/cmdx/task_hook.rb
242
- - lib/cmdx/utils/datetime_formatter.rb
243
- - lib/cmdx/utils/method_name.rb
244
- - lib/cmdx/utils/runtime.rb
248
+ - lib/cmdx/task_serializer.rb
249
+ - lib/cmdx/utils/log_timestamp.rb
250
+ - lib/cmdx/utils/monotonic_runtime.rb
251
+ - lib/cmdx/utils/name_affix.rb
245
252
  - lib/cmdx/validators/custom.rb
246
253
  - lib/cmdx/validators/exclusion.rb
247
254
  - lib/cmdx/validators/format.rb