steel_utils/logger/
mod.rs1use std::{
2 fmt::{self, Debug, Display, Formatter, Write},
3 sync::{Arc, OnceLock},
4};
5use tracing::field::{Field, Visit};
6
7pub static STEEL_LOGGER: OnceLock<Arc<dyn SteelLogger>> = OnceLock::new();
10
11pub enum Level {
13 Tracing(tracing::Level),
15 Console,
17 Chat(String),
19 Command(String),
21}
22impl Display for Level {
23 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
24 write!(
25 f,
26 "{}",
27 match self {
28 Level::Tracing(level) => match *level {
29 tracing::Level::ERROR => "\x1b[0;1;31m[Error]\x1b[0m".to_string(),
30 tracing::Level::WARN => "\x1b[0;1;33m[Warn]\x1b[0m".to_string(),
31 tracing::Level::INFO => "\x1b[0;1;34m[Info]\x1b[0m".to_string(),
32 tracing::Level::DEBUG => "\x1b[0;1;32m[Debug]\x1b[0m".to_string(),
33 tracing::Level::TRACE => "\x1b[0;1;90m[Trace]\x1b[0m".to_string(),
34 },
35 Level::Console => "\x1b[0;1;35m[Console]\x1b[0m".to_string(),
36 Level::Chat(name) => format!("\x1b[0;36m[Chat: {name}]\x1b[0m"),
37 Level::Command(name) => format!("\x1b[0;35m[Command: {name}]\x1b[0m"),
38 }
39 )
40 }
41}
42
43#[macro_export]
45macro_rules! console {
46 ($($arg:tt)+) =>
47 ($crate::logger::STEEL_LOGGER.get().expect("Steel logger isn't initialized!").log(
48 $crate::logger::Level::Console,
49 $crate::logger::LogData::message(format!($($arg)+)),
50 ));
51}
52#[macro_export]
54macro_rules! chat {
55 ($player:expr,$($arg:tt)+) =>
56 ($crate::logger::STEEL_LOGGER.get().expect("Steel logger isn't initialized!").log(
57 $crate::logger::Level::Chat($player),
58 $crate::logger::LogData::message(format!($($arg)+)),
59 ));
60}
61#[macro_export]
63macro_rules! command {
64 ($player:expr,$($arg:tt)+) =>
65 ($crate::logger::STEEL_LOGGER.get().expect("Steel logger isn't initialized!").log(
66 $crate::logger::Level::Command($player),
67 $crate::logger::LogData::message(format!($($arg)+)),
68 ));
69}
70
71#[derive(Default)]
73pub struct LogData {
74 pub message: String,
76 pub module_path: String,
78 pub extra: String,
80}
81
82impl LogData {
83 #[must_use]
85 pub const fn new() -> Self {
86 Self {
87 message: String::new(),
88 module_path: String::new(),
89 extra: String::new(),
90 }
91 }
92 #[must_use]
94 pub fn message(msg: String) -> Self {
95 Self {
96 message: msg,
97 module_path: module_path!().to_string(),
98 extra: String::new(),
99 }
100 }
101}
102
103impl Visit for LogData {
104 fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
105 match field.name() {
106 "message" => {
107 write!(self.message, "{value:?}").ok();
108 }
109 "log.module_path" => {
110 write!(self.module_path, "{value:?}").ok();
111 }
112 "log.target" => (),
113 name => {
114 write!(self.extra, " ({name}: {value:?})").ok();
115 }
116 }
117 }
118
119 fn record_str(&mut self, field: &Field, value: &str) {
120 match field.name() {
121 "message" => {
122 write!(self.message, "{value}").ok();
123 }
124 "log.module_path" => {
125 write!(self.module_path, "{value}").ok();
126 }
127 "log.target" => (),
128 name => {
129 write!(self.extra, " ({name}: {value})").ok();
130 }
131 }
132 }
133}
134
135pub trait SteelLogger: Send + Sync {
137 fn log(&self, level: Level, data: LogData);
139}