Class: Flare::Marker
- Inherits:
-
Object
- Object
- Flare::Marker
- Defined in:
- lib/flare/marker.rb
Overview
Thread-safe registry of trace_ids that Path 2 (the WebMarkerSubscriber) has marked for export. FilteringSpanProcessor checks marked? on every on_finish; matching spans get forwarded to the trace exporter, the rest are dropped.
Each entry records the OWNER span_id (the local rack server span the subscriber was inside when it marked the trace). Cleanup is keyed on the owner finishing, not the trace root finishing – remote-parented rack spans aren’t trace roots, and child spans can outlive their parent in OTel, so root-driven cleanup would leak on the dominant production case (web app behind a load balancer or service mesh).
Bounded by:
- sweep(): drops entries older than max_age (default 5 min) so a rack
span that never finishes (process killed mid-request, exception path
that skips ensure) doesn't leak forever.
- hard ceiling at max_entries (default 10k): on overflow, drop oldest
10% by marked_at.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- DEFAULT_MAX_ENTRIES =
10_000- DEFAULT_MAX_AGE =
seconds
5 * 60
Instance Attribute Summary collapse
-
#evicted_count ⇒ Object
readonly
Returns the value of attribute evicted_count.
Instance Method Summary collapse
-
#initialize(max_entries: DEFAULT_MAX_ENTRIES, max_age: DEFAULT_MAX_AGE) ⇒ Marker
constructor
A new instance of Marker.
- #mark(trace_id, owner_span_id:, rule_id:) ⇒ Object
- #marked?(trace_id) ⇒ Boolean
-
#owner?(trace_id, span_id) ⇒ Boolean
True only when span_id matches the marker’s owner – the rack span that originally marked this trace.
- #rule_id(trace_id) ⇒ Object
- #size ⇒ Object
-
#sweep ⇒ Object
Drop entries older than max_age.
- #unmark(trace_id) ⇒ Object
Constructor Details
#initialize(max_entries: DEFAULT_MAX_ENTRIES, max_age: DEFAULT_MAX_AGE) ⇒ Marker
Returns a new instance of Marker.
33 34 35 36 37 38 |
# File 'lib/flare/marker.rb', line 33 def initialize(max_entries: DEFAULT_MAX_ENTRIES, max_age: DEFAULT_MAX_AGE) @entries = Concurrent::Map.new @max_entries = max_entries @max_age = max_age @evicted_count = Concurrent::AtomicFixnum.new(0) end |
Instance Attribute Details
#evicted_count ⇒ Object (readonly)
Returns the value of attribute evicted_count.
31 32 33 |
# File 'lib/flare/marker.rb', line 31 def evicted_count @evicted_count end |
Instance Method Details
#mark(trace_id, owner_span_id:, rule_id:) ⇒ Object
40 41 42 43 44 45 46 47 |
# File 'lib/flare/marker.rb', line 40 def mark(trace_id, owner_span_id:, rule_id:) @entries[trace_id] = Entry.new( owner_span_id: owner_span_id, rule_id: rule_id, marked_at: monotonic_now ) maybe_evict_oldest end |
#marked?(trace_id) ⇒ Boolean
49 50 51 |
# File 'lib/flare/marker.rb', line 49 def marked?(trace_id) @entries.key?(trace_id) end |
#owner?(trace_id, span_id) ⇒ Boolean
True only when span_id matches the marker’s owner – the rack span that originally marked this trace. Used by FilteringSpanProcessor to decide when to unmark (only when that exact span finishes, not on every span that happens to have this trace_id).
57 58 59 60 |
# File 'lib/flare/marker.rb', line 57 def owner?(trace_id, span_id) entry = @entries[trace_id] !entry.nil? && entry.owner_span_id == span_id end |
#rule_id(trace_id) ⇒ Object
62 63 64 65 |
# File 'lib/flare/marker.rb', line 62 def rule_id(trace_id) entry = @entries[trace_id] entry&.rule_id end |
#size ⇒ Object
71 72 73 |
# File 'lib/flare/marker.rb', line 71 def size @entries.size end |
#sweep ⇒ Object
Drop entries older than max_age. Call periodically (the RuleManager’s scheduler is the natural place) to handle the rack-span-never-finishes leak case (CAF-7).
78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/flare/marker.rb', line 78 def sweep threshold = monotonic_now - @max_age evicted = 0 @entries.each_pair do |trace_id, entry| if entry.marked_at < threshold @entries.delete(trace_id) evicted += 1 end end @evicted_count.increment(evicted) if evicted.positive? evicted end |
#unmark(trace_id) ⇒ Object
67 68 69 |
# File 'lib/flare/marker.rb', line 67 def unmark(trace_id) @entries.delete(trace_id) end |