use std::sync::atomic::{AtomicU64, Ordering}; use tracing_serde_structured::AsSerde; use crate::wit; /// A [`tracing::Subscriber`] that forwards events to the host server over WIT. /// /// Installed automatically as the global subscriber when the plugin is loaded. pub(crate) struct WitSubscriber { next_id: AtomicU64, } impl WitSubscriber { /// Creates a new `WitSubscriber` with the span ID counter starting at `1`. pub const fn new() -> Self { Self { next_id: AtomicU64::new(1), } } } impl tracing::Subscriber for WitSubscriber { /// Always returns `true` — all log levels are forwarded to the host. fn enabled(&self, _metadata: &tracing::Metadata<'_>) -> bool { true } /// Allocates a new monotonically increasing span ID. fn new_span(&self, _attrs: &tracing::span::Attributes<'_>) -> tracing::span::Id { let id = self.next_id.fetch_add(1, Ordering::Relaxed); tracing::span::Id::from_u64(id) } /// No-op — span field recording is not forwarded to the host. fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {} /// No-op — causality links are not forwarded to the host. fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {} /// Serialises the tracing event with `postcard` and sends it to the host via WIT. fn event(&self, event: &tracing::Event<'_>) { if let Ok(serialized) = postcard::to_allocvec(&event.as_serde()) { wit::pumpkin::plugin::logging::log_tracing(&serialized); } } /// No-op — span entry is not tracked. fn enter(&self, _span: &tracing::span::Id) {} /// No-op — span exit is not tracked. fn exit(&self, _span: &tracing::span::Id) {} } /// The log severity level used with [`log`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LogLevel { /// Very fine-grained diagnostic information. Trace, /// Diagnostic information useful during development. Debug, /// General informational messages. Info, /// Potentially harmful situations that do not stop execution. Warn, /// Errors that may require attention. Error, } impl LogLevel { /// Converts this level to the WIT-generated `Level` type expected by the host. const fn to_wit(self) -> wit::pumpkin::plugin::logging::Level { match self { Self::Trace => wit::pumpkin::plugin::logging::Level::Trace, Self::Debug => wit::pumpkin::plugin::logging::Level::Debug, Self::Info => wit::pumpkin::plugin::logging::Level::Info, Self::Warn => wit::pumpkin::plugin::logging::Level::Warn, Self::Error => wit::pumpkin::plugin::logging::Level::Error, } } } /// Sends a log message to the server at the given severity level. /// /// Prefer the standard `tracing` macros (`tracing::info!`, `tracing::warn!`, etc.) /// for structured logging; use this function when you need a direct, low-level log call. pub fn log(level: LogLevel, message: &str) { wit::pumpkin::plugin::logging::log(level.to_wit(), message); }