logforth_core/logger/builder.rs
1// Copyright 2024 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::Append;
16use crate::Diagnostic;
17use crate::Filter;
18use crate::Logger;
19use crate::logger::log_impl::Dispatch;
20
21/// Create a new empty [`LoggerBuilder`] instance for configuring log dispatching.
22///
23/// # Examples
24///
25/// ```
26/// use logforth_core::append;
27///
28/// let logger = logforth_core::builder()
29/// .dispatch(|d| d.append(append::Stderr::default()))
30/// .build();
31/// ```
32pub fn builder() -> LoggerBuilder {
33 LoggerBuilder { dispatches: vec![] }
34}
35
36/// A builder for configuring log dispatching.
37///
38/// # Examples
39///
40/// ```
41/// use logforth_core::append;
42///
43/// let logger = logforth_core::builder()
44/// .dispatch(|d| d.append(append::Stdout::default()))
45/// .build();
46/// ```
47#[must_use = "call `build` to construct a logger instance"]
48#[derive(Debug)]
49pub struct LoggerBuilder {
50 // stashed dispatches
51 dispatches: Vec<Dispatch>,
52}
53
54impl LoggerBuilder {
55 /// Register a new dispatch with the [`LoggerBuilder`].
56 ///
57 /// # Examples
58 ///
59 /// ```
60 /// use logforth_core::append;
61 ///
62 /// let logger = logforth_core::builder()
63 /// .dispatch(|d| d.append(append::Stderr::default()))
64 /// .build();
65 /// ```
66 pub fn dispatch<F>(mut self, f: F) -> Self
67 where
68 F: FnOnce(DispatchBuilder<false>) -> DispatchBuilder<true>,
69 {
70 self.dispatches.push(f(DispatchBuilder::new()).build());
71 self
72 }
73
74 /// Build the [`Logger`].
75 ///
76 /// # Examples
77 ///
78 /// ```
79 /// use logforth_core::record::Record;
80 ///
81 /// let l = logforth_core::builder().build();
82 /// let r = Record::builder()
83 /// .payload(format_args!("hello world!"))
84 /// .build();
85 /// l.log(&r);
86 /// ```
87 pub fn build(self) -> Logger {
88 Logger::new(self.dispatches)
89 }
90}
91
92/// A builder for configuring a log dispatch, including filters and appenders.
93///
94/// # Examples
95///
96/// ```
97/// use logforth_core::append;
98/// use logforth_core::record::Level;
99/// use logforth_core::record::LevelFilter;
100///
101/// let logger = logforth_core::builder()
102/// .dispatch(|d| {
103/// d.filter(LevelFilter::MoreSevereEqual(Level::Info))
104/// .append(append::Stdout::default())
105/// })
106/// .build();
107/// ```
108#[derive(Debug)]
109pub struct DispatchBuilder<const APPEND: bool> {
110 filters: Vec<Box<dyn Filter>>,
111 diagnostics: Vec<Box<dyn Diagnostic>>,
112 appends: Vec<Box<dyn Append>>,
113}
114
115impl DispatchBuilder<false> {
116 fn new() -> Self {
117 DispatchBuilder {
118 filters: vec![],
119 diagnostics: vec![],
120 appends: vec![],
121 }
122 }
123
124 /// Add a filter to this dispatch.
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// use logforth_core::append;
130 /// use logforth_core::record::Level;
131 /// use logforth_core::record::LevelFilter;
132 ///
133 /// let logger = logforth_core::builder()
134 /// .dispatch(|d| {
135 /// d.filter(LevelFilter::MoreSevereEqual(Level::Error))
136 /// .append(append::Stderr::default())
137 /// })
138 /// .build();
139 /// ```
140 pub fn filter(mut self, filter: impl Into<Box<dyn Filter>>) -> Self {
141 self.filters.push(filter.into());
142 self
143 }
144
145 /// Add a diagnostic to this dispatch.
146 ///
147 /// # Examples
148 ///
149 /// ```
150 /// use logforth_core::append;
151 /// use logforth_core::diagnostic;
152 /// use logforth_core::record::Level;
153 /// use logforth_core::record::LevelFilter;
154 ///
155 /// let logger = logforth_core::builder()
156 /// .dispatch(|d| {
157 /// d.filter(LevelFilter::MoreSevereEqual(Level::Error))
158 /// .diagnostic(diagnostic::ThreadLocalDiagnostic::default())
159 /// .append(append::Stderr::default())
160 /// })
161 /// .build();
162 /// ```
163 pub fn diagnostic(mut self, diagnostic: impl Into<Box<dyn Diagnostic>>) -> Self {
164 self.diagnostics.push(diagnostic.into());
165 self
166 }
167}
168
169impl DispatchBuilder<true> {
170 fn build(self) -> Dispatch {
171 Dispatch::new(self.filters, self.diagnostics, self.appends)
172 }
173}
174
175impl<const APPEND: bool> DispatchBuilder<APPEND> {
176 /// Add an appender to this dispatch.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// use logforth_core::append;
182 ///
183 /// let logger = logforth_core::builder()
184 /// .dispatch(|d| d.append(append::Stdout::default()))
185 /// .build();
186 /// ```
187 pub fn append(mut self, append: impl Into<Box<dyn Append>>) -> DispatchBuilder<true> {
188 self.appends.push(append.into());
189 DispatchBuilder {
190 filters: self.filters,
191 diagnostics: self.diagnostics,
192 appends: self.appends,
193 }
194 }
195}