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}