Pumpkin/crates/pumpkin-plugin-api/src/logging.rs
2026-08-08 13:44:51 +02:00

90 lines
3.1 KiB
Rust

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);
}