1use std::sync::Arc;
4
5#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
7pub enum LogLevel {
8 Trace,
10 Debug,
12 Info,
14 Warn,
16 Error,
18}
19
20#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct LogRecord {
23 level: LogLevel,
24 target: String,
25 message: String,
26}
27
28impl LogRecord {
29 #[must_use]
31 pub fn new(level: LogLevel, target: impl Into<String>, message: impl Into<String>) -> Self {
32 Self {
33 level,
34 target: target.into(),
35 message: message.into(),
36 }
37 }
38
39 #[must_use]
41 pub const fn level(&self) -> LogLevel {
42 self.level
43 }
44
45 #[must_use]
47 pub fn target(&self) -> &str {
48 &self.target
49 }
50
51 #[must_use]
53 pub fn message(&self) -> &str {
54 &self.message
55 }
56}
57
58pub trait LogSink: Send + Sync {
60 fn log(&self, record: &LogRecord);
62}
63
64#[derive(Debug, Default)]
66pub struct NoopLogSink;
67
68impl LogSink for NoopLogSink {
69 fn log(&self, _record: &LogRecord) {}
70}
71
72#[derive(Clone)]
74pub struct Logger {
75 sink: Arc<dyn LogSink>,
76}
77
78impl Logger {
79 #[must_use]
81 pub fn new(sink: Arc<dyn LogSink>) -> Self {
82 Self { sink }
83 }
84
85 pub fn emit(&self, record: &LogRecord) {
87 self.sink.log(record);
88 }
89
90 pub fn log(&self, level: LogLevel, target: impl Into<String>, message: impl Into<String>) {
92 self.emit(&LogRecord::new(level, target, message));
93 }
94}
95
96impl Default for Logger {
97 fn default() -> Self {
98 Self::new(Arc::new(NoopLogSink))
99 }
100}