pinenut_log/
record.rs

1//!  The `Pinenut` log record.
2
3use pinenut_derive::{Builder, Decode, Encode};
4
5/// Represents logging levels of a `Pinenut` log.
6///
7/// The default value in [`Meta`] is [`Level::Info`].
8#[repr(u8)]
9#[non_exhaustive]
10#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
11pub enum Level {
12    /// The `error` log level.
13    ///
14    /// It is typically the highest level of severity and is used when an operation
15    /// fails.
16    Error = 1,
17    /// The `warning` log level.
18    ///
19    /// It is used when something unexpected happened, or there might be a problem in
20    /// the near future.
21    Warn,
22    /// The `informational` log level.
23    ///
24    /// Infomational messages to track the general flow of the application.
25    Info,
26    /// The `debug` log level.
27    ///
28    /// Logs that contain information useful for debugging during development and
29    /// troubleshooting.
30    Debug,
31    /// The `verbose` log level.
32    ///
33    /// Logs may include more information than the `Debug` level and are usually not
34    /// enabled in a production environment.
35    Verbose,
36}
37
38impl Level {
39    /// Returns the underlying primitive representation.
40    #[inline]
41    pub(crate) fn primitive(&self) -> u8 {
42        *self as u8
43    }
44
45    /// Constructs from the underlying primitive representation.
46    pub(crate) fn from_primitive(value: u8) -> Option<Self> {
47        match value {
48            1 => Some(Self::Error),
49            2 => Some(Self::Warn),
50            3 => Some(Self::Info),
51            4 => Some(Self::Debug),
52            5 => Some(Self::Verbose),
53            _ => None,
54        }
55    }
56}
57
58/// Represents a location in the code where a `Pinenut` log was generated.
59///
60/// The default options are:
61///
62/// - [`Location::file`] : `None`
63/// - [`Location::func`] : `None`
64/// - [`Location::line`] : `None`
65///
66/// `Location` supports `Builder Pattern`, it can be constructed by
67/// `LocationBuilder`.
68#[derive(Encode, Decode, Builder, Default, Clone, PartialEq, Eq, Debug)]
69pub struct Location<'a> {
70    file: Option<&'a str>,
71    func: Option<&'a str>,
72    line: Option<u32>,
73}
74
75impl<'a> Location<'a> {
76    /// Constructs a new `Location`.
77    #[inline]
78    pub fn new(file: Option<&'a str>, func: Option<&'a str>, line: Option<u32>) -> Self {
79        Self { file, func, line }
80    }
81
82    /// The code file where the log was generated. `None` if not available.
83    #[inline]
84    pub fn file(&self) -> Option<&'a str> {
85        self.file
86    }
87
88    /// The function where the log was generated. `None` if not available.
89    #[inline]
90    pub fn func(&self) -> Option<&'a str> {
91        self.func
92    }
93
94    /// The code line in the file where the log was generated. `None` if not
95    /// available.
96    #[inline]
97    pub fn line(&self) -> Option<u32> {
98        self.line
99    }
100}
101
102/// Represents a date and time in the UTC time zone.
103pub type DateTime = chrono::DateTime<chrono::Utc>;
104
105/// Represents metadata associated with a `Pinenut` log.
106///
107/// The default options are:
108///
109/// - [`Meta::level`] : [`Level::Info`]
110/// - [`Meta::datetime`] : [`chrono::Utc::now()`]
111/// - [`Meta::location`] : [`Location::default()`]
112/// - [`Meta::tag`] : [`None`]
113/// - [`Meta::thread_id`] : [`None`]
114///
115/// `Meta` supports `Builder Pattern`, it can be constructed by `MetaBuilder`.
116#[derive(Encode, Decode, Builder, Clone, PartialEq, Eq, Debug)]
117pub struct Meta<'a> {
118    level: Level,
119    datetime: DateTime,
120    location: Location<'a>,
121    tag: Option<&'a str>,
122    thread_id: Option<u64>,
123}
124
125impl<'a> Meta<'a> {
126    /// Constructs a new `Meta`.
127    #[inline]
128    pub fn new(
129        level: Level,
130        datetime: DateTime,
131        location: Location<'a>,
132        tag: Option<&'a str>,
133        thread_id: Option<u64>,
134    ) -> Self {
135        Self { level, datetime, location, tag, thread_id }
136    }
137
138    /// The level of the log.
139    #[inline]
140    pub fn level(&self) -> Level {
141        self.level
142    }
143
144    /// The datetime when the log was generated.
145    #[inline]
146    pub fn datetime(&self) -> DateTime {
147        self.datetime
148    }
149
150    /// The location in the code where the log was generated.
151    #[inline]
152    pub fn location(&self) -> &Location<'a> {
153        &self.location
154    }
155
156    /// An optional tag associated with the log.
157    #[inline]
158    pub fn tag(&self) -> Option<&'a str> {
159        self.tag
160    }
161
162    /// The identifier of the thread where the log was generated.
163    #[inline]
164    pub fn thread_id(&self) -> Option<u64> {
165        self.thread_id
166    }
167}
168
169impl<'a> Default for Meta<'a> {
170    #[inline]
171    fn default() -> Self {
172        Meta::new(Level::Info, chrono::Utc::now(), Location::default(), None, None)
173    }
174}
175
176/// Represents a `Pinenut` log record.
177///
178/// `Record` supports `Builder Pattern`, it can be constructed by `RecordBuilder`.
179#[derive(Encode, Decode, Builder, Default, Clone, PartialEq, Eq, Debug)]
180pub struct Record<'a> {
181    meta: Meta<'a>,
182    content: &'a str,
183}
184
185impl<'a> Record<'a> {
186    /// Constructs a new `Record`.
187    #[inline]
188    pub fn new(meta: Meta<'a>, content: &'a str) -> Self {
189        Self { meta, content }
190    }
191
192    /// The metadata associated with the log.
193    #[inline]
194    pub fn meta(&self) -> &Meta<'a> {
195        &self.meta
196    }
197
198    /// The content of the log.
199    #[inline]
200    pub fn content(&self) -> &'a str {
201        self.content
202    }
203}