Class: Flare::Sampler
- Inherits:
-
Object
- Object
- Flare::Sampler
- Defined in:
- lib/flare/sampler.rb
Overview
Path 1 trace sampler. At span start, iterates active rules; returns RECORD_AND_SAMPLE when one matches and the deterministic trace_id_ratio falls under the rule’s rate. Otherwise RECORD_ONLY – the span still records so MetricSpanProcessor sees it; the trace export decision for web spans is deferred to Path 2 via Flare::Marker.
Used as the ‘root` sampler inside an OTel ParentBased sampler so root spans go through this logic but child spans inherit upstream decisions. The `local_parent_not_sampled` slot of the ParentBased should point at Flare::ALWAYS_RECORD_ONLY – the default ALWAYS_OFF would drop children of an unsampled local parent, making them NoOp spans the processors never see.
Rules are pushed in via update_rules from Flare::RuleManager; the swap is atomic, and malformed rule entries are dropped with a counter so a bad server payload can’t crash the tracing path.
Defined Under Namespace
Classes: Rule
Constant Summary collapse
- Decision =
OpenTelemetry::SDK::Trace::Samplers::Decision
- Result =
OpenTelemetry::SDK::Trace::Samplers::Result
- RULE_ID_ATTRIBUTE =
"flare.rule_id"
Instance Attribute Summary collapse
-
#dropped_rule_count ⇒ Object
readonly
Returns the value of attribute dropped_rule_count.
Instance Method Summary collapse
- #description ⇒ Object
-
#initialize ⇒ Sampler
constructor
A new instance of Sampler.
- #rules ⇒ Object
- #should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:) ⇒ Boolean
-
#trace_id_ratio(trace_id) ⇒ Object
Cross-language formula: last 8 bytes of the 16-byte raw trace_id as uint64-big-endian, divided by 2^64.
-
#update_rules(new_rules) ⇒ Object
new_rules: an array of rule hashes from GET /api/rules, e.g.
Constructor Details
#initialize ⇒ Sampler
Returns a new instance of Sampler.
33 34 35 36 |
# File 'lib/flare/sampler.rb', line 33 def initialize @rules_ref = Concurrent::AtomicReference.new([].freeze) @dropped_rule_count = Concurrent::AtomicFixnum.new(0) end |
Instance Attribute Details
#dropped_rule_count ⇒ Object (readonly)
Returns the value of attribute dropped_rule_count.
31 32 33 |
# File 'lib/flare/sampler.rb', line 31 def dropped_rule_count @dropped_rule_count end |
Instance Method Details
#description ⇒ Object
65 66 67 |
# File 'lib/flare/sampler.rb', line 65 def description "Flare::Sampler" end |
#rules ⇒ Object
47 48 49 |
# File 'lib/flare/sampler.rb', line 47 def rules @rules_ref.get end |
#should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:) ⇒ Boolean
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/flare/sampler.rb', line 51 def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:) tracestate = tracestate_from(parent_context) rules.each do |rule| next unless matches?(rule, attributes) next unless trace_id_ratio(trace_id) < rule.rate merged = (attributes || {}).merge(RULE_ID_ATTRIBUTE => rule.id) return Result.new(decision: Decision::RECORD_AND_SAMPLE, attributes: merged, tracestate: tracestate) end Result.new(decision: Decision::RECORD_ONLY, tracestate: tracestate) end |
#trace_id_ratio(trace_id) ⇒ Object
Cross-language formula: last 8 bytes of the 16-byte raw trace_id as uint64-big-endian, divided by 2^64. Same in every Flare SDK so the server can reproduce the decision if it ever needs to.
72 73 74 75 76 77 78 |
# File 'lib/flare/sampler.rb', line 72 def trace_id_ratio(trace_id) bytes = trace_id.is_a?(String) ? trace_id.bytes : Array(trace_id) tail = bytes.last(8) n = 0 tail.each { |b| n = (n << 8) | b } n.to_f / (1 << 64) end |
#update_rules(new_rules) ⇒ Object
new_rules: an array of rule hashes from GET /api/rules, e.g.
[{ "id" => 1, "match_attributes" => {...}, "rate" => 0.5 }, ...]
Entries that don’t validate are skipped (counted in dropped_rule_count).
41 42 43 44 45 |
# File 'lib/flare/sampler.rb', line 41 def update_rules(new_rules) validated = (new_rules || []).filter_map { |r| validate(r) } @dropped_rule_count.increment((new_rules || []).length - validated.length) @rules_ref.set(validated.freeze) end |