julewire-core 1.0.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 +7 -0
- data/CHANGELOG.md +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/docs/advanced-configuration.md +66 -0
- data/docs/attribute-keys.md +74 -0
- data/docs/configuration.md +327 -0
- data/docs/context-and-propagation.md +353 -0
- data/docs/contracts.md +211 -0
- data/docs/development.md +49 -0
- data/docs/extensions-and-api.md +567 -0
- data/docs/health-schema.md +104 -0
- data/docs/instrumentation-cheatsheet.md +29 -0
- data/docs/internals.md +135 -0
- data/docs/outputs-and-lifecycle.md +206 -0
- data/docs/quickstart.md +133 -0
- data/docs/record-sources.md +17 -0
- data/docs/records-and-data-policy.md +230 -0
- data/docs/security-and-wire.md +45 -0
- data/docs/tail.md +91 -0
- data/exe/julewire +6 -0
- data/julewire-core.gemspec +41 -0
- data/lib/julewire/core/cli/doctor.rb +143 -0
- data/lib/julewire/core/cli/line_helpers.rb +77 -0
- data/lib/julewire/core/cli/log_formats/console_text.rb +25 -0
- data/lib/julewire/core/cli/log_formats/core_json_decoder.rb +46 -0
- data/lib/julewire/core/cli/log_formats/core_json_encoder.rb +21 -0
- data/lib/julewire/core/cli/log_formats/record_decoder.rb +39 -0
- data/lib/julewire/core/cli/log_formats.rb +123 -0
- data/lib/julewire/core/cli/tail.rb +153 -0
- data/lib/julewire/core/cli/transcode.rb +105 -0
- data/lib/julewire/core/cli.rb +73 -0
- data/lib/julewire/core/configuration.rb +99 -0
- data/lib/julewire/core/context_store.rb +384 -0
- data/lib/julewire/core/destinations/chaos_output.rb +91 -0
- data/lib/julewire/core/destinations/collection.rb +177 -0
- data/lib/julewire/core/destinations/definition.rb +125 -0
- data/lib/julewire/core/destinations/destination.rb +268 -0
- data/lib/julewire/core/destinations/registry.rb +81 -0
- data/lib/julewire/core/destinations/sink.rb +35 -0
- data/lib/julewire/core/destinations/synchronized_output.rb +57 -0
- data/lib/julewire/core/destinations/tail_sampling.rb +321 -0
- data/lib/julewire/core/destinations/write_step.rb +119 -0
- data/lib/julewire/core/destinations.rb +33 -0
- data/lib/julewire/core/diagnostics/callback_notifier.rb +63 -0
- data/lib/julewire/core/diagnostics/doctor.rb +114 -0
- data/lib/julewire/core/diagnostics/failure_snapshot.rb +39 -0
- data/lib/julewire/core/diagnostics/health.rb +144 -0
- data/lib/julewire/core/diagnostics/integration_health_store.rb +64 -0
- data/lib/julewire/core/diagnostics/internal_records.rb +61 -0
- data/lib/julewire/core/diagnostics/invalid_severity_reporter.rb +112 -0
- data/lib/julewire/core/diagnostics/meta_observer.rb +161 -0
- data/lib/julewire/core/diagnostics/process_integration_health.rb +26 -0
- data/lib/julewire/core/diagnostics/tail/renderer.rb +36 -0
- data/lib/julewire/core/diagnostics/tail.rb +168 -0
- data/lib/julewire/core/diagnostics.rb +8 -0
- data/lib/julewire/core/error.rb +7 -0
- data/lib/julewire/core/execution/boundary.rb +106 -0
- data/lib/julewire/core/execution/handle.rb +77 -0
- data/lib/julewire/core/execution/lineage.rb +192 -0
- data/lib/julewire/core/execution/measurement_handle.rb +28 -0
- data/lib/julewire/core/execution/no_current_error.rb +9 -0
- data/lib/julewire/core/execution/scope.rb +246 -0
- data/lib/julewire/core/execution/scope_fields.rb +76 -0
- data/lib/julewire/core/execution/scope_identity.rb +71 -0
- data/lib/julewire/core/execution/scope_snapshot.rb +92 -0
- data/lib/julewire/core/execution/summary_state.rb +206 -0
- data/lib/julewire/core/execution/view.rb +56 -0
- data/lib/julewire/core/facade_methods.rb +181 -0
- data/lib/julewire/core/fields/attribute_keys.rb +54 -0
- data/lib/julewire/core/fields/attributes_proxy.rb +11 -0
- data/lib/julewire/core/fields/bags.rb +123 -0
- data/lib/julewire/core/fields/carry_proxy.rb +22 -0
- data/lib/julewire/core/fields/context_proxy.rb +11 -0
- data/lib/julewire/core/fields/field_set.rb +78 -0
- data/lib/julewire/core/fields/field_stack.rb +269 -0
- data/lib/julewire/core/fields/internal/deletion.rb +68 -0
- data/lib/julewire/core/fields/internal.rb +87 -0
- data/lib/julewire/core/fields/lookup.rb +35 -0
- data/lib/julewire/core/fields/section_proxy.rb +88 -0
- data/lib/julewire/core/fields/stack_set.rb +69 -0
- data/lib/julewire/core/fields/static_labels.rb +43 -0
- data/lib/julewire/core/fields/summary_proxy.rb +62 -0
- data/lib/julewire/core/integration/configurable.rb +52 -0
- data/lib/julewire/core/integration/destination_health.rb +43 -0
- data/lib/julewire/core/integration/event_subscriber.rb +62 -0
- data/lib/julewire/core/integration/facade.rb +131 -0
- data/lib/julewire/core/integration/fork_hooks.rb +79 -0
- data/lib/julewire/core/integration/health.rb +41 -0
- data/lib/julewire/core/integration/ivar_state.rb +38 -0
- data/lib/julewire/core/integration/lifecycle.rb +22 -0
- data/lib/julewire/core/integration/scoped.rb +34 -0
- data/lib/julewire/core/integration/settings.rb +92 -0
- data/lib/julewire/core/integration/subscriber_install.rb +39 -0
- data/lib/julewire/core/integration/subscription.rb +29 -0
- data/lib/julewire/core/integration/values.rb +192 -0
- data/lib/julewire/core/lifecycle_error.rb +7 -0
- data/lib/julewire/core/local_storage.rb +91 -0
- data/lib/julewire/core/processing/level_threshold.rb +53 -0
- data/lib/julewire/core/processing/match.rb +74 -0
- data/lib/julewire/core/processing/pipeline.rb +360 -0
- data/lib/julewire/core/processing/processor_chain.rb +69 -0
- data/lib/julewire/core/processing/processor_registry.rb +115 -0
- data/lib/julewire/core/processing/processor_wrapper.rb +44 -0
- data/lib/julewire/core/processing/record_field_transform.rb +124 -0
- data/lib/julewire/core/processing/sampling.rb +109 -0
- data/lib/julewire/core/processing.rb +41 -0
- data/lib/julewire/core/propagation/carrier.rb +93 -0
- data/lib/julewire/core/propagation.rb +50 -0
- data/lib/julewire/core/records/console_formatter.rb +24 -0
- data/lib/julewire/core/records/deconstruct.rb +19 -0
- data/lib/julewire/core/records/display_message.rb +166 -0
- data/lib/julewire/core/records/draft.rb +576 -0
- data/lib/julewire/core/records/formatter.rb +14 -0
- data/lib/julewire/core/records/lazy_emit_input.rb +99 -0
- data/lib/julewire/core/records/metadata.rb +23 -0
- data/lib/julewire/core/records/public_projection.rb +51 -0
- data/lib/julewire/core/records/raw_input.rb +41 -0
- data/lib/julewire/core/records/record.rb +175 -0
- data/lib/julewire/core/records/severity.rb +44 -0
- data/lib/julewire/core/runtime.rb +515 -0
- data/lib/julewire/core/runtime_locator.rb +20 -0
- data/lib/julewire/core/runtime_registry.rb +48 -0
- data/lib/julewire/core/runtime_state.rb +39 -0
- data/lib/julewire/core/scheduling/deadline.rb +24 -0
- data/lib/julewire/core/scheduling/deadline_scheduler.rb +207 -0
- data/lib/julewire/core/scheduling/shared_scheduler.rb +48 -0
- data/lib/julewire/core/sentinel.rb +18 -0
- data/lib/julewire/core/serialization/backtrace_limiter.rb +50 -0
- data/lib/julewire/core/serialization/bounded_transform.rb +55 -0
- data/lib/julewire/core/serialization/bounded_traversal.rb +274 -0
- data/lib/julewire/core/serialization/deep_compact_empty.rb +67 -0
- data/lib/julewire/core/serialization/deep_freeze.rb +63 -0
- data/lib/julewire/core/serialization/encoding_sanitizer.rb +40 -0
- data/lib/julewire/core/serialization/exception_shape.rb +88 -0
- data/lib/julewire/core/serialization/json_encoder.rb +69 -0
- data/lib/julewire/core/serialization/serializer.rb +233 -0
- data/lib/julewire/core/serialization/serializer_pool.rb +21 -0
- data/lib/julewire/core/serialization/text_encoder.rb +147 -0
- data/lib/julewire/core/serialization/value_copy.rb +209 -0
- data/lib/julewire/core/serialization/value_traversal.rb +150 -0
- data/lib/julewire/core/testing/chaos/catalog.rb +72 -0
- data/lib/julewire/core/testing/chaos/core_runtime.rb +120 -0
- data/lib/julewire/core/testing/chaos/destination.rb +55 -0
- data/lib/julewire/core/testing/chaos/emitter.rb +20 -0
- data/lib/julewire/core/testing/chaos/raising_output.rb +42 -0
- data/lib/julewire/core/testing/chaos.rb +80 -0
- data/lib/julewire/core/testing/contracts/component.rb +162 -0
- data/lib/julewire/core/testing/contracts/deadline_scheduler.rb +59 -0
- data/lib/julewire/core/testing/contracts/integration.rb +166 -0
- data/lib/julewire/core/testing/contracts/integration_fields.rb +36 -0
- data/lib/julewire/core/testing/contracts/record_draft.rb +37 -0
- data/lib/julewire/core/testing/contracts/runtime.rb +178 -0
- data/lib/julewire/core/testing/contracts/wire.rb +60 -0
- data/lib/julewire/core/testing/contracts.rb +24 -0
- data/lib/julewire/core/testing/coverage.rb +58 -0
- data/lib/julewire/core/testing/test_reports.rb +78 -0
- data/lib/julewire/core/testing.rb +122 -0
- data/lib/julewire/core/validation.rb +69 -0
- data/lib/julewire/core/version.rb +7 -0
- data/lib/julewire/core.rb +80 -0
- data/lib/julewire/error.rb +5 -0
- data/lib/julewire-core.rb +3 -0
- metadata +237 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Execution
|
|
6
|
+
# @api public
|
|
7
|
+
# Read-only view returned by Julewire.current_execution.
|
|
8
|
+
class View
|
|
9
|
+
attr_reader :finished_at, :id, :lineage, :started_at, :type
|
|
10
|
+
|
|
11
|
+
def initialize(scope)
|
|
12
|
+
@scope = scope
|
|
13
|
+
@id = scope.id
|
|
14
|
+
@type = scope.type
|
|
15
|
+
@started_at = scope.started_at
|
|
16
|
+
@finished_at = scope.finished_at
|
|
17
|
+
@parent_scope = scope.parent
|
|
18
|
+
@lineage = scope.lineage
|
|
19
|
+
@parent = nil
|
|
20
|
+
@execution_hash = nil
|
|
21
|
+
@context_hash = nil
|
|
22
|
+
@carry_hash = nil
|
|
23
|
+
@neutral_hash = nil
|
|
24
|
+
@attributes_hash = nil
|
|
25
|
+
@labels_hash = nil
|
|
26
|
+
@summary_hash = nil
|
|
27
|
+
@metrics_hash = nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def parent
|
|
31
|
+
return unless @parent_scope
|
|
32
|
+
|
|
33
|
+
@parent ||= self.class.new(@parent_scope)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def execution_hash = Fields::FieldSet.deep_dup(@execution_hash ||= @scope.frozen_execution_hash)
|
|
37
|
+
|
|
38
|
+
def context_hash = Fields::FieldSet.deep_dup(@context_hash ||= @scope.context_hash)
|
|
39
|
+
|
|
40
|
+
def carry_hash = Fields::FieldSet.deep_dup(@carry_hash ||= @scope.carry_hash)
|
|
41
|
+
|
|
42
|
+
def neutral_hash = Fields::FieldSet.deep_dup(@neutral_hash ||= @scope.neutral_hash)
|
|
43
|
+
|
|
44
|
+
def attributes_hash = Fields::FieldSet.deep_dup(@attributes_hash ||= @scope.attributes_hash)
|
|
45
|
+
|
|
46
|
+
def labels_hash = Fields::FieldSet.deep_dup(@labels_hash ||= @scope.frozen_labels_hash)
|
|
47
|
+
|
|
48
|
+
def summary_hash = Fields::FieldSet.deep_dup(@summary_hash ||= @scope.summary_hash)
|
|
49
|
+
|
|
50
|
+
def metrics_hash = Fields::FieldSet.deep_dup(@metrics_hash ||= @scope.metrics_hash)
|
|
51
|
+
|
|
52
|
+
def finished? = !finished_at.nil?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module FacadeMethods
|
|
6
|
+
def runtime(name = :default)
|
|
7
|
+
Core::RuntimeRegistry.fetch(name, current: Core::RuntimeLocator.current)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def config = runtime.config
|
|
11
|
+
|
|
12
|
+
def configure(&) = runtime.configure(&)
|
|
13
|
+
|
|
14
|
+
def context = runtime.context
|
|
15
|
+
|
|
16
|
+
def attributes = runtime.attributes
|
|
17
|
+
|
|
18
|
+
def carry = runtime.carry
|
|
19
|
+
|
|
20
|
+
def current_execution = runtime.current_execution
|
|
21
|
+
|
|
22
|
+
def current_execution? = runtime.current_execution?
|
|
23
|
+
|
|
24
|
+
def emit(record = Core::UNSET, **fields, &)
|
|
25
|
+
runtime.emit(record, **fields, &)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def debug(record = Core::UNSET, **fields, &)
|
|
29
|
+
emit_with_severity(:debug, record, fields, &)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def info(record = Core::UNSET, **fields, &)
|
|
33
|
+
emit_with_severity(:info, record, fields, &)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def warn(record = Core::UNSET, **fields, &)
|
|
37
|
+
emit_with_severity(:warn, record, fields, &)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def error(record = Core::UNSET, **fields, &)
|
|
41
|
+
emit_with_severity(:error, record, fields, &)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def fatal(record = Core::UNSET, **fields, &)
|
|
45
|
+
emit_with_severity(:fatal, record, fields, &)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def unknown(record = Core::UNSET, **fields, &)
|
|
49
|
+
emit_with_severity(:unknown, record, fields, &)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def flush(timeout: Core::UNSET)
|
|
53
|
+
runtime.flush(timeout: timeout)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def health = runtime.health
|
|
57
|
+
|
|
58
|
+
def measure(key, &)
|
|
59
|
+
summary.measure(key, &)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def measure_start(key) = summary.measure_start(key)
|
|
63
|
+
|
|
64
|
+
def doctor(name = :default)
|
|
65
|
+
Core::Diagnostics::Doctor.call(runtime(name))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def tail(name = :default, **)
|
|
69
|
+
Core::Diagnostics::Tail.attach!(runtime(name), **)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def observe_self!(name = :default, **)
|
|
73
|
+
Core::Diagnostics::MetaObserver.attach!(name, **)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def dev!(name = :default, output: $stdout, color: Core::UNSET, chaos: false, banner: chaos, tail: true)
|
|
77
|
+
color = output.respond_to?(:tty?) ? output.tty? : true if color.equal?(Core::UNSET)
|
|
78
|
+
punk!(name, output: output, color: color, chaos: chaos, banner: banner)
|
|
79
|
+
return unless tail
|
|
80
|
+
|
|
81
|
+
tail_options = tail == true ? {} : tail
|
|
82
|
+
raise ArgumentError, "tail must be true, false, or an options Hash" unless tail_options.is_a?(Hash)
|
|
83
|
+
|
|
84
|
+
Core::Diagnostics::Tail.attach!(runtime(name), **tail_options)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def punk!(name = :default, output: $stdout, color: true, chaos: false, banner: chaos)
|
|
88
|
+
output.write(punk_banner) if banner
|
|
89
|
+
output = punk_chaos_output(output, chaos) if chaos
|
|
90
|
+
|
|
91
|
+
runtime(name).configure do |config|
|
|
92
|
+
config.destinations.clear
|
|
93
|
+
config.destinations.use(
|
|
94
|
+
:default,
|
|
95
|
+
formatter: ConsoleFormatter.new,
|
|
96
|
+
encoder: TextEncoder.new(color: color, theme: :punk),
|
|
97
|
+
output: output
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def fiber(**, &)
|
|
103
|
+
raise ArgumentError, "block required" unless block_given?
|
|
104
|
+
|
|
105
|
+
envelope = Core::Propagation.capture_local
|
|
106
|
+
Fiber.new(**) do |*args|
|
|
107
|
+
with_cleared_configure_guard do
|
|
108
|
+
Core::Propagation.restore(envelope) { yield(*args) }
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def labels = runtime.labels
|
|
114
|
+
|
|
115
|
+
def after_fork! = runtime.after_fork!
|
|
116
|
+
|
|
117
|
+
def reset! = runtime.reset!
|
|
118
|
+
|
|
119
|
+
def close(timeout: Core::UNSET)
|
|
120
|
+
runtime.close(timeout: timeout)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def summary = runtime.summary
|
|
124
|
+
|
|
125
|
+
def start_execution(type:, **)
|
|
126
|
+
runtime.start_execution(type: type, **)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def thread(*, &)
|
|
130
|
+
raise ArgumentError, "block required" unless block_given?
|
|
131
|
+
|
|
132
|
+
envelope = Core::Propagation.capture_local
|
|
133
|
+
Thread.new(*) do |*thread_args|
|
|
134
|
+
with_cleared_configure_guard do
|
|
135
|
+
Core::Propagation.restore(envelope) { yield(*thread_args) }
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def with_execution(type:, **, &)
|
|
141
|
+
runtime.with_execution(type: type, **, &)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def punk_banner
|
|
147
|
+
"!!JULEWIRE PUNK!! chaos containment armed\n"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def punk_chaos_output(output, chaos)
|
|
151
|
+
options = chaos.is_a?(Hash) ? chaos : {}
|
|
152
|
+
Core::Destinations::ChaosOutput.new(output, **options)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def emit_with_severity(severity, record, fields, &)
|
|
156
|
+
if record.equal?(Core::UNSET)
|
|
157
|
+
fields.delete("severity")
|
|
158
|
+
fields[:severity] = severity
|
|
159
|
+
runtime.emit(fields, &)
|
|
160
|
+
elsif !block_given? && !record.is_a?(Hash)
|
|
161
|
+
# Scalar eager logs stay allocation-light; lazy inputs need the wrapper
|
|
162
|
+
# so block-built records can still receive the eager severity.
|
|
163
|
+
input = fields.empty? ? { message: record.to_s } : Core.emit_input(record, fields)
|
|
164
|
+
input.delete("severity")
|
|
165
|
+
input[:severity] = severity
|
|
166
|
+
runtime.emit(input)
|
|
167
|
+
else
|
|
168
|
+
runtime.emit(Core::Records::LazyEmitInput.with_severity(severity, Core.emit_input(record, fields)), &)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def with_cleared_configure_guard
|
|
173
|
+
previous_guard = Fiber[Core::Runtime::CONFIGURE_GUARD_KEY]
|
|
174
|
+
Fiber[Core::Runtime::CONFIGURE_GUARD_KEY] = nil
|
|
175
|
+
yield
|
|
176
|
+
ensure
|
|
177
|
+
Fiber[Core::Runtime::CONFIGURE_GUARD_KEY] = previous_guard
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
|
|
4
|
+
module Julewire
|
|
5
|
+
module Core
|
|
6
|
+
module Fields
|
|
7
|
+
# @api integration_spi
|
|
8
|
+
module AttributeKeys
|
|
9
|
+
HTTP_REQUEST_METHOD = :"http.request.method"
|
|
10
|
+
HTTP_RESPONSE_BODY_SIZE = :"http.response.body.size"
|
|
11
|
+
HTTP_RESPONSE_STATUS_CODE = :"http.response.status_code"
|
|
12
|
+
URL_FULL = :"url.full"
|
|
13
|
+
URL_PATH = :"url.path"
|
|
14
|
+
USER_AGENT_ORIGINAL = :"user_agent.original"
|
|
15
|
+
CLIENT_ADDRESS = :"client.address"
|
|
16
|
+
|
|
17
|
+
CODE_FILE_PATH = :"code.file.path"
|
|
18
|
+
CODE_FUNCTION_NAME = :"code.function.name"
|
|
19
|
+
CODE_LINE_NUMBER = :"code.line.number"
|
|
20
|
+
|
|
21
|
+
MESSAGING_BATCH_MESSAGE_COUNT = :"messaging.batch.message_count"
|
|
22
|
+
MESSAGING_CONSUMER_GROUP_NAME = :"messaging.consumer.group.name"
|
|
23
|
+
MESSAGING_DESTINATION_NAME = :"messaging.destination.name"
|
|
24
|
+
MESSAGING_DESTINATION_PARTITION_ID = :"messaging.destination.partition.id"
|
|
25
|
+
MESSAGING_KAFKA_MESSAGE_KEY = :"messaging.kafka.message.key"
|
|
26
|
+
MESSAGING_KAFKA_OFFSET = :"messaging.kafka.offset"
|
|
27
|
+
MESSAGING_OPERATION_NAME = :"messaging.operation.name"
|
|
28
|
+
MESSAGING_OPERATION_TYPE = :"messaging.operation.type"
|
|
29
|
+
MESSAGING_SYSTEM = :"messaging.system"
|
|
30
|
+
|
|
31
|
+
JOB_ENQUEUED_AT = :"job.enqueued_at"
|
|
32
|
+
JOB_EXECUTION_COUNT = :"job.execution_count"
|
|
33
|
+
JOB_ID = :"job.id"
|
|
34
|
+
JOB_NAME = :"job.name"
|
|
35
|
+
JOB_PRIORITY = :"job.priority"
|
|
36
|
+
JOB_PROVIDER_ID = :"job.provider_id"
|
|
37
|
+
JOB_QUEUE_NAME = :"job.queue.name"
|
|
38
|
+
JOB_SCHEDULED_AT = :"job.scheduled_at"
|
|
39
|
+
JOB_STATUS = :"job.status"
|
|
40
|
+
JOB_SYSTEM = :"job.system"
|
|
41
|
+
|
|
42
|
+
class << self
|
|
43
|
+
def fields(fields)
|
|
44
|
+
return {} unless fields.is_a?(Hash)
|
|
45
|
+
|
|
46
|
+
fields.compact
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def from(neutral) = neutral.is_a?(Hash) ? neutral : {}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Fields
|
|
6
|
+
# @api extension
|
|
7
|
+
module Bags
|
|
8
|
+
Definition = Data.define(
|
|
9
|
+
:name,
|
|
10
|
+
:record_hash,
|
|
11
|
+
:transform_container,
|
|
12
|
+
:app_write,
|
|
13
|
+
:integration_write,
|
|
14
|
+
:propagate,
|
|
15
|
+
:emit_by_default,
|
|
16
|
+
:delete_paths,
|
|
17
|
+
:stack
|
|
18
|
+
)
|
|
19
|
+
RECORD_SCALAR_KEYS = %i[
|
|
20
|
+
timestamp
|
|
21
|
+
severity
|
|
22
|
+
kind
|
|
23
|
+
event
|
|
24
|
+
message
|
|
25
|
+
logger
|
|
26
|
+
source
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def define(name, **capabilities)
|
|
33
|
+
Definition.new(
|
|
34
|
+
name: name,
|
|
35
|
+
record_hash: true,
|
|
36
|
+
transform_container: true,
|
|
37
|
+
app_write: false,
|
|
38
|
+
integration_write: false,
|
|
39
|
+
propagate: false,
|
|
40
|
+
emit_by_default: true,
|
|
41
|
+
delete_paths: false,
|
|
42
|
+
stack: false,
|
|
43
|
+
**capabilities
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
DEFINITIONS = {
|
|
49
|
+
execution: define(:execution, integration_write: true, propagate: true),
|
|
50
|
+
context: define(
|
|
51
|
+
:context,
|
|
52
|
+
app_write: true,
|
|
53
|
+
integration_write: true,
|
|
54
|
+
propagate: true,
|
|
55
|
+
stack: true
|
|
56
|
+
),
|
|
57
|
+
carry: define(
|
|
58
|
+
:carry,
|
|
59
|
+
app_write: true,
|
|
60
|
+
integration_write: true,
|
|
61
|
+
propagate: true,
|
|
62
|
+
emit_by_default: false,
|
|
63
|
+
delete_paths: true,
|
|
64
|
+
stack: true
|
|
65
|
+
),
|
|
66
|
+
neutral: define(:neutral, integration_write: true, emit_by_default: false, stack: true),
|
|
67
|
+
attributes: define(
|
|
68
|
+
:attributes,
|
|
69
|
+
app_write: true,
|
|
70
|
+
integration_write: true,
|
|
71
|
+
stack: true
|
|
72
|
+
),
|
|
73
|
+
labels: define(:labels),
|
|
74
|
+
payload: define(:payload),
|
|
75
|
+
metrics: define(:metrics),
|
|
76
|
+
error: define(:error, record_hash: false),
|
|
77
|
+
summary: define(
|
|
78
|
+
:summary,
|
|
79
|
+
record_hash: false,
|
|
80
|
+
transform_container: false,
|
|
81
|
+
integration_write: true,
|
|
82
|
+
emit_by_default: false
|
|
83
|
+
)
|
|
84
|
+
}.freeze
|
|
85
|
+
private_constant :Definition, :DEFINITIONS, :RECORD_SCALAR_KEYS
|
|
86
|
+
|
|
87
|
+
class << self
|
|
88
|
+
def definition(name) = DEFINITIONS.fetch(name)
|
|
89
|
+
|
|
90
|
+
def record_scalar_keys = RECORD_SCALAR_KEYS
|
|
91
|
+
|
|
92
|
+
def record_hash_sections = select_names(:record_hash)
|
|
93
|
+
|
|
94
|
+
def required_record_keys = (record_scalar_keys + record_hash_sections + %i[error]).freeze
|
|
95
|
+
|
|
96
|
+
def transform_container_sections = select_names(:transform_container)
|
|
97
|
+
|
|
98
|
+
def hidden_output_sections
|
|
99
|
+
DEFINITIONS.filter_map do |name, definition|
|
|
100
|
+
name if definition.record_hash && !definition.emit_by_default
|
|
101
|
+
end.freeze
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def app_write_sections = select_names(:app_write)
|
|
105
|
+
|
|
106
|
+
def integration_write_sections = select_names(:integration_write)
|
|
107
|
+
|
|
108
|
+
def propagation_sections = select_names(:propagate)
|
|
109
|
+
|
|
110
|
+
def stack_sections = select_names(:stack)
|
|
111
|
+
|
|
112
|
+
def delete_paths?(name) = definition(name).delete_paths
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def select_names(attribute)
|
|
117
|
+
DEFINITIONS.filter_map { |name, definition| name if definition.public_send(attribute) }.freeze
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Fields
|
|
6
|
+
class CarryProxy < SectionProxy
|
|
7
|
+
def initialize(store) = super(store, :carry)
|
|
8
|
+
|
|
9
|
+
def delete(*path)
|
|
10
|
+
@store.delete_carry(path)
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def without(*path, &)
|
|
15
|
+
raise ArgumentError, "block required" unless block_given?
|
|
16
|
+
|
|
17
|
+
@store.without_carry(path, &)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module Core
|
|
5
|
+
module Fields
|
|
6
|
+
# @api integration_spi
|
|
7
|
+
module FieldSet
|
|
8
|
+
VALUE_KEY = :value
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
# Public ingress accepts String or Symbol keys. Core stores Symbol keys
|
|
12
|
+
# after normalization so extension contracts stay simple.
|
|
13
|
+
def coerce(fields = nil, keyword_fields = {}, invalid: :ignore)
|
|
14
|
+
coerced = {}
|
|
15
|
+
coerce_fields!(coerced, fields, invalid: invalid) unless fields.nil?
|
|
16
|
+
merge!(coerced, keyword_fields) unless keyword_fields.empty?
|
|
17
|
+
coerced
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def merge(left, right)
|
|
21
|
+
merge!(deep_symbolize_keys(left), right)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def merge!(target, fields)
|
|
25
|
+
return target unless fields.is_a?(Hash)
|
|
26
|
+
|
|
27
|
+
fields.each do |key, value|
|
|
28
|
+
target[Fields::Internal.normalize_key(key)] = copy_field_value(value)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
target
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deep_dup(value)
|
|
35
|
+
return {} if value.is_a?(Hash) && value.empty?
|
|
36
|
+
return [] if value.is_a?(Array) && value.empty?
|
|
37
|
+
|
|
38
|
+
Serialization::ValueCopy.call(value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def deep_symbolize_keys(value)
|
|
42
|
+
return {} if value.is_a?(Hash) && value.empty?
|
|
43
|
+
return [] if value.is_a?(Array) && value.empty?
|
|
44
|
+
|
|
45
|
+
Serialization::ValueCopy.call(value, symbolize_keys: true)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def frozen_copy(value)
|
|
49
|
+
Fields::Internal.frozen_copy(value)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def value_for(hash, key, default: nil)
|
|
53
|
+
return default unless hash.is_a?(Hash)
|
|
54
|
+
|
|
55
|
+
normalized = key.is_a?(String) ? Fields::Internal.normalize_key(key) : key
|
|
56
|
+
return hash[normalized] if hash.key?(normalized)
|
|
57
|
+
|
|
58
|
+
default
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def coerce_fields!(target, fields, invalid:)
|
|
64
|
+
if fields.is_a?(Hash)
|
|
65
|
+
merge!(target, fields)
|
|
66
|
+
elsif invalid == :wrap
|
|
67
|
+
target[VALUE_KEY] = deep_dup(fields)
|
|
68
|
+
elsif invalid == :raise
|
|
69
|
+
raise ArgumentError, "fields must be a Hash"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def copy_field_value(value) = deep_symbolize_keys(value)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|