Skip to main content

rivet_logger/logger/
level.rs

1use std::str::FromStr;
2
3use super::LoggerError;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
6#[repr(u16)]
7pub enum Level {
8    Debug = 100,
9    Info = 200,
10    Notice = 250,
11    Warning = 300,
12    Error = 400,
13    Critical = 500,
14    Alert = 550,
15    Emergency = 600,
16}
17
18impl Level {
19    pub const fn as_str(self) -> &'static str {
20        match self {
21            Self::Debug => "DEBUG",
22            Self::Info => "INFO",
23            Self::Notice => "NOTICE",
24            Self::Warning => "WARNING",
25            Self::Error => "ERROR",
26            Self::Critical => "CRITICAL",
27            Self::Alert => "ALERT",
28            Self::Emergency => "EMERGENCY",
29        }
30    }
31
32    pub const fn value(self) -> u16 {
33        self as u16
34    }
35
36    pub const fn from_rfc_5424(level: u8) -> Option<Self> {
37        match level {
38            7 => Some(Self::Debug),
39            6 => Some(Self::Info),
40            5 => Some(Self::Notice),
41            4 => Some(Self::Warning),
42            3 => Some(Self::Error),
43            2 => Some(Self::Critical),
44            1 => Some(Self::Alert),
45            0 => Some(Self::Emergency),
46            _ => None,
47        }
48    }
49}
50
51impl TryFrom<u16> for Level {
52    type Error = LoggerError;
53
54    fn try_from(value: u16) -> Result<Self, LoggerError> {
55        match value {
56            100 => Ok(Self::Debug),
57            200 => Ok(Self::Info),
58            250 => Ok(Self::Notice),
59            300 => Ok(Self::Warning),
60            400 => Ok(Self::Error),
61            500 => Ok(Self::Critical),
62            550 => Ok(Self::Alert),
63            600 => Ok(Self::Emergency),
64            _ => Err(LoggerError::InvalidLevelValue(value.to_string())),
65        }
66    }
67}
68
69impl FromStr for Level {
70    type Err = LoggerError;
71
72    fn from_str(s: &str) -> Result<Self, Self::Err> {
73        let normalized = s.trim().to_ascii_lowercase();
74        match normalized.as_str() {
75            "debug" => Ok(Self::Debug),
76            "info" => Ok(Self::Info),
77            "notice" => Ok(Self::Notice),
78            "warning" | "warn" => Ok(Self::Warning),
79            "error" => Ok(Self::Error),
80            "critical" => Ok(Self::Critical),
81            "alert" => Ok(Self::Alert),
82            "emergency" => Ok(Self::Emergency),
83            _ => {
84                if let Ok(value) = normalized.parse::<u16>() {
85                    return value.into_level();
86                }
87                Err(LoggerError::InvalidLevelValue(s.to_string()))
88            }
89        }
90    }
91}
92
93pub trait IntoLevel {
94    fn into_level(self) -> Result<Level, LoggerError>;
95}
96
97impl IntoLevel for Level {
98    fn into_level(self) -> Result<Level, LoggerError> {
99        Ok(self)
100    }
101}
102
103impl IntoLevel for u8 {
104    fn into_level(self) -> Result<Level, LoggerError> {
105        if let Some(level) = Level::from_rfc_5424(self) {
106            return Ok(level);
107        }
108
109        Level::try_from(self as u16)
110    }
111}
112
113impl IntoLevel for u16 {
114    fn into_level(self) -> Result<Level, LoggerError> {
115        if let Some(level) = Level::from_rfc_5424(self as u8).filter(|_| self <= 7) {
116            return Ok(level);
117        }
118
119        Level::try_from(self)
120    }
121}
122
123impl IntoLevel for i32 {
124    fn into_level(self) -> Result<Level, LoggerError> {
125        if self < 0 {
126            return Err(LoggerError::InvalidLevelValue(self.to_string()));
127        }
128
129        (self as u16).into_level()
130    }
131}
132
133impl IntoLevel for &str {
134    fn into_level(self) -> Result<Level, LoggerError> {
135        self.parse()
136    }
137}
138
139impl IntoLevel for String {
140    fn into_level(self) -> Result<Level, LoggerError> {
141        self.as_str().into_level()
142    }
143}