Class: Datadog::OpenFeature::Hooks::SpanEnrichmentHook::SpanEnrichmentState
- Inherits:
-
Object
- Object
- Datadog::OpenFeature::Hooks::SpanEnrichmentHook::SpanEnrichmentState
- Defined in:
- lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb
Overview
Per-root-span state. Enforces the frozen limits, dedupes serial
ids structurally via a Set, and renders the three ffe_* tag shapes.
Not internally synchronized: every method is only ever called while the
owning SpanEnrichmentHook's mutex is held (capture, encode, cleanup),
so the state stays a plain object and the lock provides the
consistent snapshot at encode time.
Instance Method Summary collapse
-
#add_default(flag_key, value) ⇒ Object
valueis the flag's resolved runtime-default — any OpenFeature value type (String, boolean, number, or a structured Hash/Array). - #add_serial_id(serial_id) ⇒ Object
-
#add_subject(targeting_key, serial_id) ⇒ Object
Subject serial ids are NOT required to be a subset of the flag set: the frozen cross-SDK wire contract does not mandate
subjects ⊆ flags, so a subject may reference a serial id that the independent 200-flag cap dropped fromffe_flags_enc. -
#has_data? ⇒ Boolean
Subjects are intentionally not checked: a subject is only ever added alongside a serial id, so serial ids cover that case.
-
#initialize ⇒ SpanEnrichmentState
constructor
A new instance of SpanEnrichmentState.
- #to_span_tags ⇒ Object
Constructor Details
#initialize ⇒ SpanEnrichmentState
Returns a new instance of SpanEnrichmentState.
20 21 22 23 24 |
# File 'lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb', line 20 def initialize @serial_ids = Set.new @subjects = {} # sha256hex => Set<int> @defaults = {} # flag_key => String end |
Instance Method Details
#add_default(flag_key, value) ⇒ Object
value is the flag's resolved runtime-default — any OpenFeature
value type (String, boolean, number, or a structured Hash/Array).
Non-strings are JSON-encoded (not to_s) so a structured default is
captured faithfully rather than as Ruby's inspect form (e.g.
{"a"=>1}, which is not valid JSON). The result is a bounded
diagnostic PREVIEW, not a round-trippable value: it is truncated to
the frozen 64-char cap, so a long JSON string is intentionally left
as a non-parseable prefix. The backend treats this field as a
display string, so a clipped value is acceptable.
62 63 64 65 66 67 68 69 70 |
# File 'lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb', line 62 def add_default(flag_key, value) return if @defaults.key?(flag_key) # first-wins return if @defaults.size >= MAX_DEFAULTS value_str = value.is_a?(String) ? value : JSON.generate(value) # Slicing is by codepoint, so a multibyte UTF-8 character is never # split; `|| value_str` keeps the value non-nil for the zero-start slice. @defaults[flag_key] = value_str[0, MAX_DEFAULT_VALUE_LENGTH] || value_str end |
#add_serial_id(serial_id) ⇒ Object
26 27 28 29 30 |
# File 'lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb', line 26 def add_serial_id(serial_id) return if @serial_ids.size >= MAX_SERIAL_IDS @serial_ids.add(serial_id) end |
#add_subject(targeting_key, serial_id) ⇒ Object
Subject serial ids are NOT required to be a subset of the flag set:
the frozen cross-SDK wire contract does not mandate subjects ⊆ flags,
so a subject may reference a serial id that the independent 200-flag cap
dropped from ffe_flags_enc. This mirrors the reference implementation
and every other SDK; the caps (200 flags, 10 subjects, 20 experiments)
are applied independently on purpose.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb', line 38 def add_subject(targeting_key, serial_id) hashed = Codec.hash_targeting_key(targeting_key) existing = @subjects[hashed] if existing return if existing.size >= MAX_EXPERIMENTS_PER_SUBJECT existing.add(serial_id) elsif @subjects.size >= MAX_SUBJECTS nil else @subjects[hashed] = Set[serial_id] end end |
#has_data? ⇒ Boolean
Subjects are intentionally not checked: a subject is only ever added alongside a serial id, so serial ids cover that case.
74 75 76 |
# File 'lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb', line 74 def has_data? @serial_ids.any? || @defaults.any? end |
#to_span_tags ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb', line 78 def = {} [TAG_FLAGS_ENC] = Codec.encode_delta_varint(@serial_ids) if @serial_ids.any? if @subjects.any? encoded_subjects = {} @subjects.each { |hashed, ids| encoded_subjects[hashed] = Codec.encode_delta_varint(ids) } [TAG_SUBJECTS_ENC] = JSON.generate(encoded_subjects) end [TAG_RUNTIME_DEFAULTS] = JSON.generate(@defaults) if @defaults.any? end |