Skip to main content

basalt_api/
logger.rs

1//! Plugin logger with automatic target prefixing.
2//!
3//! The [`PluginLogger`] wraps the `log` crate and automatically
4//! sets the log target to `basalt::plugin::<name>`, ensuring
5//! consistent, filterable log output across all plugins.
6
7use std::fmt;
8
9/// A logger scoped to a specific plugin.
10///
11/// Obtained via [`Context::logger()`](crate::context::Context::logger).
12/// All messages are logged with target `basalt::plugin::<name>`,
13/// making them easy to filter in log output.
14///
15/// Methods accept `impl Display`, so formatting is deferred until
16/// the log level is checked — no allocation if the level is filtered.
17///
18/// # Example
19///
20/// ```ignore
21/// registrar.on::<PlayerJoinedEvent>(Stage::Post, 0, |event, ctx| {
22///     let log = ctx.logger();
23///     log.info(format_args!("{} joined", event.info.username));
24///     log.debug("sending welcome message");
25/// });
26/// ```
27pub struct PluginLogger {
28    target: String,
29}
30
31impl PluginLogger {
32    /// Creates a new logger for the given plugin name.
33    pub fn new(plugin_name: &str) -> Self {
34        Self {
35            target: format!("basalt::plugin::{plugin_name}"),
36        }
37    }
38
39    /// Logs at ERROR level.
40    pub fn error(&self, msg: impl fmt::Display) {
41        log::log!(target: &self.target, log::Level::Error, "{msg}");
42    }
43
44    /// Logs at WARN level.
45    pub fn warn(&self, msg: impl fmt::Display) {
46        log::log!(target: &self.target, log::Level::Warn, "{msg}");
47    }
48
49    /// Logs at INFO level.
50    pub fn info(&self, msg: impl fmt::Display) {
51        log::log!(target: &self.target, log::Level::Info, "{msg}");
52    }
53
54    /// Logs at DEBUG level.
55    pub fn debug(&self, msg: impl fmt::Display) {
56        log::log!(target: &self.target, log::Level::Debug, "{msg}");
57    }
58
59    /// Logs at TRACE level.
60    pub fn trace(&self, msg: impl fmt::Display) {
61        log::log!(target: &self.target, log::Level::Trace, "{msg}");
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn logger_target_format() {
71        let logger = PluginLogger::new("chat");
72        assert_eq!(logger.target, "basalt::plugin::chat");
73    }
74
75    #[test]
76    fn logger_does_not_panic() {
77        let logger = PluginLogger::new("test");
78        // These should not panic even without a logger initialized
79        logger.error("test error");
80        logger.warn("test warn");
81        logger.info("test info");
82        logger.debug("test debug");
83        logger.trace("test trace");
84    }
85}