legionio 1.6.18 → 1.6.20
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/CHANGELOG.md +27 -0
- data/README.md +1 -1
- data/legionio.gemspec +1 -1
- data/lib/legion/api/hooks.rb +1 -2
- data/lib/legion/api/lex.rb +1 -2
- data/lib/legion/api.rb +1 -2
- data/lib/legion/events.rb +1 -2
- data/lib/legion/extensions/actors/base.rb +2 -4
- data/lib/legion/extensions/actors/every.rb +3 -6
- data/lib/legion/extensions/actors/loop.rb +1 -2
- data/lib/legion/extensions/actors/poll.rb +4 -7
- data/lib/legion/extensions/actors/subscription.rb +7 -9
- data/lib/legion/extensions/core.rb +1 -3
- data/lib/legion/extensions/helpers/logger.rb +56 -3
- data/lib/legion/extensions/helpers/task.rb +2 -4
- data/lib/legion/extensions/transport.rb +2 -5
- data/lib/legion/extensions.rb +1 -2
- data/lib/legion/runner/status.rb +5 -7
- data/lib/legion/service.rb +75 -29
- data/lib/legion/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9dd4d5c0f258dd9199195ac95f89dbcaaeccc3ccbf844924f463dfecffe6304c
|
|
4
|
+
data.tar.gz: 453721f4e03bf0c9ff3387575749241cb3bc9c8093b5c366d7b3434e823558be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 440288ee7de2bf883920879b3658c1cdf1c2a27546e39be8641f7d92dc91956c0ed6042e3ab4400103de06be0adb1fbca4738d215d9e6e0b8f26c05a617d2a2c
|
|
7
|
+
data.tar.gz: cb62010a5b8062fbef95bf39efc642d02251897ae9447901bbafbf230a8ec4012c695ca12f87000c24374b0c073c4caa90a380118b12fa02759e8856ae9a4e0f
|
data/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.6.20] - 2026-03-27
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Bump `legion-logging` dependency to `>= 1.4.0` (required for `log_exception`, writer lambdas)
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- `subscription.rb` (both `on_delivery` and `subscribe` blocks): initialize `fn = nil` before `process_message` so the rescue interpolation never raises `NameError` if message processing fails before `fn` is assigned
|
|
12
|
+
- `Helpers::Logger#lex_name` removed to avoid overriding `Helpers::Base#lex_name` (underscore contract used by settings/routing); renamed to private `log_lex_name` used only within this module for gem name derivation
|
|
13
|
+
- `Helpers::Logger#handle_exception`: use `spec&.version&.to_s` so nil spec version produces `nil` rather than `""` in structured log output
|
|
14
|
+
- README: update version badge from `v1.6.18` to `v1.6.20`
|
|
15
|
+
|
|
16
|
+
## [1.6.19] - 2026-03-27
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- `teardown_logging_transport`: rescue block in `setup_logging_transport` now calls `teardown_logging_transport` to clean up any partially-created `@log_session` on failure
|
|
20
|
+
- `teardown_logging_transport`: guard `open?` call with `respond_to?(:open?)` check to avoid `NoMethodError` on session objects that do not implement the method
|
|
21
|
+
- `service_logging_transport_spec`: early-return specs now assert `create_dedicated_session` was not called and `@log_session` remains nil, rather than the vacuous `respond_to(:call)` check
|
|
22
|
+
- `service_logging_transport_spec`: replaced vacuous `not_to eq(owner)` assertion with `have_received(:create_dedicated_session)` to verify the dedicated session was actually created
|
|
23
|
+
|
|
5
24
|
## [1.6.18] - 2026-03-27
|
|
6
25
|
|
|
26
|
+
### Added
|
|
27
|
+
- `setup_logging_transport`: dedicated AMQP session for log and exception forwarding, replacing the previous `register_logging_hooks` approach; writer lambda wiring is gated by `Settings[:logging][:transport]` feature flags
|
|
28
|
+
- `teardown_logging_transport`: cleanly shuts down the dedicated logging AMQP session during the shutdown sequence
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Split `log.error(e.message); log.error(e.backtrace)` patterns replaced with `log.log_exception` across 14 files for structured, single-call exception logging
|
|
32
|
+
- `Extensions::Helpers::Logger#handle_exception` rewritten to use `log.log_exception` with full lex context
|
|
33
|
+
|
|
7
34
|
### Fixed
|
|
8
35
|
- `legionio pipeline image analyze`: `call_llm` no longer passes unsupported `messages:` keyword to `Legion::LLM.chat`; now creates a chat object and sends multimodal content via `chat.ask`, returning a plain hash with `:content` and `:usage` keys
|
|
9
36
|
- `legionio ai trace search/summarize`: both commands now call `setup_connection` before invoking `TraceSearch`, ensuring `Legion::LLM` is booted so `TraceSearch.generate_filter` can use structured LLM output instead of returning "no filter generated"; added `class_option :config_dir` and `class_option :verbose` to `TraceCommand`
|
data/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Schedule tasks, chain services into dependency graphs, run them concurrently via
|
|
|
14
14
|
╰──────────────────────────────────────╯
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
**Ruby >= 3.4** | **v1.
|
|
17
|
+
**Ruby >= 3.4** | **v1.6.20** | **Apache-2.0** | [@Esity](https://github.com/Esity)
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
data/legionio.gemspec
CHANGED
|
@@ -56,7 +56,7 @@ Gem::Specification.new do |spec|
|
|
|
56
56
|
spec.add_dependency 'legion-crypt', '>= 1.4.17'
|
|
57
57
|
spec.add_dependency 'legion-data', '>= 1.6.7'
|
|
58
58
|
spec.add_dependency 'legion-json', '>= 1.2.1'
|
|
59
|
-
spec.add_dependency 'legion-logging', '>= 1.
|
|
59
|
+
spec.add_dependency 'legion-logging', '>= 1.4.0'
|
|
60
60
|
spec.add_dependency 'legion-settings', '>= 1.3.19'
|
|
61
61
|
spec.add_dependency 'legion-transport', '>= 1.4.4'
|
|
62
62
|
|
data/lib/legion/api/hooks.rb
CHANGED
|
@@ -66,8 +66,7 @@ module Legion
|
|
|
66
66
|
|
|
67
67
|
dispatch_hook(context, payload: payload, runner: runner, function: function)
|
|
68
68
|
rescue StandardError => e
|
|
69
|
-
Legion::Logging.
|
|
70
|
-
Legion::Logging.error e.backtrace&.first(5)
|
|
69
|
+
Legion::Logging.log_exception(e, payload_summary: "API #{request.request_method} #{request.path_info}", component_type: :api)
|
|
71
70
|
context.json_error('internal_error', e.message, status_code: 500)
|
|
72
71
|
end
|
|
73
72
|
|
data/lib/legion/api/lex.rb
CHANGED
|
@@ -53,8 +53,7 @@ module Legion
|
|
|
53
53
|
context.json_response({ task_id: result[:task_id], status: result[:status],
|
|
54
54
|
result: result[:result] }.compact)
|
|
55
55
|
rescue StandardError => e
|
|
56
|
-
Legion::Logging.
|
|
57
|
-
Legion::Logging.error e.backtrace&.first(5)
|
|
56
|
+
Legion::Logging.log_exception(e, payload_summary: "API POST /api/lex/#{request.path_info.sub(%r{^/api/lex/}, '')}", component_type: :api)
|
|
58
57
|
context.json_error('internal_error', e.message, status_code: 500)
|
|
59
58
|
end
|
|
60
59
|
|
data/lib/legion/api.rb
CHANGED
|
@@ -95,8 +95,7 @@ module Legion
|
|
|
95
95
|
error do
|
|
96
96
|
content_type :json
|
|
97
97
|
err = env['sinatra.error']
|
|
98
|
-
Legion::Logging.
|
|
99
|
-
Legion::Logging.error err.backtrace&.first(10)
|
|
98
|
+
Legion::Logging.log_exception(err, payload_summary: "API #{request.request_method} #{request.path_info} returned 500", component_type: :api)
|
|
100
99
|
Legion::JSON.dump({
|
|
101
100
|
error: { code: 'internal_error', message: err.message },
|
|
102
101
|
meta: { timestamp: Time.now.utc.iso8601, node: Legion::Settings[:client][:name] }
|
data/lib/legion/events.rb
CHANGED
|
@@ -31,8 +31,7 @@ module Legion
|
|
|
31
31
|
listeners[event_name.to_s].each do |listener|
|
|
32
32
|
listener.call(event)
|
|
33
33
|
rescue StandardError => e
|
|
34
|
-
Legion::Logging.
|
|
35
|
-
Legion::Logging.error e.backtrace&.first(5)
|
|
34
|
+
Legion::Logging.log_exception(e, payload_summary: "[Events] listener error on #{event_name}", component_type: :event)
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
# Also fire wildcard listeners
|
|
@@ -9,8 +9,7 @@ module Legion
|
|
|
9
9
|
def runner
|
|
10
10
|
Legion::Runner.run(runner_class: runner_class, function: function, check_subtask: check_subtask?, generate_task: generate_task?)
|
|
11
11
|
rescue StandardError => e
|
|
12
|
-
Legion::Logging.
|
|
13
|
-
Legion::Logging.error e.backtrace
|
|
12
|
+
Legion::Logging.log_exception(e, component_type: :actor)
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def manual
|
|
@@ -23,8 +22,7 @@ module Legion
|
|
|
23
22
|
klass.send(func, **args)
|
|
24
23
|
end
|
|
25
24
|
rescue StandardError => e
|
|
26
|
-
Legion::Logging.
|
|
27
|
-
Legion::Logging.error e.backtrace
|
|
25
|
+
Legion::Logging.log_exception(e, component_type: :actor)
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
def function
|
|
@@ -16,15 +16,13 @@ module Legion
|
|
|
16
16
|
begin
|
|
17
17
|
skip_or_run { use_runner? ? runner : manual }
|
|
18
18
|
rescue StandardError => e
|
|
19
|
-
log.
|
|
20
|
-
log.error e.backtrace if defined?(log)
|
|
19
|
+
log.log_exception(e, payload_summary: "[Every] tick failed for #{self.class}", component_type: :actor) if defined?(log)
|
|
21
20
|
end
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
@timer.execute
|
|
25
24
|
rescue StandardError => e
|
|
26
|
-
log.
|
|
27
|
-
log.error e.backtrace
|
|
25
|
+
log.log_exception(e, component_type: :actor)
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
def time
|
|
@@ -49,8 +47,7 @@ module Legion
|
|
|
49
47
|
|
|
50
48
|
@timer.shutdown
|
|
51
49
|
rescue StandardError => e
|
|
52
|
-
log.
|
|
53
|
-
log.error e.backtrace
|
|
50
|
+
log.log_exception(e, component_type: :actor)
|
|
54
51
|
end
|
|
55
52
|
end
|
|
56
53
|
end
|
|
@@ -17,13 +17,11 @@ check_subtask: check_subtask? }}"
|
|
|
17
17
|
@timer = Concurrent::TimerTask.new(execution_interval: time, run_now: run_now?) do
|
|
18
18
|
skip_or_run { poll_cycle }
|
|
19
19
|
rescue StandardError => e
|
|
20
|
-
Legion::Logging.fatal
|
|
21
|
-
Legion::Logging.fatal e.backtrace
|
|
20
|
+
Legion::Logging.log_exception(e, level: :fatal, component_type: :actor)
|
|
22
21
|
end
|
|
23
22
|
@timer.execute
|
|
24
23
|
rescue StandardError => e
|
|
25
|
-
Legion::Logging.
|
|
26
|
-
Legion::Logging.error e.backtrace
|
|
24
|
+
Legion::Logging.log_exception(e, component_type: :actor)
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
def poll_cycle
|
|
@@ -55,8 +53,7 @@ check_subtask: check_subtask? }}"
|
|
|
55
53
|
log.debug("#{self.class} result: #{results}")
|
|
56
54
|
results
|
|
57
55
|
rescue StandardError => e
|
|
58
|
-
Legion::Logging.fatal
|
|
59
|
-
Legion::Logging.fatal e.backtrace
|
|
56
|
+
Legion::Logging.log_exception(e, level: :fatal, component_type: :actor)
|
|
60
57
|
end
|
|
61
58
|
|
|
62
59
|
def cache_name
|
|
@@ -91,7 +88,7 @@ check_subtask: check_subtask? }}"
|
|
|
91
88
|
Legion::Logging.debug 'Cancelling Legion Poller'
|
|
92
89
|
@timer.shutdown
|
|
93
90
|
rescue StandardError => e
|
|
94
|
-
Legion::Logging.
|
|
91
|
+
Legion::Logging.log_exception(e, component_type: :actor)
|
|
95
92
|
end
|
|
96
93
|
end
|
|
97
94
|
end
|
|
@@ -17,8 +17,7 @@ module Legion
|
|
|
17
17
|
@queue = queue.new
|
|
18
18
|
@queue.channel.prefetch(prefetch) if defined? prefetch
|
|
19
19
|
rescue StandardError => e
|
|
20
|
-
log.fatal
|
|
21
|
-
log.fatal e.backtrace
|
|
20
|
+
log.log_exception(e, level: :fatal, component_type: :actor)
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
def create_queue
|
|
@@ -48,12 +47,13 @@ module Legion
|
|
|
48
47
|
true
|
|
49
48
|
end
|
|
50
49
|
|
|
51
|
-
def prepare
|
|
50
|
+
def prepare
|
|
52
51
|
@queue = queue.new
|
|
53
52
|
@queue.channel.prefetch(prefetch) if defined? prefetch
|
|
54
53
|
consumer_tag = "#{Legion::Settings[:client][:name]}_#{lex_name}_#{runner_name}_#{SecureRandom.uuid}"
|
|
55
54
|
@consumer = Bunny::Consumer.new(@queue.channel, @queue, consumer_tag, false, false)
|
|
56
55
|
@consumer.on_delivery do |delivery_info, metadata, payload|
|
|
56
|
+
fn = nil
|
|
57
57
|
message = process_message(payload, metadata, delivery_info)
|
|
58
58
|
fn = find_function(message)
|
|
59
59
|
log.debug "[Subscription] message received: #{lex_name}/#{fn}" if defined?(log)
|
|
@@ -76,14 +76,12 @@ module Legion
|
|
|
76
76
|
|
|
77
77
|
cancel if Legion::Settings[:client][:shutting_down]
|
|
78
78
|
rescue StandardError => e
|
|
79
|
-
log.
|
|
80
|
-
log.error e.backtrace
|
|
79
|
+
log.log_exception(e, payload_summary: "[Subscription] message processing failed: #{lex_name}/#{fn}", component_type: :actor)
|
|
81
80
|
@queue.reject(delivery_info.delivery_tag) if manual_ack
|
|
82
81
|
end
|
|
83
82
|
log.info "[Subscription] prepared: #{lex_name}/#{runner_name}"
|
|
84
83
|
rescue StandardError => e
|
|
85
|
-
log.fatal
|
|
86
|
-
log.fatal e.backtrace
|
|
84
|
+
log.log_exception(e, level: :fatal, payload_summary: 'Subscription#prepare failed', component_type: :actor)
|
|
87
85
|
end
|
|
88
86
|
|
|
89
87
|
def activate
|
|
@@ -159,6 +157,7 @@ module Legion
|
|
|
159
157
|
metadata = rmq_message.last
|
|
160
158
|
delivery_info = rmq_message.first
|
|
161
159
|
|
|
160
|
+
fn = nil
|
|
162
161
|
message = process_message(payload, metadata, delivery_info)
|
|
163
162
|
fn = find_function(message)
|
|
164
163
|
log.debug "[Subscription] message received: #{lex_name}/#{fn}" if defined?(log)
|
|
@@ -185,8 +184,7 @@ module Legion
|
|
|
185
184
|
|
|
186
185
|
cancel if Legion::Settings[:client][:shutting_down]
|
|
187
186
|
rescue StandardError => e
|
|
188
|
-
log.
|
|
189
|
-
log.error e.backtrace
|
|
187
|
+
log.log_exception(e, payload_summary: "[Subscription] message processing failed: #{lex_name}/#{fn}", component_type: :actor)
|
|
190
188
|
log.warn "[Subscription] nacking message for #{lex_name}/#{fn}"
|
|
191
189
|
@queue.reject(delivery_info.delivery_tag) if manual_ack
|
|
192
190
|
end
|
|
@@ -220,9 +220,7 @@ module Legion
|
|
|
220
220
|
lex_class.const_set(:Data, Module.new { extend Legion::Extensions::Data })
|
|
221
221
|
end
|
|
222
222
|
rescue StandardError => e
|
|
223
|
-
|
|
224
|
-
log.error e.message
|
|
225
|
-
log.error e.backtrace
|
|
223
|
+
log.log_exception(e, payload_summary: "[Core] auto_generate_data failed for #{name}", component_type: :builder)
|
|
226
224
|
end
|
|
227
225
|
end
|
|
228
226
|
end
|
|
@@ -7,9 +7,17 @@ module Legion
|
|
|
7
7
|
include Legion::Logging::Helper
|
|
8
8
|
|
|
9
9
|
def handle_exception(exception, task_id: nil, **opts)
|
|
10
|
-
|
|
11
|
-
log.
|
|
12
|
-
|
|
10
|
+
spec = gem_spec_for_lex
|
|
11
|
+
log.log_exception(exception,
|
|
12
|
+
lex: log_lex_name,
|
|
13
|
+
component_type: derive_component_type,
|
|
14
|
+
gem_name: lex_gem_name,
|
|
15
|
+
lex_version: spec&.version&.to_s,
|
|
16
|
+
gem_path: spec&.full_gem_path,
|
|
17
|
+
source_code_uri: spec&.metadata&.[]('source_code_uri'),
|
|
18
|
+
handled: true,
|
|
19
|
+
payload_summary: opts.empty? ? nil : opts,
|
|
20
|
+
task_id: task_id)
|
|
13
21
|
|
|
14
22
|
unless task_id.nil?
|
|
15
23
|
Legion::Transport::Messages::TaskLog.new(
|
|
@@ -25,6 +33,51 @@ module Legion
|
|
|
25
33
|
|
|
26
34
|
raise Legion::Exception::HandledTask
|
|
27
35
|
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def derive_component_type
|
|
40
|
+
parts = respond_to?(:calling_class_array) ? calling_class_array : self.class.to_s.split('::')
|
|
41
|
+
match = parts.find { |p| Legion::Extensions::Helpers::Base::NAMESPACE_BOUNDARIES.include?(p) }
|
|
42
|
+
case match
|
|
43
|
+
when 'Runners' then :runner
|
|
44
|
+
when 'Actor', 'Actors' then :actor
|
|
45
|
+
when 'Transport' then :transport
|
|
46
|
+
when 'Helpers' then :helper
|
|
47
|
+
when 'Data' then :data
|
|
48
|
+
else :unknown
|
|
49
|
+
end
|
|
50
|
+
rescue StandardError
|
|
51
|
+
:unknown
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def lex_gem_name
|
|
55
|
+
base_name = log_lex_name
|
|
56
|
+
return nil unless base_name
|
|
57
|
+
|
|
58
|
+
"lex-#{base_name}"
|
|
59
|
+
rescue StandardError
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def gem_spec_for_lex
|
|
64
|
+
name = lex_gem_name
|
|
65
|
+
return nil unless name
|
|
66
|
+
|
|
67
|
+
Gem::Specification.find_by_name(name)
|
|
68
|
+
rescue Gem::MissingSpecError
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def log_lex_name
|
|
73
|
+
if respond_to?(:segments)
|
|
74
|
+
segments.join('-')
|
|
75
|
+
else
|
|
76
|
+
derive_log_tag
|
|
77
|
+
end
|
|
78
|
+
rescue StandardError
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
28
81
|
end
|
|
29
82
|
end
|
|
30
83
|
end
|
|
@@ -16,8 +16,7 @@ module Legion
|
|
|
16
16
|
return true if Legion::Data::Model::TaskLog.insert(task_id: task_id, function_id: function_id, entry: Legion::JSON.dump(payload))
|
|
17
17
|
end
|
|
18
18
|
rescue StandardError => e
|
|
19
|
-
log.warn
|
|
20
|
-
log.warn("generate_task_log failed, reverting to rmq message, e: #{e.message}")
|
|
19
|
+
log.log_exception(e, level: :warn, payload_summary: 'generate_task_log failed, reverting to rmq message', component_type: :helper)
|
|
21
20
|
end
|
|
22
21
|
Legion::Transport::Messages::TaskLog.new(task_id: task_id, runner_class: runner_class, function: function, entry: payload).publish
|
|
23
22
|
end
|
|
@@ -41,8 +40,7 @@ module Legion
|
|
|
41
40
|
end
|
|
42
41
|
Legion::Transport::Messages::TaskUpdate.new(**update_hash).publish
|
|
43
42
|
rescue StandardError => e
|
|
44
|
-
log.fatal
|
|
45
|
-
log.fatal e.backtrace
|
|
43
|
+
log.log_exception(e, level: :fatal, component_type: :helper)
|
|
46
44
|
raise e
|
|
47
45
|
end
|
|
48
46
|
|
|
@@ -24,8 +24,7 @@ module Legion
|
|
|
24
24
|
auto_create_dlx_queue
|
|
25
25
|
log.info "[Transport] built exchanges=#{@exchanges.count} queues=#{@queues.count} for #{lex_name}"
|
|
26
26
|
rescue StandardError => e
|
|
27
|
-
log.
|
|
28
|
-
log.error e.backtrace
|
|
27
|
+
log.log_exception(e, payload_summary: "[Transport] build failed for #{lex_name}", component_type: :transport)
|
|
29
28
|
end
|
|
30
29
|
|
|
31
30
|
def generate_base_modules
|
|
@@ -140,9 +139,7 @@ module Legion
|
|
|
140
139
|
to = to.is_a?(String) ? Kernel.const_get(to).new : to.new
|
|
141
140
|
to.bind(from, routing_key: routing_key)
|
|
142
141
|
rescue StandardError => e
|
|
143
|
-
log.fatal
|
|
144
|
-
log.fatal e.backtrace
|
|
145
|
-
log.fatal({ from: from, to: to, routing_key: routing_key })
|
|
142
|
+
log.log_exception(e, level: :fatal, payload_summary: { from: from, to: to, routing_key: routing_key }, component_type: :transport)
|
|
146
143
|
end
|
|
147
144
|
|
|
148
145
|
def e_to_q
|
data/lib/legion/extensions.rb
CHANGED
data/lib/legion/runner/status.rb
CHANGED
|
@@ -21,8 +21,7 @@ module Legion
|
|
|
21
21
|
Legion::Transport::Messages::TaskUpdate.new(task_id: task_id, status: status, **).publish
|
|
22
22
|
rescue StandardError => e
|
|
23
23
|
retries += 1
|
|
24
|
-
Legion::Logging.
|
|
25
|
-
Legion::Logging.fatal e.backtrace
|
|
24
|
+
Legion::Logging.log_exception(e, level: :fatal, payload_summary: "[Status] update_rmq failed (attempt #{retries}/3)", component_type: :runner)
|
|
26
25
|
retry if retries < 3
|
|
27
26
|
end
|
|
28
27
|
|
|
@@ -32,9 +31,9 @@ module Legion
|
|
|
32
31
|
task = Legion::Data::Model::Task[task_id]
|
|
33
32
|
task.update(status: status)
|
|
34
33
|
rescue StandardError => e
|
|
35
|
-
Legion::Logging.
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
Legion::Logging.log_exception(e, level: :warn,
|
|
35
|
+
payload_summary: "[Status] update_db failed for task_id=#{task_id}, falling back to RabbitMQ update",
|
|
36
|
+
component_type: :runner)
|
|
38
37
|
update_rmq(task_id: task_id, status: status, **)
|
|
39
38
|
end
|
|
40
39
|
|
|
@@ -61,8 +60,7 @@ module Legion
|
|
|
61
60
|
|
|
62
61
|
{ success: true, task_id: Legion::Data::Model::Task.insert(insert), **insert }
|
|
63
62
|
rescue StandardError => e
|
|
64
|
-
Legion::Logging.
|
|
65
|
-
Legion::Logging.error e.backtrace
|
|
63
|
+
Legion::Logging.log_exception(e, component_type: :runner)
|
|
66
64
|
raise(e)
|
|
67
65
|
end
|
|
68
66
|
end
|
data/lib/legion/service.rb
CHANGED
|
@@ -48,7 +48,7 @@ module Legion
|
|
|
48
48
|
if transport
|
|
49
49
|
setup_transport
|
|
50
50
|
Legion::Readiness.mark_ready(:transport)
|
|
51
|
-
|
|
51
|
+
setup_logging_transport
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
setup_dispatch
|
|
@@ -248,14 +248,18 @@ module Legion
|
|
|
248
248
|
Legion::Logging.setup(log_level: log_level, level: log_level, trace: true)
|
|
249
249
|
end
|
|
250
250
|
|
|
251
|
-
def reconfigure_logging(cli_level)
|
|
252
|
-
|
|
253
|
-
level = cli_level ||
|
|
251
|
+
def reconfigure_logging(cli_level = nil)
|
|
252
|
+
ls = Legion::Settings[:logging] || {}
|
|
253
|
+
level = cli_level || ls[:level] || 'info'
|
|
254
|
+
|
|
254
255
|
Legion::Logging.setup(
|
|
255
|
-
level:
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
level: level,
|
|
257
|
+
format: (ls[:format] || 'text').to_sym,
|
|
258
|
+
log_file: ls[:log_file],
|
|
259
|
+
log_stdout: ls.fetch(:log_stdout, true),
|
|
260
|
+
trace: ls.fetch(:trace, true),
|
|
261
|
+
async: ls.fetch(:async, true),
|
|
262
|
+
include_pid: ls.fetch(:include_pid, false)
|
|
259
263
|
)
|
|
260
264
|
end
|
|
261
265
|
|
|
@@ -365,34 +369,73 @@ module Legion
|
|
|
365
369
|
Legion::Logging.info 'Legion::Transport connected'
|
|
366
370
|
end
|
|
367
371
|
|
|
368
|
-
def
|
|
372
|
+
def setup_logging_transport # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
369
373
|
return unless defined?(Legion::Transport::Connection)
|
|
370
374
|
return unless Legion::Transport::Connection.session_open?
|
|
371
|
-
return unless Legion::Transport::Connection.respond_to?(:log_channel)
|
|
372
375
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
376
|
+
lt_settings = begin
|
|
377
|
+
Legion::Settings.dig(:logging, :transport) || {}
|
|
378
|
+
rescue StandardError
|
|
379
|
+
{}
|
|
377
380
|
end
|
|
381
|
+
return unless lt_settings[:enabled] == true
|
|
378
382
|
|
|
379
|
-
|
|
380
|
-
|
|
383
|
+
forward_logs = lt_settings.fetch(:forward_logs, true)
|
|
384
|
+
forward_exceptions = lt_settings.fetch(:forward_exceptions, true)
|
|
385
|
+
return unless forward_logs || forward_exceptions
|
|
381
386
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
387
|
+
log_session = Legion::Transport::Connection.create_dedicated_session(name: 'legion-logging')
|
|
388
|
+
@log_session = log_session
|
|
389
|
+
log_channel = log_session.create_channel
|
|
390
|
+
log_channel.prefetch(1)
|
|
391
|
+
exchange = log_channel.topic('legion.logging', durable: true)
|
|
385
392
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
393
|
+
if forward_logs
|
|
394
|
+
Legion::Logging.log_writer = lambda { |event, routing_key:|
|
|
395
|
+
begin
|
|
396
|
+
next unless log_channel&.open?
|
|
397
|
+
|
|
398
|
+
exchange.publish(Legion::JSON.dump(event), routing_key: routing_key)
|
|
399
|
+
rescue StandardError
|
|
400
|
+
nil
|
|
401
|
+
end
|
|
402
|
+
}
|
|
392
403
|
end
|
|
393
404
|
|
|
394
|
-
|
|
395
|
-
|
|
405
|
+
if forward_exceptions
|
|
406
|
+
Legion::Logging.exception_writer = lambda { |event, routing_key:, headers:, properties:|
|
|
407
|
+
begin
|
|
408
|
+
next unless log_channel&.open?
|
|
409
|
+
|
|
410
|
+
exchange.publish(
|
|
411
|
+
Legion::JSON.dump(event),
|
|
412
|
+
routing_key: routing_key,
|
|
413
|
+
headers: headers,
|
|
414
|
+
**properties
|
|
415
|
+
)
|
|
416
|
+
rescue StandardError
|
|
417
|
+
nil
|
|
418
|
+
end
|
|
419
|
+
}
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
modes = []
|
|
423
|
+
modes << 'logs' if forward_logs
|
|
424
|
+
modes << 'exceptions' if forward_exceptions
|
|
425
|
+
Legion::Logging.info("Logging transport wired: #{modes.join(' + ')} (dedicated session)")
|
|
426
|
+
rescue StandardError => e
|
|
427
|
+
Legion::Logging.warn "Logging transport setup failed: #{e.message}"
|
|
428
|
+
teardown_logging_transport
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def teardown_logging_transport
|
|
432
|
+
Legion::Logging.log_writer = nil
|
|
433
|
+
Legion::Logging.exception_writer = nil
|
|
434
|
+
@log_session&.close if @log_session.respond_to?(:close) &&
|
|
435
|
+
(!@log_session.respond_to?(:open?) || @log_session.open?)
|
|
436
|
+
@log_session = nil
|
|
437
|
+
rescue StandardError
|
|
438
|
+
nil
|
|
396
439
|
end
|
|
397
440
|
|
|
398
441
|
def setup_alerts
|
|
@@ -547,6 +590,7 @@ module Legion
|
|
|
547
590
|
shutdown_component('Cache') { Legion::Cache.shutdown }
|
|
548
591
|
Legion::Readiness.mark_not_ready(:cache)
|
|
549
592
|
|
|
593
|
+
teardown_logging_transport
|
|
550
594
|
shutdown_component('Transport') { Legion::Transport::Connection.shutdown }
|
|
551
595
|
Legion::Readiness.mark_not_ready(:transport)
|
|
552
596
|
|
|
@@ -558,7 +602,7 @@ module Legion
|
|
|
558
602
|
Legion::Events.emit('service.shutdown')
|
|
559
603
|
end
|
|
560
604
|
|
|
561
|
-
def reload
|
|
605
|
+
def reload # rubocop:disable Metrics/MethodLength
|
|
562
606
|
return if @reloading
|
|
563
607
|
|
|
564
608
|
@reloading = true
|
|
@@ -583,6 +627,7 @@ module Legion
|
|
|
583
627
|
shutdown_component('Cache') { Legion::Cache.shutdown }
|
|
584
628
|
Legion::Readiness.mark_not_ready(:cache)
|
|
585
629
|
|
|
630
|
+
teardown_logging_transport
|
|
586
631
|
shutdown_component('Transport') { Legion::Transport::Connection.shutdown }
|
|
587
632
|
Legion::Readiness.mark_not_ready(:transport)
|
|
588
633
|
|
|
@@ -599,7 +644,8 @@ module Legion
|
|
|
599
644
|
|
|
600
645
|
setup_transport
|
|
601
646
|
Legion::Readiness.mark_ready(:transport)
|
|
602
|
-
|
|
647
|
+
teardown_logging_transport
|
|
648
|
+
setup_logging_transport
|
|
603
649
|
|
|
604
650
|
require 'legion/cache' unless defined?(Legion::Cache)
|
|
605
651
|
Legion::Cache.setup
|
data/lib/legion/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legionio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.
|
|
4
|
+
version: 1.6.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -281,14 +281,14 @@ dependencies:
|
|
|
281
281
|
requirements:
|
|
282
282
|
- - ">="
|
|
283
283
|
- !ruby/object:Gem::Version
|
|
284
|
-
version: 1.
|
|
284
|
+
version: 1.4.0
|
|
285
285
|
type: :runtime
|
|
286
286
|
prerelease: false
|
|
287
287
|
version_requirements: !ruby/object:Gem::Requirement
|
|
288
288
|
requirements:
|
|
289
289
|
- - ">="
|
|
290
290
|
- !ruby/object:Gem::Version
|
|
291
|
-
version: 1.
|
|
291
|
+
version: 1.4.0
|
|
292
292
|
- !ruby/object:Gem::Dependency
|
|
293
293
|
name: legion-settings
|
|
294
294
|
requirement: !ruby/object:Gem::Requirement
|