julewire-core 1.0.0 → 1.1.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/CHANGELOG.md +29 -0
- data/docs/advanced-configuration.md +2 -1
- data/docs/configuration.md +14 -7
- data/docs/context-and-propagation.md +26 -4
- data/docs/contracts.md +25 -50
- data/docs/extensions-and-api.md +87 -88
- data/docs/health-schema.md +12 -2
- data/docs/internals.md +24 -23
- data/docs/outputs-and-lifecycle.md +15 -8
- data/docs/records-and-data-policy.md +38 -7
- data/lib/julewire/core/cli/doctor.rb +20 -16
- data/lib/julewire/core/cli/line_helpers.rb +23 -12
- data/lib/julewire/core/cli/log_formats/core_json_decoder.rb +3 -3
- data/lib/julewire/core/cli/log_formats/record_decoder.rb +1 -1
- data/lib/julewire/core/cli/log_formats.rb +9 -9
- data/lib/julewire/core/cli/tail.rb +19 -14
- data/lib/julewire/core/cli/transcode.rb +4 -5
- data/lib/julewire/core/cli.rb +1 -1
- data/lib/julewire/core/configuration.rb +1 -1
- data/lib/julewire/core/context_store.rb +56 -87
- data/lib/julewire/core/destinations/chaos_output.rb +2 -2
- data/lib/julewire/core/destinations/collection.rb +8 -16
- data/lib/julewire/core/destinations/definition.rb +1 -9
- data/lib/julewire/core/destinations/destination.rb +16 -66
- data/lib/julewire/core/destinations/processor_handling.rb +78 -0
- data/lib/julewire/core/destinations/registry.rb +1 -1
- data/lib/julewire/core/destinations/sink.rb +0 -1
- data/lib/julewire/core/destinations/synchronized_output.rb +54 -17
- data/lib/julewire/core/destinations/tail_sampling.rb +18 -27
- data/lib/julewire/core/destinations/write_step.rb +5 -5
- data/lib/julewire/core/destinations.rb +0 -7
- data/lib/julewire/core/diagnostics/callback_notifier.rb +4 -2
- data/lib/julewire/core/diagnostics/doctor.rb +22 -15
- data/lib/julewire/core/diagnostics/failure_snapshot.rb +9 -3
- data/lib/julewire/core/diagnostics/health.rb +41 -57
- data/lib/julewire/core/diagnostics/integration_health_store.rb +11 -24
- data/lib/julewire/core/diagnostics/internal_records.rb +8 -12
- data/lib/julewire/core/diagnostics/invalid_severity_reporter.rb +16 -55
- data/lib/julewire/core/diagnostics/meta_observer.rb +37 -44
- data/lib/julewire/core/diagnostics/process_integration_health.rb +0 -5
- data/lib/julewire/core/diagnostics/tail/renderer.rb +1 -1
- data/lib/julewire/core/diagnostics/tail.rb +18 -22
- data/lib/julewire/core/execution/boundary.rb +2 -8
- data/lib/julewire/core/execution/handle.rb +14 -17
- data/lib/julewire/core/execution/lineage.rb +26 -62
- data/lib/julewire/core/execution/measurement_handle.rb +6 -10
- data/lib/julewire/core/execution/scope.rb +17 -22
- data/lib/julewire/core/execution/scope_fields.rb +4 -13
- data/lib/julewire/core/execution/scope_identity.rb +1 -9
- data/lib/julewire/core/execution/scope_snapshot.rb +18 -39
- data/lib/julewire/core/execution/summary_state.rb +16 -19
- data/lib/julewire/core/execution/view.rb +8 -17
- data/lib/julewire/core/facade_methods.rb +67 -65
- data/lib/julewire/core/fields/attribute_keys.rb +0 -2
- data/lib/julewire/core/fields/bags.rb +23 -27
- data/lib/julewire/core/fields/field_set.rb +52 -16
- data/lib/julewire/core/fields/field_stack.rb +69 -109
- data/lib/julewire/core/fields/internal/deletion.rb +6 -9
- data/lib/julewire/core/fields/internal.rb +35 -26
- data/lib/julewire/core/fields/lookup.rb +9 -13
- data/lib/julewire/core/fields/section_proxy.rb +1 -9
- data/lib/julewire/core/fields/stack_set.rb +9 -14
- data/lib/julewire/core/fields/static_labels.rb +1 -1
- data/lib/julewire/core/integration/configurable.rb +4 -3
- data/lib/julewire/core/integration/destination_health.rb +28 -7
- data/lib/julewire/core/integration/event_subscriber.rb +1 -1
- data/lib/julewire/core/integration/facade.rb +12 -15
- data/lib/julewire/core/integration/fork_hooks.rb +12 -36
- data/lib/julewire/core/integration/health.rb +0 -3
- data/lib/julewire/core/integration/ivar_state.rb +0 -5
- data/lib/julewire/core/integration/protocol.rb +20 -0
- data/lib/julewire/core/integration/settings.rb +4 -4
- data/lib/julewire/core/integration/subscriber_install.rb +2 -2
- data/lib/julewire/core/integration/subscription.rb +3 -2
- data/lib/julewire/core/integration/values.rb +0 -17
- data/lib/julewire/core/local_storage.rb +3 -19
- data/lib/julewire/core/processing/invalid_result_failure.rb +23 -0
- data/lib/julewire/core/processing/level_threshold.rb +7 -14
- data/lib/julewire/core/processing/match.rb +6 -4
- data/lib/julewire/core/processing/pipeline.rb +46 -40
- data/lib/julewire/core/processing/processor_chain.rb +22 -11
- data/lib/julewire/core/processing/processor_registry.rb +3 -4
- data/lib/julewire/core/processing/record_field_transform.rb +0 -4
- data/lib/julewire/core/processing/sampling.rb +1 -3
- data/lib/julewire/core/processing.rb +2 -2
- data/lib/julewire/core/propagation/carrier.rb +73 -19
- data/lib/julewire/core/propagation.rb +18 -4
- data/lib/julewire/core/records/build_input.rb +75 -0
- data/lib/julewire/core/records/console_formatter.rb +6 -6
- data/lib/julewire/core/records/deconstruct.rb +1 -1
- data/lib/julewire/core/records/display_message.rb +2 -4
- data/lib/julewire/core/records/draft.rb +127 -258
- data/lib/julewire/core/records/lazy_emit_input.rb +2 -12
- data/lib/julewire/core/records/metadata.rb +4 -3
- data/lib/julewire/core/records/public_projection.rb +2 -2
- data/lib/julewire/core/records/raw_input.rb +1 -1
- data/lib/julewire/core/records/record.rb +30 -18
- data/lib/julewire/core/records/severity.rb +7 -15
- data/lib/julewire/core/runtime.rb +87 -72
- data/lib/julewire/core/runtime_registry.rb +20 -15
- data/lib/julewire/core/runtime_state.rb +5 -3
- data/lib/julewire/core/scheduling/shared_scheduler.rb +28 -22
- data/lib/julewire/core/serialization/backtrace_limiter.rb +13 -9
- data/lib/julewire/core/serialization/bounded_transform.rb +3 -2
- data/lib/julewire/core/serialization/bounded_traversal.rb +72 -83
- data/lib/julewire/core/serialization/deep_compact_empty.rb +9 -11
- data/lib/julewire/core/serialization/deep_freeze.rb +45 -6
- data/lib/julewire/core/serialization/encoding_sanitizer.rb +2 -3
- data/lib/julewire/core/serialization/exception_shape.rb +7 -6
- data/lib/julewire/core/serialization/json_encoder.rb +10 -13
- data/lib/julewire/core/serialization/serializer.rb +22 -49
- data/lib/julewire/core/serialization/serializer_pool.rb +9 -0
- data/lib/julewire/core/serialization/text_encoder.rb +5 -5
- data/lib/julewire/core/serialization/truncation_metadata.rb +157 -0
- data/lib/julewire/core/serialization/value_copy.rb +183 -109
- data/lib/julewire/core/serialization/value_traversal.rb +10 -127
- data/lib/julewire/core/testing.rb +6 -56
- data/lib/julewire/core/validation.rb +2 -3
- data/lib/julewire/core/version.rb +1 -1
- data/lib/julewire/core.rb +2 -7
- metadata +7 -19
- data/lib/julewire/core/scheduling/deadline_scheduler.rb +0 -207
- data/lib/julewire/core/testing/chaos/catalog.rb +0 -72
- data/lib/julewire/core/testing/chaos/core_runtime.rb +0 -120
- data/lib/julewire/core/testing/chaos/destination.rb +0 -55
- data/lib/julewire/core/testing/chaos/emitter.rb +0 -20
- data/lib/julewire/core/testing/chaos/raising_output.rb +0 -42
- data/lib/julewire/core/testing/chaos.rb +0 -80
- data/lib/julewire/core/testing/contracts/component.rb +0 -162
- data/lib/julewire/core/testing/contracts/deadline_scheduler.rb +0 -59
- data/lib/julewire/core/testing/contracts/integration.rb +0 -166
- data/lib/julewire/core/testing/contracts/integration_fields.rb +0 -36
- data/lib/julewire/core/testing/contracts/record_draft.rb +0 -37
- data/lib/julewire/core/testing/contracts/runtime.rb +0 -178
- data/lib/julewire/core/testing/contracts/wire.rb +0 -60
- data/lib/julewire/core/testing/contracts.rb +0 -24
- data/lib/julewire/core/testing/coverage.rb +0 -58
- data/lib/julewire/core/testing/test_reports.rb +0 -78
|
@@ -6,24 +6,16 @@ module Julewire
|
|
|
6
6
|
# @api integration_spi
|
|
7
7
|
module Facade
|
|
8
8
|
class << self
|
|
9
|
-
def emit(record =
|
|
9
|
+
def emit(record = UNSET, enforce_level: true, **fields)
|
|
10
10
|
record = Core.emit_input(record, fields)
|
|
11
|
-
|
|
12
|
-
if runtime.respond_to?(:emit_integration)
|
|
13
|
-
runtime.emit_integration(record, enforce_level: enforce_level)
|
|
14
|
-
elsif enforce_level
|
|
15
|
-
runtime.emit(record)
|
|
16
|
-
else
|
|
17
|
-
runtime.emit_without_level(record)
|
|
18
|
-
end
|
|
11
|
+
RuntimeLocator.current.emit_integration(record, enforce_level: enforce_level)
|
|
19
12
|
nil
|
|
20
13
|
end
|
|
21
14
|
|
|
22
|
-
def with_execution(type:,
|
|
23
|
-
raise ArgumentError, "block required" unless block_given?
|
|
24
|
-
|
|
15
|
+
def with_execution(type:, **options, &)
|
|
25
16
|
integration_write_section!(:execution)
|
|
26
|
-
|
|
17
|
+
validate_owned_fields!(options)
|
|
18
|
+
RuntimeLocator.current.with_execution(type: type, owned: true, **options, &)
|
|
27
19
|
end
|
|
28
20
|
|
|
29
21
|
def with_attributes(fields, &)
|
|
@@ -88,6 +80,7 @@ module Julewire
|
|
|
88
80
|
raise ArgumentError, "block required" unless block_given?
|
|
89
81
|
|
|
90
82
|
integration_write_section!(section)
|
|
83
|
+
validate_owned_fields!(fields)
|
|
91
84
|
case section
|
|
92
85
|
when :attributes then ContextStore.current.with_attributes(fields, owned: true, &)
|
|
93
86
|
when :carry then ContextStore.current.with_carry(fields, owned: true, &)
|
|
@@ -104,7 +97,6 @@ module Julewire
|
|
|
104
97
|
when :context then ContextStore.current.add_context(fields, owned: true)
|
|
105
98
|
when :neutral then ContextStore.current.add_neutral(fields, owned: true)
|
|
106
99
|
end
|
|
107
|
-
nil
|
|
108
100
|
end
|
|
109
101
|
|
|
110
102
|
def integration_write_section!(section)
|
|
@@ -115,10 +107,15 @@ module Julewire
|
|
|
115
107
|
raise ArgumentError, "integration cannot write #{section}"
|
|
116
108
|
end
|
|
117
109
|
|
|
110
|
+
def validate_owned_fields!(value)
|
|
111
|
+
Protocol.validate_symbol_hash(value)
|
|
112
|
+
end
|
|
113
|
+
|
|
118
114
|
def add_summary_fields(fields, writer)
|
|
119
115
|
integration_write_section!(:summary)
|
|
116
|
+
validate_owned_fields!(fields)
|
|
120
117
|
scope = ContextStore.current.current_scope
|
|
121
|
-
return unless scope
|
|
118
|
+
return unless scope
|
|
122
119
|
|
|
123
120
|
fields = Serialization::DeepCompactEmpty.compact_owned!(fields)
|
|
124
121
|
scope.public_send(writer, fields, owned: true) unless fields.empty?
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "concurrent/map"
|
|
4
|
+
|
|
3
5
|
module Julewire
|
|
4
6
|
module Core
|
|
5
7
|
module Integration
|
|
@@ -7,51 +9,28 @@ module Julewire
|
|
|
7
9
|
Entry = Data.define(:integration, :component, :callback)
|
|
8
10
|
private_constant :Entry
|
|
9
11
|
|
|
10
|
-
@
|
|
11
|
-
@entries = {}
|
|
12
|
+
@entries = Concurrent::Map.new
|
|
12
13
|
|
|
13
14
|
class << self
|
|
14
15
|
def register(integration, component:, &callback)
|
|
15
16
|
raise ArgumentError, "block required" unless callback
|
|
16
17
|
|
|
17
|
-
name
|
|
18
|
-
component
|
|
19
|
-
register_entry(
|
|
18
|
+
validate_symbol_name!(integration, name: :integration)
|
|
19
|
+
validate_symbol_name!(component, name: :component)
|
|
20
|
+
register_entry(integration, component, callback)
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def run
|
|
23
|
-
snapshot =
|
|
24
|
+
snapshot = entries.values
|
|
24
25
|
snapshot.each { run_entry(it) }
|
|
25
|
-
nil
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def after_fork!
|
|
29
|
-
@mutex = Mutex.new
|
|
30
|
-
nil
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def reset!
|
|
34
|
-
mutex.synchronize { entries.clear }
|
|
35
|
-
nil
|
|
36
26
|
end
|
|
37
27
|
|
|
38
28
|
private
|
|
39
29
|
|
|
40
|
-
attr_reader :entries
|
|
30
|
+
attr_reader :entries
|
|
41
31
|
|
|
42
32
|
def register_entry(name, component, callback)
|
|
43
|
-
|
|
44
|
-
entries[[name, component]] = Entry.new(name, component, callback)
|
|
45
|
-
end
|
|
46
|
-
nil
|
|
47
|
-
rescue StandardError => e
|
|
48
|
-
Diagnostics::ProcessIntegrationHealth.record_failure(
|
|
49
|
-
name,
|
|
50
|
-
e,
|
|
51
|
-
action: :register_after_fork,
|
|
52
|
-
component: component
|
|
53
|
-
)
|
|
54
|
-
nil
|
|
33
|
+
entries[[name, component]] = Entry.new(name, component, callback)
|
|
55
34
|
end
|
|
56
35
|
|
|
57
36
|
def run_entry(entry)
|
|
@@ -63,14 +42,11 @@ module Julewire
|
|
|
63
42
|
action: :after_fork,
|
|
64
43
|
component: entry.component
|
|
65
44
|
)
|
|
66
|
-
nil
|
|
67
45
|
end
|
|
68
46
|
|
|
69
|
-
def
|
|
70
|
-
name
|
|
71
|
-
raise ArgumentError, "
|
|
72
|
-
|
|
73
|
-
name.to_sym
|
|
47
|
+
def validate_symbol_name!(value, name:)
|
|
48
|
+
raise TypeError, "#{name} must be a Symbol" unless value.instance_of?(Symbol)
|
|
49
|
+
raise ArgumentError, "#{name} is required" if value == :""
|
|
74
50
|
end
|
|
75
51
|
end
|
|
76
52
|
end
|
|
@@ -12,7 +12,6 @@ module Julewire
|
|
|
12
12
|
else
|
|
13
13
|
Diagnostics::ProcessIntegrationHealth.record_failure(integration, error, **metadata)
|
|
14
14
|
end
|
|
15
|
-
nil
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def record_success(integration, runtime: nil, **)
|
|
@@ -21,14 +20,12 @@ module Julewire
|
|
|
21
20
|
else
|
|
22
21
|
Diagnostics::ProcessIntegrationHealth.record_success(integration)
|
|
23
22
|
end
|
|
24
|
-
nil
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
def with_failure_health(integration, component:, action:, runtime: nil, **metadata)
|
|
28
26
|
yield.tap { record_success(integration, runtime: runtime) }
|
|
29
27
|
rescue StandardError => e
|
|
30
28
|
record_failure(integration, e, runtime: runtime, component: component, action: action, **metadata)
|
|
31
|
-
nil
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
def scoped(integration, runtime: nil)
|
|
@@ -10,18 +10,13 @@ module Julewire
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def fetch(owner)
|
|
13
|
-
return unless owner.respond_to?(:instance_variable_get)
|
|
14
|
-
|
|
15
13
|
owner.instance_variable_get(@marker)
|
|
16
14
|
rescue StandardError
|
|
17
15
|
nil
|
|
18
16
|
end
|
|
19
17
|
|
|
20
18
|
def store(owner, value)
|
|
21
|
-
return value unless owner.respond_to?(:instance_variable_set)
|
|
22
|
-
|
|
23
19
|
owner.instance_variable_set(@marker, value)
|
|
24
|
-
value
|
|
25
20
|
rescue StandardError
|
|
26
21
|
value
|
|
27
22
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Integration
|
|
6
|
+
# @api integration_spi
|
|
7
|
+
module Protocol
|
|
8
|
+
class << self
|
|
9
|
+
def validate_symbol_keys(value)
|
|
10
|
+
Serialization::DeepFreeze.validate_symbol_keys(value)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def validate_symbol_hash(value)
|
|
14
|
+
Serialization::DeepFreeze.validate_symbol_hash(value)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -13,7 +13,7 @@ module Julewire
|
|
|
13
13
|
|
|
14
14
|
module ClassMethods
|
|
15
15
|
def setting(name, default: nil, predicate: false, validate: nil, &block)
|
|
16
|
-
settings_defaults[name] = block ||
|
|
16
|
+
settings_defaults[name] = block || -> { default }
|
|
17
17
|
settings_validators[name] = validate if validate
|
|
18
18
|
ivar = :"@#{name}"
|
|
19
19
|
|
|
@@ -60,7 +60,7 @@ module Julewire
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def setting_default(default)
|
|
63
|
-
|
|
63
|
+
Fields::FieldSet.deep_dup(instance_exec(&default))
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def validate_settings!
|
|
@@ -81,9 +81,9 @@ module Julewire
|
|
|
81
81
|
case validator
|
|
82
82
|
when Symbol
|
|
83
83
|
validator_method = method(validator)
|
|
84
|
-
validator_method.arity ==
|
|
84
|
+
validator_method.arity == 2 ? validator_method.call(value, name) : validator_method.call(value)
|
|
85
85
|
else
|
|
86
|
-
validator.arity ==
|
|
86
|
+
validator.arity == 2 ? instance_exec(value, name, &validator) : instance_exec(value, &validator)
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
end
|
|
@@ -17,10 +17,10 @@ module Julewire
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
19
|
def update_subscription(configuration)
|
|
20
|
-
@subscription
|
|
20
|
+
@subscription.update(configuration)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def store_subscription(subscriber, unsubscribe:
|
|
23
|
+
def store_subscription(subscriber, unsubscribe:)
|
|
24
24
|
@subscription = Subscription.new(subscriber, unsubscribe: unsubscribe)
|
|
25
25
|
subscriber
|
|
26
26
|
end
|
|
@@ -7,7 +7,8 @@ module Julewire
|
|
|
7
7
|
class Subscription
|
|
8
8
|
attr_reader :subscriber
|
|
9
9
|
|
|
10
|
-
def initialize(subscriber, unsubscribe:
|
|
10
|
+
def initialize(subscriber, unsubscribe:)
|
|
11
|
+
Validation.validate_callable!(unsubscribe, name: :unsubscribe)
|
|
11
12
|
@subscriber = subscriber
|
|
12
13
|
@unsubscribe = unsubscribe
|
|
13
14
|
end
|
|
@@ -18,7 +19,7 @@ module Julewire
|
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def reset
|
|
21
|
-
@unsubscribe
|
|
22
|
+
@unsubscribe.call
|
|
22
23
|
nil
|
|
23
24
|
rescue StandardError
|
|
24
25
|
nil
|
|
@@ -59,8 +59,6 @@ module Julewire
|
|
|
59
59
|
def path_value(object, path, default: nil)
|
|
60
60
|
current = object
|
|
61
61
|
Array(path).each do |key|
|
|
62
|
-
return default if current.nil?
|
|
63
|
-
|
|
64
62
|
current = indexed_value(current, key)
|
|
65
63
|
return default if current.equal?(MISSING)
|
|
66
64
|
end
|
|
@@ -68,11 +66,6 @@ module Julewire
|
|
|
68
66
|
end
|
|
69
67
|
|
|
70
68
|
def first_value(source, keys:)
|
|
71
|
-
if source.is_a?(Hash)
|
|
72
|
-
found = direct_hash_first_value(source, keys)
|
|
73
|
-
return found unless found.equal?(MISSING)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
69
|
keys.each do |key|
|
|
77
70
|
found = indexed_value(source, key)
|
|
78
71
|
return found unless found.equal?(MISSING) || blank_value?(found)
|
|
@@ -82,16 +75,6 @@ module Julewire
|
|
|
82
75
|
|
|
83
76
|
private
|
|
84
77
|
|
|
85
|
-
def direct_hash_first_value(source, keys)
|
|
86
|
-
keys.each do |key|
|
|
87
|
-
next unless source.key?(key)
|
|
88
|
-
|
|
89
|
-
found = source[key]
|
|
90
|
-
return found unless blank_value?(found)
|
|
91
|
-
end
|
|
92
|
-
MISSING
|
|
93
|
-
end
|
|
94
|
-
|
|
95
78
|
def indexed_value(source, key)
|
|
96
79
|
return hash_value(source, key, default: MISSING) if source.is_a?(Hash)
|
|
97
80
|
return MISSING unless source.respond_to?(:[])
|
|
@@ -15,15 +15,12 @@ module Julewire
|
|
|
15
15
|
private_constant :RUNTIME_KEY, :CONTEXT_STORE_THREAD_KEY, :CONTEXT_STORE_FIBER_IVAR
|
|
16
16
|
|
|
17
17
|
@runtime_ref = Concurrent::AtomicReference.new
|
|
18
|
-
@runtime_mutex = Mutex.new
|
|
19
18
|
|
|
20
19
|
class << self
|
|
21
20
|
def runtime
|
|
22
21
|
return ractor_runtime if ractor_local_storage?
|
|
23
22
|
|
|
24
|
-
runtime_ref.
|
|
25
|
-
runtime_ref.get || Runtime.new.tap { runtime_ref.set(it) }
|
|
26
|
-
end
|
|
23
|
+
runtime_ref.update { it || Runtime.new }
|
|
27
24
|
end
|
|
28
25
|
|
|
29
26
|
def runtime=(runtime)
|
|
@@ -42,22 +39,9 @@ module Julewire
|
|
|
42
39
|
store_context(nil)
|
|
43
40
|
end
|
|
44
41
|
|
|
45
|
-
def after_fork!
|
|
46
|
-
runtime = runtime_ref.get
|
|
47
|
-
@runtime_mutex = Mutex.new
|
|
48
|
-
@runtime_ref = Concurrent::AtomicReference.new(runtime)
|
|
49
|
-
nil
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Private testing seam for storage-selection behavior.
|
|
53
|
-
def main_ractor?
|
|
54
|
-
::Ractor.main?
|
|
55
|
-
end
|
|
56
|
-
private :main_ractor?
|
|
57
|
-
|
|
58
42
|
private
|
|
59
43
|
|
|
60
|
-
attr_reader :
|
|
44
|
+
attr_reader :runtime_ref
|
|
61
45
|
|
|
62
46
|
def ractor_runtime
|
|
63
47
|
::Ractor.store_if_absent(RUNTIME_KEY) { Runtime.new }
|
|
@@ -83,7 +67,7 @@ module Julewire
|
|
|
83
67
|
end
|
|
84
68
|
|
|
85
69
|
def ractor_local_storage?
|
|
86
|
-
|
|
70
|
+
!::Ractor.main?
|
|
87
71
|
end
|
|
88
72
|
end
|
|
89
73
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Processing
|
|
6
|
+
module InvalidResultFailure
|
|
7
|
+
class << self
|
|
8
|
+
def build(message:, phase:, processor_name:, record_metadata:, result:)
|
|
9
|
+
[
|
|
10
|
+
ArgumentError.new(message),
|
|
11
|
+
{
|
|
12
|
+
phase: phase,
|
|
13
|
+
processor: processor_name,
|
|
14
|
+
record_metadata: record_metadata,
|
|
15
|
+
result_class: result.class.name
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -4,7 +4,6 @@ module Julewire
|
|
|
4
4
|
module Core
|
|
5
5
|
module Processing
|
|
6
6
|
class LevelThreshold
|
|
7
|
-
DEFAULT_EVENT = "log"
|
|
8
7
|
DEFAULT_SEVERITY = :info
|
|
9
8
|
|
|
10
9
|
attr_reader :level
|
|
@@ -20,32 +19,26 @@ module Julewire
|
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def raw_input_allowed?(input)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
severity, invalid, invalid_raw_value = raw_input_severity(input)
|
|
22
|
+
severity, invalid_raw_value = raw_input_severity(input)
|
|
26
23
|
allowed = allow?(severity)
|
|
27
24
|
# Surviving inputs warn later at Records::Draft normalization.
|
|
28
|
-
record_invalid_raw_severity(
|
|
25
|
+
record_invalid_raw_severity(invalid_raw_value) unless invalid_raw_value.equal?(MISSING) || allowed
|
|
29
26
|
allowed
|
|
30
27
|
end
|
|
31
28
|
|
|
32
29
|
private
|
|
33
30
|
|
|
34
31
|
def raw_input_severity(input)
|
|
35
|
-
return [DEFAULT_SEVERITY,
|
|
32
|
+
return [DEFAULT_SEVERITY, MISSING] unless Records::RawInput.explicit_severity?(input)
|
|
36
33
|
|
|
37
34
|
raw_value = Records::RawInput.value(input, :severity)
|
|
38
|
-
[Records::Severity.normalize(raw_value),
|
|
35
|
+
[Records::Severity.normalize(raw_value), MISSING]
|
|
39
36
|
rescue ArgumentError
|
|
40
|
-
[DEFAULT_SEVERITY,
|
|
37
|
+
[DEFAULT_SEVERITY, raw_value]
|
|
41
38
|
end
|
|
42
39
|
|
|
43
|
-
def record_invalid_raw_severity(
|
|
44
|
-
@invalid_severity_reporter.call(
|
|
45
|
-
raw_value,
|
|
46
|
-
source: Records::RawInput.value(input, :source),
|
|
47
|
-
event: Records::RawInput.value(input, :event) || DEFAULT_EVENT
|
|
48
|
-
)
|
|
40
|
+
def record_invalid_raw_severity(raw_value)
|
|
41
|
+
@invalid_severity_reporter.call(raw_value)
|
|
49
42
|
end
|
|
50
43
|
end
|
|
51
44
|
end
|
|
@@ -17,7 +17,7 @@ module Julewire
|
|
|
17
17
|
raise ArgumentError, "match handler is required" unless handler
|
|
18
18
|
|
|
19
19
|
conditions = normalize_conditions(conditions, keyword_conditions)
|
|
20
|
-
@rules << Rule.new(conditions
|
|
20
|
+
@rules << Rule.new(conditions, handler)
|
|
21
21
|
self
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -46,7 +46,9 @@ module Julewire
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def matches_conditions?(draft, conditions)
|
|
49
|
-
conditions.all?
|
|
49
|
+
conditions.all? do |key, pattern|
|
|
50
|
+
draft.key?(key) && matches_value?(pattern, draft.fetch(key))
|
|
51
|
+
end
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def matches_value?(pattern, value)
|
|
@@ -64,8 +66,8 @@ module Julewire
|
|
|
64
66
|
return false unless value.is_a?(Hash)
|
|
65
67
|
|
|
66
68
|
pattern.all? do |key, nested_pattern|
|
|
67
|
-
nested_value = Fields::FieldSet.value_for(value, key, default:
|
|
68
|
-
!nested_value.equal?(
|
|
69
|
+
nested_value = Fields::FieldSet.value_for(value, key, default: UNSET)
|
|
70
|
+
!nested_value.equal?(UNSET) && matches_value?(nested_pattern, nested_value)
|
|
69
71
|
end
|
|
70
72
|
end
|
|
71
73
|
end
|