scouter_types/
span_capture.rs1use crate::trace::{TraceSpanRecord, SCOUTER_EVAL_SCENARIO_ID_ATTR};
2use crate::TraceId as ScouterTraceId;
3use std::collections::{HashMap, HashSet};
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::RwLock;
6
7pub const CAPTURE_BUFFER_MAX: usize = 20_000;
8
9pub static CAPTURING: AtomicBool = AtomicBool::new(false);
11
12pub static CAPTURE_BUFFER: RwLock<Vec<TraceSpanRecord>> = RwLock::new(Vec::new());
14
15pub fn is_capturing() -> bool {
17 CAPTURING.load(Ordering::Acquire)
18}
19
20pub fn drain_captured_spans() -> Vec<TraceSpanRecord> {
22 std::mem::take(&mut *CAPTURE_BUFFER.write().unwrap_or_else(|p| p.into_inner()))
23}
24
25pub fn get_captured_spans_by_trace_ids(
28 trace_ids: &HashSet<ScouterTraceId>,
29) -> Vec<TraceSpanRecord> {
30 let buf = CAPTURE_BUFFER.read().unwrap_or_else(|p| p.into_inner());
31 buf.iter()
32 .filter(|span| trace_ids.contains(&span.trace_id))
33 .cloned()
34 .collect()
35}
36
37pub fn get_all_captured_spans() -> Vec<TraceSpanRecord> {
39 CAPTURE_BUFFER
40 .read()
41 .unwrap_or_else(|p| p.into_inner())
42 .clone()
43}
44
45pub fn get_spans_grouped_by_scenario_id(
56 scenario_ids: &HashSet<String>,
57) -> HashMap<String, Vec<TraceSpanRecord>> {
58 let buf = CAPTURE_BUFFER.read().unwrap_or_else(|p| p.into_inner());
59
60 let mut trace_to_scenario: HashMap<ScouterTraceId, String> = HashMap::new();
62 for span in buf.iter() {
63 for attr in &span.attributes {
64 if attr.key == SCOUTER_EVAL_SCENARIO_ID_ATTR {
65 if let Some(sid) = attr.value.as_str() {
66 if scenario_ids.contains(sid) {
67 trace_to_scenario.insert(span.trace_id, sid.to_string());
68 }
69 }
70 break;
71 }
72 }
73 }
74
75 let mut grouped: HashMap<String, Vec<TraceSpanRecord>> = HashMap::new();
77 for span in buf.iter() {
78 if let Some(sid) = trace_to_scenario.get(&span.trace_id) {
79 grouped.entry(sid.clone()).or_default().push(span.clone());
80 }
81 }
82 grouped
83}
84
85pub fn get_trace_ids_by_scenario_ids(scenario_ids: &HashSet<String>) -> HashSet<ScouterTraceId> {
89 let buf = CAPTURE_BUFFER.read().unwrap_or_else(|p| p.into_inner());
90 buf.iter()
91 .filter(|span| {
92 span.attributes.iter().any(|attr| {
93 attr.key == SCOUTER_EVAL_SCENARIO_ID_ATTR
94 && attr
95 .value
96 .as_str()
97 .map(|v| scenario_ids.contains(v))
98 .unwrap_or(false)
99 })
100 })
101 .map(|span| span.trace_id)
102 .collect()
103}