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}
42impl Debug for Level {
43 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
44 write!(
45 f,
46 "{}",
47 match self {
48 Level::Tracing(level) => match *level {
49 tracing::Level::ERROR => "[Error]".to_string(),
50 tracing::Level::WARN => "[Warn]".to_string(),
51 tracing::Level::INFO => "[Info]".to_string(),
52 tracing::Level::DEBUG => "[Debug]".to_string(),
53 tracing::Level::TRACE => "[Trace]".to_string(),
54 },
55 Level::Console => "[Console]".to_string(),
56 Level::Chat(name) => format!("[Chat: {name}]"),
57 Level::Command(name) => format!("[Command: {name}]"),
58 }
59 )
60 }
61}
62
63#[macro_export]
65macro_rules! console {
66 ($($arg:tt)+) =>
67 ($crate::logger::STEEL_LOGGER.get().expect("Steel logger isn't initialized!").log(
68 $crate::logger::Level::Console,
69 $crate::logger::LogData::message(format!($($arg)+)),
70 ));
71}
72#[macro_export]
74macro_rules! chat {
75 ($player:expr,$($arg:tt)+) =>
76 ($crate::logger::STEEL_LOGGER.get().expect("Steel logger isn't initialized!").log(
77 $crate::logger::Level::Chat($player),
78 $crate::logger::LogData::message(format!($($arg)+)),
79 ));
80}
81#[macro_export]
83macro_rules! command {
84 ($player:expr,$($arg:tt)+) =>
85 ($crate::logger::STEEL_LOGGER.get().expect("Steel logger isn't initialized!").log(
86 $crate::logger::Level::Command($player),
87 $crate::logger::LogData::message(format!($($arg)+)),
88 ));
89}
90
91#[derive(Default)]
93pub struct LogData {
94 pub message: String,
96 pub module_path: String,
98 pub extra: String,
100}
101
102impl LogData {
103 #[must_use]
105 pub const fn new() -> Self {
106 Self {
107 message: String::new(),
108 module_path: String::new(),
109 extra: String::new(),
110 }
111 }
112 #[must_use]
114 pub fn message(msg: String) -> Self {
115 Self {
116 message: msg,
117 module_path: module_path!().to_string(),
118 extra: String::new(),
119 }
120 }
121}
122
123impl Visit for LogData {
124 fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
125 match field.name() {
126 "message" => {
127 write!(self.message, "{value:?}").ok();
128 }
129 "log.module_path" => {
130 write!(self.module_path, "{value:?}").ok();
131 }
132 "log.target" => (),
133 name => {
134 write!(self.extra, " ({name}: {value:?})").ok();
135 }
136 }
137 }
138
139 fn record_str(&mut self, field: &Field, value: &str) {
140 match field.name() {
141 "message" => {
142 write!(self.message, "{value}").ok();
143 }
144 "log.module_path" => {
145 write!(self.module_path, "{value}").ok();
146 }
147 "log.target" => (),
148 name => {
149 write!(self.extra, " ({name}: {value})").ok();
150 }
151 }
152 }
153}
154
155pub trait SteelLogger: Send + Sync {
157 fn log(&self, level: Level, data: LogData);
159}