Skip to main content
Glama
logging.rs4.05 kB
#[macro_export] /// This is a really simple macro to assert a snapshot of the logs. /// To use it call `.with_subscriber(assert_snapshot_subscriber!())` in your test just before calling `await`. /// This will assert a snapshot of the logs in pretty yaml format. /// You can also use subscriber::with_default(assert_snapshot_subscriber!(), || { ... }) to assert the logs in non async code. macro_rules! assert_snapshot_subscriber { () => { $crate::assert_snapshot_subscriber!(tracing_core::LevelFilter::INFO, {}) }; ($redactions:tt) => { $crate::assert_snapshot_subscriber!(tracing_core::LevelFilter::INFO, $redactions) }; ($level:expr) => { $crate::assert_snapshot_subscriber!($level, {}) }; ($level:expr, $redactions:tt) => { $crate::logging::test::SnapshotSubscriber::create_subscriber($level, |yaml| { insta::with_settings!({sort_maps => true}, { // the tests here will force maps to sort let mut settings = insta::Settings::clone_current(); settings.set_snapshot_suffix("logs"); settings.set_sort_maps(true); settings.bind(|| { insta::assert_yaml_snapshot!(yaml, $redactions); }); }); }) }; } #[cfg(test)] pub(crate) mod test { use std::sync::Arc; use std::sync::Mutex; use serde_json::Value; use tracing_core::LevelFilter; use tracing_core::Subscriber; use tracing_subscriber::layer::SubscriberExt; pub(crate) struct SnapshotSubscriber { buffer: Arc<Mutex<Vec<u8>>>, assertion: fn(Value), } impl std::io::Write for SnapshotSubscriber { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { let buf_len = buf.len(); self.buffer.lock().unwrap().append(&mut buf.to_vec()); Ok(buf_len) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } impl Drop for SnapshotSubscriber { fn drop(&mut self) { let log = String::from_utf8(self.buffer.lock().unwrap().to_vec()).unwrap(); let parsed: Value = if log.is_empty() { serde_json::json!([]) } else { let parsed_log: Vec<Value> = log .lines() .map(|line| { let mut line: Value = serde_json::from_str(line).unwrap(); // move the message field to the top level let fields = line .as_object_mut() .unwrap() .get_mut("fields") .unwrap() .as_object_mut() .unwrap(); let message = fields.remove("message").unwrap_or_default(); line.as_object_mut() .unwrap() .insert("message".to_string(), message); line }) .collect(); serde_json::json!(parsed_log) }; (self.assertion)(parsed) } } impl SnapshotSubscriber { pub(crate) fn create_subscriber( level: LevelFilter, assertion: fn(Value), ) -> impl Subscriber { let collector = Self { buffer: Arc::new(Mutex::new(Vec::new())), assertion, }; tracing_subscriber::registry::Registry::default() .with(level) .with( tracing_subscriber::fmt::Layer::default() .json() .without_time() .with_target(false) .with_file(false) .with_line_number(false) .with_writer(Mutex::new(collector)), ) } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/apollographql/apollo-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server