use crate::event_bus::EventBus;
use crate::observer::TracingGraphObserver;
use crate::store::InMemoryTracingStore;
use crate::types::TraceStatus;
use langgraph_checkpoint::config::RunnableConfig;
use serde_json::Value as JsonValue;
use std::sync::Arc;
pub struct TracingContext {
store: Arc<InMemoryTracingStore>,
event_bus: EventBus,
observer: TracingGraphObserver,
}
impl TracingContext {
pub fn observer(&mut self) -> &mut TracingGraphObserver {
&mut self.observer
}
pub fn store(&self) -> &Arc<InMemoryTracingStore> {
&self.store
}
pub fn event_bus(&self) -> &EventBus {
&self.event_bus
}
pub fn new() -> Self {
let store = Arc::new(InMemoryTracingStore::new());
let event_bus = EventBus::new();
let observer = TracingGraphObserver::new(store.clone(), event_bus.clone());
Self {
store,
event_bus,
observer,
}
}
pub fn start_server(&self, addr: &str) {
let store = self.store.clone();
let event_bus = self.event_bus.clone();
let addr = addr.to_string();
tokio::spawn(async move {
crate::server::start(
&addr,
store,
event_bus,
Some("crates/langgraph-tracing/frontend/dist"),
)
.await
.unwrap();
});
}
pub async fn run_with_tracing<F, Fut>(
&mut self,
name: &str,
input: JsonValue,
base_config: RunnableConfig,
f: F,
) -> JsonValue
where
F: FnOnce(RunnableConfig) -> Fut,
Fut: std::future::Future<Output = JsonValue>,
{
let trace_id = self.observer.on_graph_start(name, input);
let mut config = base_config;
let configurable = config
.entry("configurable".to_string())
.or_insert_with(|| serde_json::json!({}));
if let Some(obj) = configurable.as_object_mut() {
obj.insert("trace_id".to_string(), serde_json::json!(trace_id));
}
let output = f(config).await;
self.observer
.on_graph_end(&trace_id, output.clone(), TraceStatus::Success);
output
}
}
impl Default for TracingContext {
fn default() -> Self {
Self::new()
}
}