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}