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
|
@@ -11,10 +11,8 @@ module Julewire
|
|
|
11
11
|
no_output_dropped
|
|
12
12
|
processor_dropped
|
|
13
13
|
processor_error
|
|
14
|
+
processor_invalid
|
|
14
15
|
].freeze
|
|
15
|
-
EMPTY_HASH = {}.freeze
|
|
16
|
-
private_constant :EMPTY_HASH
|
|
17
|
-
|
|
18
16
|
# @api integration_spi
|
|
19
17
|
# Integration-facing raw/normalized record pipeline.
|
|
20
18
|
def initialize(configuration:, invalid_severity_reporter: Diagnostics::InvalidSeverityReporter.counter)
|
|
@@ -32,11 +30,11 @@ module Julewire
|
|
|
32
30
|
initialize_tracking
|
|
33
31
|
end
|
|
34
32
|
|
|
35
|
-
def emit(input =
|
|
33
|
+
def emit(input = UNSET, **fields, &)
|
|
36
34
|
emit_with_level_check(input, true, fields, &)
|
|
37
35
|
end
|
|
38
36
|
|
|
39
|
-
def emit_without_level(input =
|
|
37
|
+
def emit_without_level(input = UNSET, **fields, &)
|
|
40
38
|
emit_with_level_check(input, false, fields, &)
|
|
41
39
|
end
|
|
42
40
|
|
|
@@ -50,7 +48,7 @@ module Julewire
|
|
|
50
48
|
# Runtime summaries already carry their captured scope fields.
|
|
51
49
|
def emit_isolated_input(input, enforce_level: true)
|
|
52
50
|
emit_input_with_guard(input, enforce_level: enforce_level, lazy: false) do
|
|
53
|
-
|
|
51
|
+
build_isolated_owned_draft(input)
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
54
|
|
|
@@ -109,7 +107,6 @@ module Julewire
|
|
|
109
107
|
{
|
|
110
108
|
encoder: Serialization::JsonEncoder.new(max_backtrace_lines: configuration.error_backtrace_lines),
|
|
111
109
|
formatter: Records::Formatter.new,
|
|
112
|
-
error_backtrace_lines: configuration.error_backtrace_lines,
|
|
113
110
|
on_drop: configuration.on_drop,
|
|
114
111
|
on_failure: configuration.on_failure
|
|
115
112
|
}
|
|
@@ -124,9 +121,10 @@ module Julewire
|
|
|
124
121
|
|
|
125
122
|
def build_processor_chain(configuration)
|
|
126
123
|
ProcessorChain.new(
|
|
127
|
-
processors: configuration.processors.to_a
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
processors: configuration.processors.to_a,
|
|
125
|
+
on_error: method(:record_processor_error),
|
|
126
|
+
on_invalid: method(:record_invalid_processor_result),
|
|
127
|
+
on_invalid_draft: method(:record_invalid_processor_draft)
|
|
130
128
|
)
|
|
131
129
|
end
|
|
132
130
|
|
|
@@ -146,7 +144,7 @@ module Julewire
|
|
|
146
144
|
if raw_input_blocked?(input, enforce_level: enforce_level, lazy: lazy)
|
|
147
145
|
increment_pipeline_counter(:level_dropped)
|
|
148
146
|
else
|
|
149
|
-
emit_prepared_draft(yield, enforce_level: enforce_level
|
|
147
|
+
emit_prepared_draft(yield, enforce_level: enforce_level)
|
|
150
148
|
end
|
|
151
149
|
finish_emit_attempt(degradation_marker)
|
|
152
150
|
rescue StandardError => e
|
|
@@ -159,7 +157,6 @@ module Julewire
|
|
|
159
157
|
return false unless @destinations.empty?
|
|
160
158
|
|
|
161
159
|
record_no_output_drop
|
|
162
|
-
true
|
|
163
160
|
end
|
|
164
161
|
|
|
165
162
|
def finish_emit_attempt(degradation_marker)
|
|
@@ -171,9 +168,7 @@ module Julewire
|
|
|
171
168
|
Records::Record.validate_normalized!(record)
|
|
172
169
|
return emit_fast_record(record, enforce_level: enforce_level) if fast_record_path?
|
|
173
170
|
|
|
174
|
-
emit_prepared_draft(Records::Draft.from_record(record,
|
|
175
|
-
enforce_level: enforce_level)
|
|
176
|
-
nil
|
|
171
|
+
emit_prepared_draft(Records::Draft.from_record(record), enforce_level: enforce_level)
|
|
177
172
|
end
|
|
178
173
|
|
|
179
174
|
def fast_record_path?
|
|
@@ -188,7 +183,6 @@ module Julewire
|
|
|
188
183
|
|
|
189
184
|
increment_pipeline_counter(:entered)
|
|
190
185
|
emit_to_destinations(record)
|
|
191
|
-
nil
|
|
192
186
|
end
|
|
193
187
|
|
|
194
188
|
def raw_input_blocked?(input, enforce_level:, lazy:)
|
|
@@ -210,14 +204,14 @@ module Julewire
|
|
|
210
204
|
)
|
|
211
205
|
end
|
|
212
206
|
|
|
213
|
-
def
|
|
207
|
+
def build_isolated_owned_draft(input)
|
|
214
208
|
build_draft_from(
|
|
215
209
|
input,
|
|
216
|
-
input_owned:
|
|
217
|
-
context:
|
|
218
|
-
neutral:
|
|
219
|
-
attributes:
|
|
220
|
-
carry:
|
|
210
|
+
input_owned: true,
|
|
211
|
+
context: nil,
|
|
212
|
+
neutral: nil,
|
|
213
|
+
attributes: nil,
|
|
214
|
+
carry: nil,
|
|
221
215
|
scope: nil
|
|
222
216
|
)
|
|
223
217
|
end
|
|
@@ -229,9 +223,7 @@ module Julewire
|
|
|
229
223
|
neutral: neutral,
|
|
230
224
|
attributes: attributes,
|
|
231
225
|
carry: carry,
|
|
232
|
-
static_labels: @labels,
|
|
233
226
|
input_owned: input_owned,
|
|
234
|
-
freeze_sections: @processors_empty,
|
|
235
227
|
scope: scope,
|
|
236
228
|
error_backtrace_lines: @error_backtrace_lines,
|
|
237
229
|
invalid_severity_reporter: @invalid_severity_reporter
|
|
@@ -241,7 +233,6 @@ module Julewire
|
|
|
241
233
|
def initialize_tracking
|
|
242
234
|
@health = Diagnostics::Health.new(
|
|
243
235
|
counter_keys: COUNTER_KEYS,
|
|
244
|
-
callback_metadata: {},
|
|
245
236
|
callback_failure_counter: :callback_error
|
|
246
237
|
)
|
|
247
238
|
end
|
|
@@ -267,13 +258,13 @@ module Julewire
|
|
|
267
258
|
@threshold.allow?(record_or_draft.fetch(:severity))
|
|
268
259
|
end
|
|
269
260
|
|
|
270
|
-
def emit_prepared_draft(draft, enforce_level
|
|
261
|
+
def emit_prepared_draft(draft, enforce_level:)
|
|
271
262
|
if enforce_level && !emit_record?(draft)
|
|
272
263
|
increment_pipeline_counter(:level_dropped)
|
|
273
264
|
return
|
|
274
265
|
end
|
|
275
266
|
|
|
276
|
-
draft = merge_static_labels(draft)
|
|
267
|
+
draft = merge_static_labels(draft)
|
|
277
268
|
increment_pipeline_counter(:entered)
|
|
278
269
|
emit_processed_draft(draft, enforce_level: enforce_level)
|
|
279
270
|
rescue StandardError => e
|
|
@@ -289,9 +280,12 @@ module Julewire
|
|
|
289
280
|
return
|
|
290
281
|
end
|
|
291
282
|
|
|
292
|
-
processed
|
|
283
|
+
if processed.instance_of?(ProcessorChain::ErrorResult)
|
|
284
|
+
processed = processed.draft
|
|
285
|
+
enforce_level = false
|
|
286
|
+
end
|
|
293
287
|
|
|
294
|
-
if
|
|
288
|
+
if enforce_level && !emit_record?(processed)
|
|
295
289
|
increment_pipeline_counter(:level_dropped)
|
|
296
290
|
return
|
|
297
291
|
end
|
|
@@ -299,27 +293,40 @@ module Julewire
|
|
|
299
293
|
emit_to_destinations(processed.to_record)
|
|
300
294
|
end
|
|
301
295
|
|
|
302
|
-
def processed_draft_and_level(processed, default_enforce_level)
|
|
303
|
-
if processed.is_a?(ProcessorChain::ErrorResult)
|
|
304
|
-
[processed.draft, false]
|
|
305
|
-
else
|
|
306
|
-
[processed, default_enforce_level]
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
296
|
def record_processor_error(error, record_metadata)
|
|
311
297
|
increment_pipeline_counter(:processor_error)
|
|
312
298
|
notify_failure(error, phase: :processor, record_metadata: record_metadata)
|
|
313
299
|
end
|
|
314
300
|
|
|
301
|
+
def record_invalid_processor_result(processor_name, result, record_metadata)
|
|
302
|
+
increment_pipeline_counter(:processor_invalid)
|
|
303
|
+
error, metadata = InvalidResultFailure.build(
|
|
304
|
+
message: "processor returned unsupported result",
|
|
305
|
+
phase: :processor_result,
|
|
306
|
+
processor_name: processor_name,
|
|
307
|
+
record_metadata: record_metadata,
|
|
308
|
+
result: result
|
|
309
|
+
)
|
|
310
|
+
notify_failure(error, **metadata)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def record_invalid_processor_draft(processor_name, error, record_metadata)
|
|
314
|
+
increment_pipeline_counter(:processor_invalid)
|
|
315
|
+
notify_failure(
|
|
316
|
+
error,
|
|
317
|
+
phase: :processor_data,
|
|
318
|
+
processor: processor_name,
|
|
319
|
+
record_metadata: record_metadata
|
|
320
|
+
)
|
|
321
|
+
end
|
|
322
|
+
|
|
315
323
|
def emit_internal_error_record(error)
|
|
316
324
|
emit_prepared_draft(
|
|
317
|
-
Diagnostics::InternalRecords.emit_error(error
|
|
325
|
+
Diagnostics::InternalRecords.emit_error(error),
|
|
318
326
|
enforce_level: false
|
|
319
327
|
)
|
|
320
328
|
rescue StandardError => e
|
|
321
329
|
notify_failure(e, phase: :internal_error_record)
|
|
322
|
-
nil
|
|
323
330
|
end
|
|
324
331
|
|
|
325
332
|
def emit_to_destinations(record)
|
|
@@ -328,7 +335,6 @@ module Julewire
|
|
|
328
335
|
|
|
329
336
|
def record_no_output_drop
|
|
330
337
|
increment_pipeline_counter(:no_output_dropped)
|
|
331
|
-
nil
|
|
332
338
|
end
|
|
333
339
|
|
|
334
340
|
def notify_failure(error, **metadata)
|
|
@@ -7,10 +7,11 @@ module Julewire
|
|
|
7
7
|
DROP = Core.sentinel(:drop)
|
|
8
8
|
ErrorResult = Data.define(:draft)
|
|
9
9
|
|
|
10
|
-
def initialize(processors:,
|
|
10
|
+
def initialize(processors:, on_error:, on_invalid:, on_invalid_draft:)
|
|
11
11
|
@processors = processors
|
|
12
|
-
@error_backtrace_lines = error_backtrace_lines
|
|
13
12
|
@on_error = on_error
|
|
13
|
+
@on_invalid = on_invalid
|
|
14
|
+
@on_invalid_draft = on_invalid_draft
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def empty? = @processors.empty?
|
|
@@ -19,13 +20,15 @@ module Julewire
|
|
|
19
20
|
current = draft
|
|
20
21
|
|
|
21
22
|
@processors.each do |processor|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
result = processor.call(current)
|
|
24
|
+
current = apply_processor_result(current, processor, result)
|
|
25
|
+
return DROP if current.equal?(DROP)
|
|
26
|
+
return DROP unless valid_processor_draft?(processor, current)
|
|
24
27
|
rescue StandardError => e
|
|
25
28
|
action = handle_processor_error(processor, e, current)
|
|
26
29
|
case action
|
|
27
30
|
when :continue
|
|
28
|
-
|
|
31
|
+
return DROP unless valid_processor_draft?(processor, current)
|
|
29
32
|
when :drop
|
|
30
33
|
return DROP
|
|
31
34
|
else
|
|
@@ -33,15 +36,17 @@ module Julewire
|
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
|
|
36
|
-
current
|
|
39
|
+
current
|
|
37
40
|
end
|
|
38
41
|
|
|
39
42
|
private
|
|
40
43
|
|
|
41
|
-
def apply_processor_result(current, result)
|
|
42
|
-
return
|
|
43
|
-
return
|
|
44
|
+
def apply_processor_result(current, processor, result)
|
|
45
|
+
return DROP if result == :drop
|
|
46
|
+
return current if result.nil?
|
|
47
|
+
return result if result.instance_of?(Records::Draft)
|
|
44
48
|
|
|
49
|
+
@on_invalid.call(processor.processor_name, result, Records::Metadata.call(current))
|
|
45
50
|
current
|
|
46
51
|
end
|
|
47
52
|
|
|
@@ -55,12 +60,18 @@ module Julewire
|
|
|
55
60
|
ErrorResult.new(processor_error_record(processor, error, record_metadata))
|
|
56
61
|
end
|
|
57
62
|
|
|
63
|
+
def valid_processor_draft?(processor, draft)
|
|
64
|
+
draft.validate!
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
@on_invalid_draft.call(processor.processor_name, e, Records::Metadata.call(draft))
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
|
|
58
70
|
def processor_error_record(processor, error, record_metadata)
|
|
59
71
|
Diagnostics::InternalRecords.processor_error(
|
|
60
72
|
processor_name: processor.processor_name,
|
|
61
73
|
error: error,
|
|
62
|
-
record_metadata: record_metadata
|
|
63
|
-
error_backtrace_lines: @error_backtrace_lines
|
|
74
|
+
record_metadata: record_metadata
|
|
64
75
|
)
|
|
65
76
|
end
|
|
66
77
|
end
|
|
@@ -49,7 +49,6 @@ module Julewire
|
|
|
49
49
|
|
|
50
50
|
entry = build_entry(processor, arguments, options)
|
|
51
51
|
prepend ? @entries.unshift(entry) : @entries << entry
|
|
52
|
-
self
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
def build_entry(processor, arguments = [], options = {})
|
|
@@ -66,7 +65,7 @@ module Julewire
|
|
|
66
65
|
on_error: on_error,
|
|
67
66
|
factory: true
|
|
68
67
|
)
|
|
69
|
-
elsif processor.
|
|
68
|
+
elsif processor.instance_of?(Class)
|
|
70
69
|
Entry.new(
|
|
71
70
|
entry: processor,
|
|
72
71
|
arguments: arguments.dup.freeze,
|
|
@@ -81,13 +80,13 @@ module Julewire
|
|
|
81
80
|
end
|
|
82
81
|
|
|
83
82
|
def normalize_entry(entry)
|
|
84
|
-
entry.
|
|
83
|
+
entry.instance_of?(Entry) ? entry : build_entry(entry)
|
|
85
84
|
end
|
|
86
85
|
|
|
87
86
|
def materialize(entry)
|
|
88
87
|
processor = if entry.factory
|
|
89
88
|
Processing.build(entry.entry, *entry.arguments, **entry.options)
|
|
90
|
-
elsif entry.entry.
|
|
89
|
+
elsif entry.entry.instance_of?(Class)
|
|
91
90
|
entry.entry.new(*entry.arguments, **entry.options)
|
|
92
91
|
else
|
|
93
92
|
entry.entry
|
|
@@ -14,10 +14,6 @@ module Julewire
|
|
|
14
14
|
private_constant :SCALAR_KEY_SET
|
|
15
15
|
|
|
16
16
|
class << self
|
|
17
|
-
def container_keys = CONTAINER_KEYS
|
|
18
|
-
|
|
19
|
-
def scalar_keys = SCALAR_KEYS
|
|
20
|
-
|
|
21
17
|
def container_key?(key) = CONTAINER_KEY_SET.key?(key)
|
|
22
18
|
|
|
23
19
|
def scalar_key?(key) = SCALAR_KEY_SET.key?(key)
|
|
@@ -77,7 +77,7 @@ module Julewire
|
|
|
77
77
|
return :drop if value.nil?
|
|
78
78
|
return if @threshold == HASH_SPACE
|
|
79
79
|
|
|
80
|
-
Sampling.stable_hash(value) < @threshold
|
|
80
|
+
:drop unless Sampling.stable_hash(value) < @threshold
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
private
|
|
@@ -98,8 +98,6 @@ module Julewire
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def field_value(hash, key)
|
|
101
|
-
return unless hash.is_a?(Hash)
|
|
102
|
-
|
|
103
101
|
Fields::FieldSet.value_for(hash, key)
|
|
104
102
|
end
|
|
105
103
|
end
|
|
@@ -10,7 +10,6 @@ module Julewire
|
|
|
10
10
|
raise ArgumentError, "processor factory block required" unless factory
|
|
11
11
|
|
|
12
12
|
@factories[normalize_kind(kind)] = factory
|
|
13
|
-
nil
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def build(kind, ...)
|
|
@@ -31,7 +30,8 @@ module Julewire
|
|
|
31
30
|
raise ArgumentError, "processor kind must respond to #to_sym" unless kind.respond_to?(:to_sym)
|
|
32
31
|
|
|
33
32
|
name = kind.to_sym
|
|
34
|
-
raise ArgumentError, "processor kind
|
|
33
|
+
raise ArgumentError, "processor kind #to_sym must return a Symbol" unless name.instance_of?(Symbol)
|
|
34
|
+
raise ArgumentError, "processor kind cannot be empty" if name.empty?
|
|
35
35
|
|
|
36
36
|
name
|
|
37
37
|
end
|
|
@@ -10,6 +10,8 @@ module Julewire
|
|
|
10
10
|
DEFAULT_KEY = "julewire"
|
|
11
11
|
DEFAULT_MAX_BYTES = 65_536
|
|
12
12
|
DEFAULT_ENVELOPE = Core.sentinel(:default_envelope)
|
|
13
|
+
|
|
14
|
+
# @api integration_spi
|
|
13
15
|
class Extracted
|
|
14
16
|
attr_reader :envelope, :status, :reason, :error
|
|
15
17
|
|
|
@@ -23,7 +25,6 @@ module Julewire
|
|
|
23
25
|
def failure? = !error.nil?
|
|
24
26
|
end
|
|
25
27
|
private_constant :DEFAULT_ENVELOPE
|
|
26
|
-
private_constant :Extracted
|
|
27
28
|
|
|
28
29
|
# @api integration_spi
|
|
29
30
|
class ExtractionError < StandardError
|
|
@@ -40,7 +41,7 @@ module Julewire
|
|
|
40
41
|
def encode(envelope: DEFAULT_ENVELOPE, max_bytes: nil)
|
|
41
42
|
Validation.validate_byte_limit!(max_bytes, name: :max_bytes)
|
|
42
43
|
|
|
43
|
-
encoded = JSON.generate(serialized_envelope(envelope)
|
|
44
|
+
encoded = JSON.generate(serialized_envelope(envelope))
|
|
44
45
|
return if max_bytes && encoded.bytesize > max_bytes
|
|
45
46
|
|
|
46
47
|
encoded
|
|
@@ -49,14 +50,14 @@ module Julewire
|
|
|
49
50
|
def inject(carrier = {}, envelope: DEFAULT_ENVELOPE, key: DEFAULT_KEY, max_bytes: nil)
|
|
50
51
|
validate_carrier!(carrier)
|
|
51
52
|
encoded = encode(envelope: envelope, max_bytes: max_bytes)
|
|
52
|
-
clear_carrier_key!(carrier, key)
|
|
53
|
+
clear_carrier_key!(carrier, key)
|
|
53
54
|
return unless encoded
|
|
54
55
|
|
|
55
56
|
carrier[key.to_s] = encoded
|
|
56
57
|
carrier
|
|
57
58
|
end
|
|
58
59
|
|
|
59
|
-
def
|
|
60
|
+
def extract_envelope(carrier, key: DEFAULT_KEY, max_bytes: DEFAULT_MAX_BYTES)
|
|
60
61
|
extract_result(carrier, key: key, max_bytes: max_bytes).envelope
|
|
61
62
|
end
|
|
62
63
|
|
|
@@ -90,7 +91,10 @@ module Julewire
|
|
|
90
91
|
end
|
|
91
92
|
|
|
92
93
|
parsed = JSON.parse(string)
|
|
93
|
-
|
|
94
|
+
unless parsed.instance_of?(Hash)
|
|
95
|
+
return extracted_failure(:non_hash,
|
|
96
|
+
"carrier payload must be a JSON object")
|
|
97
|
+
end
|
|
94
98
|
|
|
95
99
|
extracted(Fields::FieldSet.deep_symbolize_owned_keys(parsed), :ok)
|
|
96
100
|
rescue StandardError => e
|
|
@@ -103,7 +107,7 @@ module Julewire
|
|
|
103
107
|
|
|
104
108
|
def extracted_failure(status, reason, cause = nil)
|
|
105
109
|
error = ExtractionError.new(status, reason)
|
|
106
|
-
error.set_backtrace(cause.backtrace) if cause
|
|
110
|
+
error.set_backtrace(cause.backtrace) if cause
|
|
107
111
|
Extracted.new(envelope: {}, status: status, reason: reason, error: error)
|
|
108
112
|
end
|
|
109
113
|
|
|
@@ -122,14 +126,10 @@ module Julewire
|
|
|
122
126
|
def clear_carrier_key!(carrier, key)
|
|
123
127
|
string_key = key.to_s
|
|
124
128
|
symbol_key = Fields::Internal.normalize_key(key)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
rescue StandardError
|
|
130
|
-
clear_carrier_key_by_assignment(carrier, string_key, symbol_key)
|
|
131
|
-
end
|
|
132
|
-
else
|
|
129
|
+
begin
|
|
130
|
+
carrier.delete(string_key)
|
|
131
|
+
carrier.delete(symbol_key)
|
|
132
|
+
rescue StandardError
|
|
133
133
|
clear_carrier_key_by_assignment(carrier, string_key, symbol_key)
|
|
134
134
|
end
|
|
135
135
|
end
|
|
@@ -19,8 +19,11 @@ module Julewire
|
|
|
19
19
|
def restore(envelope, link_executions: false, owned: false, &)
|
|
20
20
|
raise ArgumentError, "block required" unless block_given?
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
Integration::Protocol.validate_symbol_hash(envelope) if owned
|
|
23
|
+
sections = FIELD_SECTIONS.to_h do |section|
|
|
24
|
+
[section, restore_hash_value(envelope, section, owned: owned)]
|
|
25
|
+
end
|
|
26
|
+
execution = restore_hash_value(envelope, :execution, owned: owned)
|
|
24
27
|
ContextStore.current.with_propagation(
|
|
25
28
|
**sections,
|
|
26
29
|
execution: execution,
|
|
@@ -45,6 +48,16 @@ module Julewire
|
|
|
45
48
|
value = Fields::FieldSet.value_for(hash, key)
|
|
46
49
|
value.is_a?(Hash) ? value : {}
|
|
47
50
|
end
|
|
51
|
+
|
|
52
|
+
def restore_hash_value(envelope, key, owned:)
|
|
53
|
+
return hash_value(envelope, key) unless owned
|
|
54
|
+
return {} unless envelope.key?(key)
|
|
55
|
+
|
|
56
|
+
value = envelope.fetch(key)
|
|
57
|
+
return value if value.is_a?(Hash)
|
|
58
|
+
|
|
59
|
+
raise TypeError, "propagation #{key} must be a Hash"
|
|
60
|
+
end
|
|
48
61
|
end
|
|
49
62
|
end
|
|
50
63
|
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Records
|
|
6
|
+
# Converts raw emit input into known record fields plus payload fields.
|
|
7
|
+
# @api bridge_spi
|
|
8
|
+
module BuildInput
|
|
9
|
+
RECORD_INPUT_KEYS = Record::REQUIRED_KEYS.freeze
|
|
10
|
+
RECORD_INPUT_KEY_SET = RECORD_INPUT_KEYS.to_h { [it, true] }.freeze
|
|
11
|
+
private_constant :RECORD_INPUT_KEYS, :RECORD_INPUT_KEY_SET
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def normalize_public(input)
|
|
15
|
+
return {} if input.nil?
|
|
16
|
+
return normalize_public_hash(input) if RawInput.hash_input?(input)
|
|
17
|
+
|
|
18
|
+
{ message: input.to_s }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate_owned(input)
|
|
22
|
+
raise TypeError, "owned record input must be a Hash" unless input.is_a?(Hash)
|
|
23
|
+
|
|
24
|
+
Serialization::DeepFreeze.validate_symbol_keys(input)
|
|
25
|
+
validate_known_keys!(input)
|
|
26
|
+
input
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def validate_known_keys!(input)
|
|
32
|
+
unknown = input.each_key.reject { RECORD_INPUT_KEY_SET.key?(it) }
|
|
33
|
+
return if unknown.empty?
|
|
34
|
+
|
|
35
|
+
raise TypeError, "owned record input has unknown top-level keys: #{unknown.join(", ")}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def normalize_public_hash(input)
|
|
39
|
+
normalized = {}
|
|
40
|
+
payload_fields = {}
|
|
41
|
+
input.each do |key, raw_value|
|
|
42
|
+
normalized_key = Fields::Internal.normalize_key(key)
|
|
43
|
+
value = raw_value.equal?(input) ? CIRCULAR_REFERENCE : raw_value
|
|
44
|
+
if RECORD_INPUT_KEY_SET.key?(normalized_key)
|
|
45
|
+
normalized[normalized_key] = value
|
|
46
|
+
else
|
|
47
|
+
payload_fields[normalized_key] = value
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
merge_unknown_payload!(normalized, payload_fields)
|
|
51
|
+
normalized
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def merge_unknown_payload!(normalized, payload_fields)
|
|
55
|
+
return if payload_fields.empty?
|
|
56
|
+
|
|
57
|
+
normalized[:payload] = if normalized.key?(:payload)
|
|
58
|
+
merge_payload_input(normalized.fetch(:payload), payload_fields)
|
|
59
|
+
else
|
|
60
|
+
payload_fields
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def merge_payload_input(explicit_payload, unknown_payload)
|
|
65
|
+
if explicit_payload.is_a?(Hash)
|
|
66
|
+
Fields::FieldSet.merge(unknown_payload, explicit_payload)
|
|
67
|
+
else
|
|
68
|
+
Fields::FieldSet.merge(unknown_payload, Fields::FieldSet::VALUE_KEY => explicit_payload)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -9,13 +9,13 @@ module Julewire
|
|
|
9
9
|
Record.validate_normalized!(record)
|
|
10
10
|
|
|
11
11
|
{
|
|
12
|
-
event: record
|
|
13
|
-
labels: record
|
|
12
|
+
event: record.fetch(:event),
|
|
13
|
+
labels: record.fetch(:labels),
|
|
14
14
|
message: DisplayMessage.call(record),
|
|
15
|
-
payload: record
|
|
16
|
-
severity: record
|
|
17
|
-
source: record
|
|
18
|
-
timestamp: record
|
|
15
|
+
payload: record.fetch(:payload),
|
|
16
|
+
severity: record.fetch(:severity),
|
|
17
|
+
source: record.fetch(:source),
|
|
18
|
+
timestamp: record.fetch(:timestamp)
|
|
19
19
|
}
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -118,9 +118,7 @@ module Julewire
|
|
|
118
118
|
|
|
119
119
|
def duration_text(value)
|
|
120
120
|
text = format("%.3f", value.round(3))
|
|
121
|
-
text.
|
|
122
|
-
text.delete_suffix!(".")
|
|
123
|
-
text
|
|
121
|
+
text.sub(/(?:\.0+|(\.\d+?)0+)\z/, "\\1")
|
|
124
122
|
end
|
|
125
123
|
|
|
126
124
|
def job_queue(neutral)
|
|
@@ -153,7 +151,7 @@ module Julewire
|
|
|
153
151
|
end
|
|
154
152
|
|
|
155
153
|
def value_at(value, key)
|
|
156
|
-
Fields::Lookup.
|
|
154
|
+
Fields::Lookup.wire_value(value, key)
|
|
157
155
|
end
|
|
158
156
|
|
|
159
157
|
def blank?(value)
|