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
|
@@ -12,15 +12,14 @@ module Julewire
|
|
|
12
12
|
|
|
13
13
|
class << self
|
|
14
14
|
def build( # rubocop:disable Metrics/ParameterLists -- Record construction has fixed public sections.
|
|
15
|
-
input =
|
|
15
|
+
input = nil,
|
|
16
16
|
context:,
|
|
17
17
|
scope:,
|
|
18
|
-
attributes:
|
|
19
|
-
neutral:
|
|
20
|
-
carry:
|
|
21
|
-
static_labels:
|
|
22
|
-
|
|
23
|
-
error_backtrace_lines: Core::MAX_BACKTRACE_LINES,
|
|
18
|
+
attributes: nil,
|
|
19
|
+
neutral: nil,
|
|
20
|
+
carry: nil,
|
|
21
|
+
static_labels: nil,
|
|
22
|
+
error_backtrace_lines: DEFAULT_ERROR_BACKTRACE_LINES,
|
|
24
23
|
invalid_severity_reporter: Diagnostics::InvalidSeverityReporter
|
|
25
24
|
)
|
|
26
25
|
build_with(
|
|
@@ -32,24 +31,21 @@ module Julewire
|
|
|
32
31
|
static_labels: static_labels,
|
|
33
32
|
scope: scope,
|
|
34
33
|
invalid_severity_reporter: invalid_severity_reporter,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
)
|
|
34
|
+
fields_owned: false,
|
|
35
|
+
input_owned: false,
|
|
36
|
+
error_backtrace_lines: error_backtrace_lines
|
|
39
37
|
)
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
def build_pipeline_owned( # rubocop:disable Metrics/ParameterLists -- Record construction has fixed public sections.
|
|
43
|
-
input
|
|
41
|
+
input,
|
|
44
42
|
context:,
|
|
45
43
|
scope:,
|
|
46
|
-
attributes:
|
|
47
|
-
neutral:
|
|
48
|
-
carry:
|
|
49
|
-
static_labels: {},
|
|
44
|
+
attributes: nil,
|
|
45
|
+
neutral: nil,
|
|
46
|
+
carry: nil,
|
|
50
47
|
input_owned: false,
|
|
51
|
-
|
|
52
|
-
error_backtrace_lines: Core::MAX_BACKTRACE_LINES,
|
|
48
|
+
error_backtrace_lines: DEFAULT_ERROR_BACKTRACE_LINES,
|
|
53
49
|
invalid_severity_reporter: Diagnostics::InvalidSeverityReporter
|
|
54
50
|
)
|
|
55
51
|
build_with(
|
|
@@ -58,21 +54,20 @@ module Julewire
|
|
|
58
54
|
neutral: neutral,
|
|
59
55
|
attributes: attributes,
|
|
60
56
|
carry: carry,
|
|
61
|
-
static_labels:
|
|
57
|
+
static_labels: nil,
|
|
62
58
|
scope: scope,
|
|
63
59
|
invalid_severity_reporter: invalid_severity_reporter,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
error_backtrace_lines: error_backtrace_lines
|
|
68
|
-
)
|
|
60
|
+
fields_owned: true,
|
|
61
|
+
input_owned: input_owned,
|
|
62
|
+
error_backtrace_lines: error_backtrace_lines
|
|
69
63
|
)
|
|
70
64
|
end
|
|
71
65
|
|
|
72
66
|
private
|
|
73
67
|
|
|
74
68
|
def build_with(input, context:, neutral:, attributes:, carry:, static_labels:, scope:, # rubocop:disable Metrics/ParameterLists
|
|
75
|
-
invalid_severity_reporter:,
|
|
69
|
+
invalid_severity_reporter:, fields_owned:, input_owned:,
|
|
70
|
+
error_backtrace_lines:)
|
|
76
71
|
builder = Builder.new(
|
|
77
72
|
input,
|
|
78
73
|
context: context,
|
|
@@ -82,94 +77,45 @@ module Julewire
|
|
|
82
77
|
static_labels: static_labels,
|
|
83
78
|
scope: scope,
|
|
84
79
|
invalid_severity_reporter: invalid_severity_reporter,
|
|
85
|
-
|
|
80
|
+
fields_owned: fields_owned,
|
|
81
|
+
input_owned: input_owned,
|
|
82
|
+
error_backtrace_lines: error_backtrace_lines
|
|
86
83
|
)
|
|
87
|
-
new(builder.to_h, lineage: builder.lineage
|
|
84
|
+
new(builder.to_h, lineage: builder.lineage)
|
|
88
85
|
end
|
|
89
86
|
|
|
90
87
|
public
|
|
91
88
|
|
|
92
|
-
def from_normalized_hash(data, lineage: nil
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
lineage: lineage,
|
|
100
|
-
freeze_sections: freeze_sections
|
|
101
|
-
)
|
|
89
|
+
def from_normalized_hash(data, lineage: nil)
|
|
90
|
+
Record.validate_normalized_hash!(data)
|
|
91
|
+
normalized = Fields::FieldSet.deep_dup_owned(data)
|
|
92
|
+
execution = normalized.fetch(:execution)
|
|
93
|
+
lineage ||= Execution::Lineage.from_execution_hash(execution)
|
|
94
|
+
normalized[:execution] = Execution::Lineage.clean_normalized_lazy_relationship_hash(execution)
|
|
95
|
+
new(normalized, lineage: lineage)
|
|
102
96
|
end
|
|
103
97
|
|
|
104
|
-
def from_record(record
|
|
98
|
+
def from_record(record)
|
|
105
99
|
Record.validate_normalized!(record)
|
|
106
|
-
from_normalized_hash(record.to_h, lineage: record.lineage
|
|
100
|
+
from_normalized_hash(record.to_h, lineage: record.lineage)
|
|
107
101
|
end
|
|
108
102
|
end
|
|
103
|
+
private_class_method :new
|
|
109
104
|
|
|
105
|
+
DEFAULT_ERROR_BACKTRACE_LINES = Core::MAX_BACKTRACE_LINES
|
|
110
106
|
LINEAGE_IDENTITY_KEYS = %i[type id depth root parent].freeze
|
|
111
|
-
private_constant :LINEAGE_IDENTITY_KEYS
|
|
112
|
-
|
|
113
|
-
BuildOptions = Data.define(:fields_owned, :input_owned, :freeze_sections, :error_backtrace_lines) do
|
|
114
|
-
class << self
|
|
115
|
-
def defensive(freeze_sections:, error_backtrace_lines:)
|
|
116
|
-
return default_defensive.fetch(freeze_sections) if default_backtrace_lines?(error_backtrace_lines)
|
|
117
|
-
|
|
118
|
-
new(false, false, freeze_sections, error_backtrace_lines)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def pipeline_owned(input_owned:, freeze_sections:, error_backtrace_lines:)
|
|
122
|
-
if default_backtrace_lines?(error_backtrace_lines)
|
|
123
|
-
return default_pipeline.fetch(input_owned).fetch(freeze_sections)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
new(true, input_owned, freeze_sections, error_backtrace_lines)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
private
|
|
130
|
-
|
|
131
|
-
def default_backtrace_lines?(value)
|
|
132
|
-
value == Core::MAX_BACKTRACE_LINES
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def default_defensive
|
|
136
|
-
# Hot-path defaults are reused by every emitted record.
|
|
137
|
-
@default_defensive ||= {
|
|
138
|
-
false => new(false, false, false, Core::MAX_BACKTRACE_LINES),
|
|
139
|
-
true => new(false, false, true, Core::MAX_BACKTRACE_LINES)
|
|
140
|
-
}.freeze
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def default_pipeline
|
|
144
|
-
@default_pipeline ||= {
|
|
145
|
-
false => {
|
|
146
|
-
false => new(true, false, false, Core::MAX_BACKTRACE_LINES),
|
|
147
|
-
true => new(true, false, true, Core::MAX_BACKTRACE_LINES)
|
|
148
|
-
}.freeze,
|
|
149
|
-
true => {
|
|
150
|
-
false => new(true, true, false, Core::MAX_BACKTRACE_LINES),
|
|
151
|
-
true => new(true, true, true, Core::MAX_BACKTRACE_LINES)
|
|
152
|
-
}.freeze
|
|
153
|
-
}.freeze
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
private_constant :BuildOptions
|
|
107
|
+
private_constant :DEFAULT_ERROR_BACKTRACE_LINES, :LINEAGE_IDENTITY_KEYS
|
|
158
108
|
|
|
159
|
-
def initialize(data, lineage:
|
|
109
|
+
def initialize(data, lineage:)
|
|
160
110
|
@data = data
|
|
161
|
-
@
|
|
162
|
-
@lineage = lineage || Execution::Lineage.from_execution_hash(@data[:execution])
|
|
163
|
-
validate!
|
|
111
|
+
@lineage = lineage
|
|
164
112
|
end
|
|
165
113
|
|
|
166
114
|
def [](key) = @data[key]
|
|
167
115
|
|
|
168
116
|
def []=(key, value)
|
|
169
|
-
@lineage = nil if key == :execution
|
|
170
|
-
ensure_mutable_data!
|
|
171
117
|
@data[key] = value
|
|
172
|
-
@
|
|
118
|
+
@lineage = nil if key == :execution
|
|
173
119
|
end
|
|
174
120
|
|
|
175
121
|
def fetch(...) = @data.fetch(...)
|
|
@@ -182,17 +128,19 @@ module Julewire
|
|
|
182
128
|
|
|
183
129
|
def each_key(&) = @data.each_key(&)
|
|
184
130
|
|
|
185
|
-
def to_h = Fields::FieldSet.
|
|
131
|
+
def to_h = Fields::FieldSet.deep_dup_owned(@data)
|
|
186
132
|
|
|
187
133
|
def transform_field!(key)
|
|
188
|
-
|
|
189
|
-
|
|
134
|
+
ensure_unfinalized!
|
|
135
|
+
validate_transform_key!(key, Record::REQUIRED_KEYS, kind: :field)
|
|
136
|
+
replace_transformed_field!(key, yield(self[key]))
|
|
190
137
|
self
|
|
191
138
|
end
|
|
192
139
|
|
|
193
140
|
def transform_section!(key)
|
|
194
|
-
|
|
195
|
-
|
|
141
|
+
ensure_unfinalized!
|
|
142
|
+
validate_transform_key!(key, Record::HASH_SECTIONS, kind: :section)
|
|
143
|
+
section = self[key]
|
|
196
144
|
replacement = yield(section)
|
|
197
145
|
raise TypeError, "record #{key} must be a Hash" unless replacement.is_a?(Hash)
|
|
198
146
|
|
|
@@ -201,12 +149,12 @@ module Julewire
|
|
|
201
149
|
end
|
|
202
150
|
|
|
203
151
|
def transform_record!
|
|
152
|
+
ensure_unfinalized!
|
|
204
153
|
previous_lineage = @lineage
|
|
205
|
-
previous_identity = execution_lineage_identity(
|
|
154
|
+
previous_identity = execution_lineage_identity(fetch(:execution))
|
|
206
155
|
replacement = yield(@data)
|
|
207
156
|
@lineage = replacement_lineage_for(previous_lineage, previous_identity, replacement)
|
|
208
|
-
@data = replacement
|
|
209
|
-
@to_record = nil
|
|
157
|
+
@data = replacement.dup
|
|
210
158
|
self
|
|
211
159
|
end
|
|
212
160
|
|
|
@@ -219,123 +167,86 @@ module Julewire
|
|
|
219
167
|
self
|
|
220
168
|
end
|
|
221
169
|
|
|
222
|
-
def lineage = (@lineage ||= Execution::Lineage.from_execution_hash(
|
|
170
|
+
def lineage = (@lineage ||= Execution::Lineage.from_execution_hash(fetch(:execution)))
|
|
223
171
|
|
|
224
172
|
def to_record
|
|
225
|
-
@to_record
|
|
173
|
+
return @to_record if @to_record
|
|
174
|
+
|
|
175
|
+
record = Record.from_owned_hash(@data, lineage: @lineage)
|
|
176
|
+
@lineage = record.lineage
|
|
177
|
+
@to_record = record
|
|
178
|
+
freeze
|
|
179
|
+
record
|
|
226
180
|
end
|
|
227
181
|
|
|
228
182
|
private
|
|
229
183
|
|
|
184
|
+
def validate_transform_key!(key, allowed, kind:)
|
|
185
|
+
raise TypeError, "record transform #{kind} must be a Symbol" unless key.instance_of?(Symbol)
|
|
186
|
+
return if allowed.include?(key)
|
|
187
|
+
|
|
188
|
+
raise ArgumentError, "unknown record #{kind}: #{key}"
|
|
189
|
+
end
|
|
190
|
+
|
|
230
191
|
def replace_transformed_field!(key, value)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
192
|
+
if key == :execution
|
|
193
|
+
replace_transformed_execution!(value)
|
|
194
|
+
else
|
|
195
|
+
self[key] = value
|
|
196
|
+
end
|
|
236
197
|
end
|
|
237
198
|
|
|
238
|
-
def
|
|
239
|
-
|
|
199
|
+
def replace_transformed_execution!(value)
|
|
200
|
+
preserve_lineage = transformed_execution_lineage(value)
|
|
201
|
+
self[:execution] = value
|
|
202
|
+
@lineage = preserve_lineage
|
|
240
203
|
end
|
|
241
204
|
|
|
242
|
-
def
|
|
243
|
-
|
|
205
|
+
def ensure_unfinalized!
|
|
206
|
+
raise FrozenError, "can't transform a finalized record draft" if frozen?
|
|
207
|
+
end
|
|
244
208
|
|
|
209
|
+
def transformed_execution_lineage(value)
|
|
245
210
|
replacement_lineage_for(
|
|
246
211
|
@lineage,
|
|
247
|
-
execution_lineage_identity(
|
|
212
|
+
execution_lineage_identity(fetch(:execution)),
|
|
248
213
|
@data.merge(execution: value)
|
|
249
214
|
)
|
|
250
215
|
end
|
|
251
216
|
|
|
252
217
|
def replacement_lineage_for(lineage, previous, data)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
current = data.is_a?(Hash) ? execution_lineage_identity(data[:execution]) : nil
|
|
218
|
+
current = execution_lineage_identity(data[:execution]) if data.is_a?(Hash)
|
|
256
219
|
lineage if previous == current
|
|
257
220
|
end
|
|
258
221
|
|
|
259
222
|
def execution_lineage_identity(execution)
|
|
260
223
|
return unless execution.is_a?(Hash)
|
|
261
224
|
|
|
262
|
-
normalized = Fields::FieldSet.deep_symbolize_keys(execution)
|
|
263
225
|
LINEAGE_IDENTITY_KEYS.each_with_object({}) do |key, identity|
|
|
264
|
-
identity[key] =
|
|
265
|
-
end
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
class BuildInput
|
|
269
|
-
# Normalizes raw emit input into draft top-level fields plus payload.
|
|
270
|
-
RECORD_INPUT_KEYS = Record::REQUIRED_KEYS.freeze
|
|
271
|
-
RECORD_INPUT_KEY_SET = RECORD_INPUT_KEYS.to_h { [it, true] }.freeze
|
|
272
|
-
private_constant :RECORD_INPUT_KEYS
|
|
273
|
-
private_constant :RECORD_INPUT_KEY_SET
|
|
274
|
-
|
|
275
|
-
class << self
|
|
276
|
-
def call(input, owned:)
|
|
277
|
-
return {} if input.nil?
|
|
278
|
-
return input if owned && input.is_a?(Hash)
|
|
279
|
-
return shallow_symbolize(input) if RawInput.hash_input?(input)
|
|
280
|
-
|
|
281
|
-
{ message: input.to_s }
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
private
|
|
285
|
-
|
|
286
|
-
def shallow_symbolize(input)
|
|
287
|
-
normalized = {}
|
|
288
|
-
payload_fields = {}
|
|
289
|
-
input.each do |key, raw_value|
|
|
290
|
-
normalized_key = Fields::Internal.normalize_key(key)
|
|
291
|
-
value = raw_value.equal?(input) ? CIRCULAR_REFERENCE : raw_value
|
|
292
|
-
if RECORD_INPUT_KEY_SET.key?(normalized_key)
|
|
293
|
-
normalized[normalized_key] = value
|
|
294
|
-
else
|
|
295
|
-
payload_fields[normalized_key] = value
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
merge_unknown_payload!(normalized, payload_fields)
|
|
299
|
-
normalized
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
def merge_unknown_payload!(normalized, payload_fields)
|
|
303
|
-
return if payload_fields.empty?
|
|
304
|
-
|
|
305
|
-
normalized[:payload] = if normalized.key?(:payload)
|
|
306
|
-
merge_payload_input(normalized[:payload], payload_fields)
|
|
307
|
-
else
|
|
308
|
-
payload_fields
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
def merge_payload_input(explicit_payload, unknown_payload)
|
|
313
|
-
if explicit_payload.is_a?(Hash)
|
|
314
|
-
Fields::FieldSet.merge(unknown_payload, explicit_payload)
|
|
315
|
-
else
|
|
316
|
-
Fields::FieldSet.merge(unknown_payload, Fields::FieldSet::VALUE_KEY => explicit_payload)
|
|
317
|
-
end
|
|
318
|
-
end
|
|
226
|
+
identity[key] = execution.fetch(key) if execution.key?(key)
|
|
319
227
|
end
|
|
320
228
|
end
|
|
321
|
-
private_constant :BuildInput
|
|
322
229
|
|
|
323
230
|
class Builder
|
|
324
231
|
EMPTY_HASH = {}.freeze
|
|
325
232
|
private_constant :EMPTY_HASH
|
|
326
233
|
|
|
327
|
-
def initialize(input
|
|
328
|
-
invalid_severity_reporter:,
|
|
329
|
-
|
|
330
|
-
@
|
|
234
|
+
def initialize(input, context:, neutral:, attributes:, carry:, static_labels:, scope:, # rubocop:disable Metrics/ParameterLists
|
|
235
|
+
invalid_severity_reporter:, fields_owned:, input_owned:,
|
|
236
|
+
error_backtrace_lines:)
|
|
237
|
+
@input_owned = input_owned
|
|
238
|
+
@input = if @input_owned
|
|
239
|
+
BuildInput.validate_owned(input)
|
|
240
|
+
else
|
|
241
|
+
BuildInput.normalize_public(input)
|
|
242
|
+
end
|
|
331
243
|
@context = context || {}
|
|
332
244
|
@neutral = neutral || {}
|
|
333
245
|
@attributes = attributes || {}
|
|
334
246
|
@carry = carry || {}
|
|
335
247
|
@static_labels = static_labels || {}
|
|
336
|
-
@fields_owned =
|
|
337
|
-
@
|
|
338
|
-
@error_backtrace_lines = options.error_backtrace_lines
|
|
248
|
+
@fields_owned = fields_owned
|
|
249
|
+
@error_backtrace_lines = error_backtrace_lines
|
|
339
250
|
@invalid_severity_reporter = invalid_severity_reporter
|
|
340
251
|
@scope = scope
|
|
341
252
|
end
|
|
@@ -356,7 +267,7 @@ module Julewire
|
|
|
356
267
|
def base_record(source, event)
|
|
357
268
|
{
|
|
358
269
|
timestamp: timestamp_value,
|
|
359
|
-
severity:
|
|
270
|
+
severity: severity_value,
|
|
360
271
|
kind: kind_for(value(:kind)),
|
|
361
272
|
event: event,
|
|
362
273
|
message: normalized_value(:message),
|
|
@@ -384,23 +295,22 @@ module Julewire
|
|
|
384
295
|
Serialization::ValueCopy.call(raw_value.nil? ? Time.now.utc : raw_value, freeze_values: true)
|
|
385
296
|
end
|
|
386
297
|
|
|
387
|
-
def
|
|
388
|
-
return normalize_record_severity(value(:severity)
|
|
298
|
+
def severity_value
|
|
299
|
+
return normalize_record_severity(value(:severity)) if present?(:severity)
|
|
389
300
|
|
|
390
301
|
:info
|
|
391
302
|
end
|
|
392
303
|
|
|
393
|
-
def normalize_record_severity(raw_value
|
|
394
|
-
|
|
304
|
+
def normalize_record_severity(raw_value)
|
|
305
|
+
Severity.normalize(raw_value)
|
|
395
306
|
rescue ArgumentError
|
|
396
307
|
# Below-threshold raw inputs warn before draft construction.
|
|
397
|
-
@invalid_severity_reporter.call(raw_value
|
|
308
|
+
@invalid_severity_reporter.call(raw_value)
|
|
398
309
|
:info
|
|
399
310
|
end
|
|
400
311
|
|
|
401
312
|
def kind_for(kind)
|
|
402
313
|
return :point if kind.nil?
|
|
403
|
-
return kind if Record::KINDS.value?(kind)
|
|
404
314
|
|
|
405
315
|
Record::KINDS.fetch(kind.to_s) do
|
|
406
316
|
raise ArgumentError, "unsupported record kind: #{kind.inspect}"
|
|
@@ -414,13 +324,11 @@ module Julewire
|
|
|
414
324
|
end
|
|
415
325
|
|
|
416
326
|
def base_execution_hash
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
normalized_hash(scope_execution_hash)
|
|
327
|
+
normalized_hash(scope_execution_hash, owned: true)
|
|
420
328
|
end
|
|
421
329
|
|
|
422
330
|
def input_execution_hash
|
|
423
|
-
|
|
331
|
+
hash_value(:execution)
|
|
424
332
|
end
|
|
425
333
|
|
|
426
334
|
def context_hash
|
|
@@ -440,73 +348,34 @@ module Julewire
|
|
|
440
348
|
end
|
|
441
349
|
|
|
442
350
|
def labels_hash
|
|
443
|
-
section_hash(
|
|
351
|
+
section_hash(@static_labels.merge(scope_labels_hash || EMPTY_HASH), :labels)
|
|
444
352
|
end
|
|
445
353
|
|
|
446
354
|
def merge_section(base, key)
|
|
447
|
-
return merge_owned_section(base, key) if @input_owned
|
|
448
|
-
|
|
449
|
-
value = hash_value(key)
|
|
450
|
-
value = Execution::Lineage.clean_execution_hash(value) if key == :execution
|
|
451
|
-
return normalized_hash(value) if base.empty?
|
|
452
|
-
|
|
453
|
-
base = Fields::FieldSet.deep_dup(base)
|
|
454
|
-
merged = if key == :attributes
|
|
455
|
-
Fields::Internal.deep_merge!(base, value)
|
|
456
|
-
else
|
|
457
|
-
Fields::FieldSet.merge!(base, value)
|
|
458
|
-
end
|
|
459
|
-
normalized_hash(merged)
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
def merge_owned_section(base, key)
|
|
463
355
|
value = hash_value(key)
|
|
464
356
|
value = clean_owned_execution_hash(value) if key == :execution
|
|
465
|
-
return normalized_hash(value) if base.empty?
|
|
466
357
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
normalized_hash(merged)
|
|
358
|
+
target = normalized_hash(base, owned: @fields_owned)
|
|
359
|
+
if key == :attributes
|
|
360
|
+
Fields::Internal.deep_merge_owned!(target, value)
|
|
361
|
+
else
|
|
362
|
+
Fields::Internal.merge_owned!(target, value)
|
|
363
|
+
end
|
|
474
364
|
end
|
|
475
365
|
|
|
476
366
|
def clean_owned_execution_hash(value)
|
|
477
|
-
return Execution::Lineage.clean_execution_hash(value) if @freeze_sections
|
|
478
|
-
|
|
479
367
|
Execution::Lineage.clean_owned_execution_hash(value)
|
|
480
368
|
end
|
|
481
369
|
|
|
482
|
-
def section_hash(base, key)
|
|
483
|
-
return base if owned_frozen_section?(base) && !present?(key)
|
|
484
|
-
return normalized_hash(base) unless present?(key)
|
|
485
|
-
|
|
486
|
-
merge_section(base, key)
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
def owned_frozen_section?(base)
|
|
490
|
-
@fields_owned && @freeze_sections && base.is_a?(Hash) && base.frozen?
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
def owned_frozen_scope_execution?
|
|
494
|
-
@scope && @fields_owned && @freeze_sections
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
def labels_base
|
|
498
|
-
return scope_labels_hash if @static_labels.empty?
|
|
499
|
-
|
|
500
|
-
Fields::FieldSet.merge!(Fields::FieldSet.deep_dup(@static_labels), scope_labels_hash)
|
|
501
|
-
end
|
|
370
|
+
def section_hash(base, key) = merge_section(base, key)
|
|
502
371
|
|
|
503
372
|
def hash_value(key)
|
|
504
|
-
return
|
|
373
|
+
return {} unless present?(key)
|
|
505
374
|
|
|
506
375
|
raw_value = value(key)
|
|
507
|
-
return
|
|
376
|
+
return normalized_input_hash(raw_value) if raw_value.is_a?(Hash)
|
|
508
377
|
|
|
509
|
-
|
|
378
|
+
normalized_input_hash(Fields::FieldSet::VALUE_KEY => raw_value)
|
|
510
379
|
end
|
|
511
380
|
|
|
512
381
|
def value(key)
|
|
@@ -519,11 +388,8 @@ module Julewire
|
|
|
519
388
|
|
|
520
389
|
def immutable_scalar_value(value)
|
|
521
390
|
return value unless value.is_a?(String)
|
|
522
|
-
return value if value.frozen?
|
|
523
|
-
return value.dup unless @freeze_sections
|
|
524
|
-
return value.freeze if @input_owned
|
|
525
391
|
|
|
526
|
-
value.dup
|
|
392
|
+
value.dup
|
|
527
393
|
end
|
|
528
394
|
|
|
529
395
|
def present?(key)
|
|
@@ -535,39 +401,42 @@ module Julewire
|
|
|
535
401
|
when nil
|
|
536
402
|
nil
|
|
537
403
|
when Exception
|
|
538
|
-
|
|
404
|
+
Serialization::ExceptionShape.call(error, max_backtrace_lines: @error_backtrace_lines)
|
|
539
405
|
when Hash
|
|
540
|
-
|
|
406
|
+
normalize_error_hash(error)
|
|
541
407
|
else
|
|
542
|
-
|
|
408
|
+
{ message: immutable_scalar_value(error.to_s) }
|
|
543
409
|
end
|
|
544
410
|
end
|
|
545
411
|
|
|
546
412
|
def normalize_error_hash(error)
|
|
547
413
|
Serialization::BacktraceLimiter.call(
|
|
548
|
-
|
|
414
|
+
mutable_input_hash(error),
|
|
549
415
|
max_backtrace_lines: @error_backtrace_lines
|
|
550
416
|
)
|
|
551
417
|
end
|
|
552
418
|
|
|
553
|
-
def
|
|
554
|
-
|
|
419
|
+
def normalized_input_hash(value)
|
|
420
|
+
normalized_hash(value, owned: @input_owned)
|
|
421
|
+
end
|
|
555
422
|
|
|
556
|
-
|
|
557
|
-
return Fields::
|
|
423
|
+
def normalized_hash(value, owned:)
|
|
424
|
+
return Fields::FieldSet.deep_dup_owned(value) if owned
|
|
558
425
|
|
|
559
426
|
Fields::FieldSet.deep_symbolize_keys(value)
|
|
560
427
|
end
|
|
561
428
|
|
|
562
|
-
def
|
|
563
|
-
@
|
|
429
|
+
def mutable_input_hash(value)
|
|
430
|
+
if @input_owned
|
|
431
|
+
Fields::FieldSet.deep_dup_owned(value)
|
|
432
|
+
else
|
|
433
|
+
Fields::FieldSet.deep_symbolize_keys(value)
|
|
434
|
+
end
|
|
564
435
|
end
|
|
565
436
|
|
|
566
437
|
def scope_execution_hash = @scope ? @scope.frozen_execution_hash : EMPTY_HASH
|
|
567
438
|
|
|
568
|
-
def
|
|
569
|
-
|
|
570
|
-
def scope_labels_hash = @scope ? @scope.frozen_labels_hash : EMPTY_HASH
|
|
439
|
+
def scope_labels_hash = @scope&.frozen_labels_hash
|
|
571
440
|
end
|
|
572
441
|
private_constant :Builder
|
|
573
442
|
end
|
|
@@ -24,7 +24,7 @@ module Julewire
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def each
|
|
27
|
-
return enum_for
|
|
27
|
+
return enum_for unless block_given?
|
|
28
28
|
|
|
29
29
|
input_hash.each do |key, value|
|
|
30
30
|
yield key, value unless severity_key?(key)
|
|
@@ -32,12 +32,6 @@ module Julewire
|
|
|
32
32
|
yield :severity, @severity
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def to_h
|
|
36
|
-
each_with_object({}) do |(key, value), hash|
|
|
37
|
-
hash[key] = value
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
35
|
private
|
|
42
36
|
|
|
43
37
|
def input_hash
|
|
@@ -66,9 +60,7 @@ module Julewire
|
|
|
66
60
|
SeverityInput.new(severity, input)
|
|
67
61
|
end
|
|
68
62
|
|
|
69
|
-
def input?(value)
|
|
70
|
-
value.is_a?(SeverityInput)
|
|
71
|
-
end
|
|
63
|
+
def input?(value) = value.instance_of?(SeverityInput)
|
|
72
64
|
|
|
73
65
|
private
|
|
74
66
|
|
|
@@ -88,8 +80,6 @@ module Julewire
|
|
|
88
80
|
end
|
|
89
81
|
|
|
90
82
|
def without_severity(input)
|
|
91
|
-
return input unless input.is_a?(Hash)
|
|
92
|
-
|
|
93
83
|
RawInput.without_severity_keys(input)
|
|
94
84
|
end
|
|
95
85
|
end
|
|
@@ -6,15 +6,16 @@ module Julewire
|
|
|
6
6
|
module Metadata
|
|
7
7
|
class << self
|
|
8
8
|
def call(record)
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
labels = record[:labels]
|
|
11
10
|
{
|
|
12
11
|
event: record[:event],
|
|
13
|
-
labels:
|
|
12
|
+
labels: labels.is_a?(Hash) ? Fields::FieldSet.deep_dup(labels) : {},
|
|
14
13
|
logger: record[:logger],
|
|
15
14
|
severity: record[:severity],
|
|
16
15
|
source: record[:source]
|
|
17
16
|
}.compact
|
|
17
|
+
rescue StandardError
|
|
18
|
+
{}
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
end
|