1use crate::exports::{log_to_file, log_to_window};
21use log::{Level, Log, Metadata, Record};
22
23#[derive(Debug, Clone)]
28pub struct ArcDpsLogger {
29 name: &'static str,
30}
31
32impl ArcDpsLogger {
33 #[inline]
35 pub const fn new(name: &'static str) -> Self {
36 Self { name }
37 }
38
39 fn window_enabled(metadata: &Metadata) -> bool {
41 metadata.target() != "file"
42 }
43
44 fn file_enabled(metadata: &Metadata) -> bool {
46 match metadata.target() {
47 "file" | "both" | "all" => true,
48 "window" => false,
49 _ => matches!(metadata.level(), Level::Warn | Level::Error),
50 }
51 }
52}
53
54impl Log for ArcDpsLogger {
55 fn enabled(&self, metadata: &Metadata) -> bool {
56 Self::window_enabled(metadata) || Self::file_enabled(metadata)
57 }
58
59 fn log(&self, record: &Record) {
60 let metadata = record.metadata();
61 if Self::window_enabled(metadata) {
62 WindowLogger { name: self.name }.log(record);
63 }
64 if Self::file_enabled(metadata) {
65 FileLogger { name: self.name }.log(record);
66 }
67 }
68
69 fn flush(&self) {}
70}
71
72#[derive(Debug, Clone)]
74pub struct WindowLogger {
75 name: &'static str,
76}
77
78impl WindowLogger {
79 #[inline]
81 pub const fn new(name: &'static str) -> Self {
82 Self { name }
83 }
84}
85
86impl Log for WindowLogger {
87 fn enabled(&self, _metadata: &Metadata) -> bool {
88 true
89 }
90
91 fn log(&self, record: &Record) {
92 let _ = log_to_window(format_message(self.name, record));
94 }
95
96 fn flush(&self) {}
97}
98
99#[derive(Debug, Clone)]
101pub struct FileLogger {
102 name: &'static str,
103}
104
105impl FileLogger {
106 #[inline]
108 pub const fn new(name: &'static str) -> Self {
109 Self { name }
110 }
111}
112
113impl Log for FileLogger {
114 fn enabled(&self, _metadata: &Metadata) -> bool {
115 true
116 }
117
118 fn log(&self, record: &Record) {
119 let _ = log_to_file(format_message(self.name, record));
120 }
121
122 fn flush(&self) {}
123}
124
125fn format_message(name: &'static str, record: &Record) -> String {
127 format!(
128 "{} {}: {}",
129 name,
130 record.level().to_string().to_lowercase(),
131 record.args()
132 )
133}
134
135#[cfg(test)]
136mod tests {
137 use super::ArcDpsLogger;
138 use log::{Level, Metadata};
139
140 #[test]
141 fn enabled() {
142 fn meta(target: &str, level: Level) -> Metadata {
143 Metadata::builder().target(target).level(level).build()
144 }
145
146 const MOD: &str = module_path!();
147
148 let info = meta(MOD, Level::Info);
149 assert!(ArcDpsLogger::window_enabled(&info));
150 assert!(!ArcDpsLogger::file_enabled(&info));
151
152 let warn = meta(MOD, Level::Warn);
153 assert!(ArcDpsLogger::window_enabled(&warn));
154 assert!(ArcDpsLogger::file_enabled(&warn));
155
156 let error = meta(MOD, Level::Error);
157 assert!(ArcDpsLogger::window_enabled(&error));
158 assert!(ArcDpsLogger::file_enabled(&error));
159
160 let info_file = meta("file", Level::Info);
161 assert!(!ArcDpsLogger::window_enabled(&info_file));
162 assert!(ArcDpsLogger::file_enabled(&info_file));
163
164 let info_both = meta("both", Level::Info);
165 assert!(ArcDpsLogger::window_enabled(&info_both));
166 assert!(ArcDpsLogger::file_enabled(&info_both));
167 }
168}