Skip to main content

trace_weft/
replay.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4use std::path::Path;
5use std::sync::Mutex;
6
7lazy_static::lazy_static! {
8    static ref REPLAY_CONTEXT: Mutex<Option<ReplayConfig>> = Mutex::new(None);
9}
10
11#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12pub struct ReplayConfig {
13    #[serde(default)]
14    pub mocked_spans: HashMap<String, Value>,
15    #[serde(default)]
16    pub mocked_span_ids: HashMap<String, Value>,
17    #[serde(default)]
18    pub block_side_effects: bool,
19}
20
21impl ReplayConfig {
22    pub fn load_from_env() -> Option<Self> {
23        if let Ok(path_str) = std::env::var("TRACE_WEFT_REPLAY_FILE") {
24            let path = Path::new(&path_str);
25            if path.exists()
26                && let Ok(content) = std::fs::read_to_string(path)
27            {
28                if let Ok(config) = serde_json::from_str::<Self>(&content) {
29                    tracing::info!("Loaded TraceWeft replay config from {}", path_str);
30                    return Some(config);
31                } else {
32                    tracing::error!("Failed to parse TraceWeft replay config at {}", path_str);
33                }
34            }
35        }
36        None
37    }
38}
39
40pub fn init_replay(config: ReplayConfig) {
41    if let Ok(mut ctx) = REPLAY_CONTEXT.lock() {
42        *ctx = Some(config);
43    }
44}
45
46pub fn get_mocked_output(span_id: &str, span_name: &str) -> Option<Value> {
47    if let Ok(ctx) = REPLAY_CONTEXT.lock()
48        && let Some(config) = ctx.as_ref()
49    {
50        return config
51            .mocked_span_ids
52            .get(span_id)
53            .or_else(|| config.mocked_spans.get(span_name))
54            .cloned();
55    }
56    None
57}