julewire-core 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/docs/configuration.md +14 -7
- data/docs/context-and-propagation.md +20 -0
- data/docs/contracts.md +23 -49
- data/docs/extensions-and-api.md +78 -82
- data/docs/health-schema.md +12 -2
- data/docs/internals.md +21 -20
- data/docs/outputs-and-lifecycle.md +10 -6
- data/docs/records-and-data-policy.md +36 -5
- 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.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 +51 -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 +13 -63
- 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 +14 -13
- 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 +16 -9
- data/lib/julewire/core/diagnostics/failure_snapshot.rb +6 -2
- 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 +12 -17
- data/lib/julewire/core/execution/lineage.rb +16 -56
- data/lib/julewire/core/execution/measurement_handle.rb +6 -10
- data/lib/julewire/core/execution/scope.rb +15 -20
- data/lib/julewire/core/execution/scope_fields.rb +3 -12
- 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 +29 -19
- data/lib/julewire/core/fields/field_stack.rb +68 -134
- data/lib/julewire/core/fields/internal/deletion.rb +6 -9
- data/lib/julewire/core/fields/internal.rb +19 -38
- 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 +7 -12
- 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 +17 -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 +14 -14
- data/lib/julewire/core/propagation.rb +15 -2
- 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 +125 -262
- 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 +19 -37
- data/lib/julewire/core/records/severity.rb +7 -15
- data/lib/julewire/core/runtime.rb +67 -71
- 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 +2 -12
- data/lib/julewire/core/serialization/bounded_traversal.rb +49 -66
- 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 +23 -50
- 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 +63 -48
- data/lib/julewire/core/serialization/value_copy.rb +60 -227
- 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 +6 -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
|
@@ -8,25 +8,21 @@ module Julewire
|
|
|
8
8
|
def value(source, key)
|
|
9
9
|
return unless source.respond_to?(:[])
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
return direct unless direct.nil?
|
|
13
|
-
|
|
14
|
-
alternate_key(source, key)
|
|
11
|
+
source[key]
|
|
15
12
|
rescue StandardError
|
|
16
13
|
nil
|
|
17
14
|
end
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
# Decoded wire records have String keys, while in-process records use
|
|
17
|
+
# Symbols. Keep this conversion at presentation boundaries instead of
|
|
18
|
+
# making ordinary core lookups tolerant.
|
|
19
|
+
def wire_value(source, key)
|
|
20
|
+
result = value(source, key)
|
|
21
|
+
result.nil? ? value(source, key.to_s) : result
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def alternate_key(source, key)
|
|
26
|
-
case key
|
|
27
|
-
when Symbol then source[key.name]
|
|
28
|
-
when String then source[key.to_sym]
|
|
29
|
-
end
|
|
24
|
+
def blank?(value)
|
|
25
|
+
value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
30
26
|
end
|
|
31
27
|
end
|
|
32
28
|
end
|
|
@@ -34,7 +34,7 @@ module Julewire
|
|
|
34
34
|
|
|
35
35
|
def to_h = section_hash
|
|
36
36
|
|
|
37
|
-
def [](key) =
|
|
37
|
+
def [](key) = call_store(:value, key, default: nil)
|
|
38
38
|
|
|
39
39
|
private
|
|
40
40
|
|
|
@@ -51,10 +51,6 @@ module Julewire
|
|
|
51
51
|
yield coerce_fields(fields, keyword_fields)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def nil_if_missing(value)
|
|
55
|
-
value.equal?(MISSING) ? nil : value
|
|
56
|
-
end
|
|
57
|
-
|
|
58
54
|
def add_section(fields)
|
|
59
55
|
call_store(:add, fields)
|
|
60
56
|
end
|
|
@@ -67,10 +63,6 @@ module Julewire
|
|
|
67
63
|
call_store(:hash)
|
|
68
64
|
end
|
|
69
65
|
|
|
70
|
-
def section_value(key, default:)
|
|
71
|
-
call_store(:value, key, default: default)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
66
|
def call_store(action, ...)
|
|
75
67
|
@store.public_send(store_method(action), ...)
|
|
76
68
|
end
|
|
@@ -4,13 +4,12 @@ module Julewire
|
|
|
4
4
|
module Core
|
|
5
5
|
module Fields
|
|
6
6
|
class StackSet
|
|
7
|
-
EMPTY_HASH = {}.freeze
|
|
8
|
-
private_constant :EMPTY_HASH
|
|
9
|
-
|
|
10
7
|
class << self
|
|
11
|
-
def inherit_from(source, inherit_attributes:
|
|
12
|
-
stacks = Bags.stack_sections.
|
|
13
|
-
|
|
8
|
+
def inherit_from(source, inherit_attributes:)
|
|
9
|
+
stacks = Bags.stack_sections.each_with_object({}) do |section, inherited|
|
|
10
|
+
next unless inherit_section?(section, inherit_attributes)
|
|
11
|
+
|
|
12
|
+
inherited[section] = source.stack(section).branch
|
|
14
13
|
end
|
|
15
14
|
new(**stacks)
|
|
16
15
|
end
|
|
@@ -20,16 +19,12 @@ module Julewire
|
|
|
20
19
|
def inherit_section?(section, inherit_attributes)
|
|
21
20
|
inherit_attributes || !%i[attributes neutral].include?(section)
|
|
22
21
|
end
|
|
23
|
-
|
|
24
|
-
def inherited_stack(source, section, inherit)
|
|
25
|
-
inherit ? source.stack(section).fork : FieldStack.new
|
|
26
|
-
end
|
|
27
22
|
end
|
|
28
23
|
|
|
29
24
|
def initialize(**sections)
|
|
30
25
|
@stacks = Bags.stack_sections.to_h do |section|
|
|
31
|
-
[section, field_stack(sections.fetch(section,
|
|
32
|
-
end
|
|
26
|
+
[section, field_stack(sections.fetch(section, nil), section)]
|
|
27
|
+
end
|
|
33
28
|
end
|
|
34
29
|
|
|
35
30
|
def stack(section)
|
|
@@ -28,7 +28,7 @@ module Julewire
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def reset!
|
|
31
|
-
@config =
|
|
31
|
+
@config = nil
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
private
|
|
@@ -38,9 +38,10 @@ module Julewire
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def validate_config!(configuration)
|
|
41
|
-
|
|
41
|
+
klass = configuration_class
|
|
42
|
+
return if configuration.is_a?(klass)
|
|
42
43
|
|
|
43
|
-
raise TypeError, "expected #{
|
|
44
|
+
raise TypeError, "expected #{klass}"
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
def configuration_class
|
|
@@ -10,7 +10,6 @@ module Julewire
|
|
|
10
10
|
@state = Diagnostics::Health.new(
|
|
11
11
|
callback_failure_counter: callback_failure_counter,
|
|
12
12
|
counter_keys: counter_keys,
|
|
13
|
-
failure_counter: failure_counter,
|
|
14
13
|
track_failures: failure_counter == :failures
|
|
15
14
|
)
|
|
16
15
|
end
|
|
@@ -20,20 +19,31 @@ module Julewire
|
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def record_failure(error, counter: @failure_counter, **metadata)
|
|
23
|
-
@state.record_failure(error, counter: counter,
|
|
22
|
+
@state.record_failure(error, counter: counter, **metadata)
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def record_loss(reason:, counter: reason, **metadata)
|
|
27
|
-
@state.record_loss(reason: reason, counter: counter,
|
|
26
|
+
@state.record_loss(reason: reason, counter: counter, **metadata)
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
def record_callback_failure(callback_failure)
|
|
31
30
|
@state.record_callback_failure(callback_failure)
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
def
|
|
33
|
+
def degradation_marker = @state.degradation_marker
|
|
35
34
|
|
|
36
|
-
def
|
|
35
|
+
def clear_degradation_if_unchanged(marker) = @state.clear_degradation_if_unchanged(marker)
|
|
36
|
+
|
|
37
|
+
def recover_if_successful
|
|
38
|
+
marker = degradation_marker
|
|
39
|
+
result = yield
|
|
40
|
+
clear_degradation_if_unchanged(marker) unless result == false
|
|
41
|
+
result
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def clear_failures! = @state.clear_failures!
|
|
45
|
+
|
|
46
|
+
def degraded? = @state.degraded?
|
|
37
47
|
|
|
38
48
|
def last_callback_failure = @state.last_callback_failure
|
|
39
49
|
|
|
@@ -42,8 +52,8 @@ module Julewire
|
|
|
42
52
|
def last_failure = @state.last_failure
|
|
43
53
|
|
|
44
54
|
def snapshot(status: nil, **fields)
|
|
45
|
-
snapshot = @state.snapshot(status: status,
|
|
46
|
-
callback_failure =
|
|
55
|
+
snapshot = @state.snapshot(status: status, include_loss: true, **fields)
|
|
56
|
+
callback_failure = last_callback_failure
|
|
47
57
|
return snapshot unless callback_failure
|
|
48
58
|
|
|
49
59
|
snapshot.merge(last_callback_failure: callback_failure).freeze
|
|
@@ -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
|