coaly/lib.rs
1// -----------------------------------------------------------------------------------------------
2// Coaly - context aware logging and tracing system
3//
4// Copyright (c) 2022, Frank Sommer.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are met:
9//
10// * Redistributions of source code must retain the above copyright notice, this
11// list of conditions and the following disclaimer.
12//
13// * Redistributions in binary form must reproduce the above copyright notice,
14// this list of conditions and the following disclaimer in the documentation
15// and/or other materials provided with the distribution.
16//
17// * Neither the name of the copyright holder nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31// -----------------------------------------------------------------------------------------------
32
33//! Coaly is a library for handling log and trace messages.
34//! Besides the usual levels indicating message severity it offers various formatting options
35//! and supports files, memory mapped files and remote servers over network as output resource.
36//! Advanced features are output buffering in main memory and configurable behaviour dependent
37//! on the location in the code. E.g. for one module or function all levels may be switched off,
38//! whereas for another messages of all levels are included in the output.
39//! The behaviour is entirely specified in a configuration file that is read once at application
40//! start and cannot be changed during runtime.
41
42#[macro_use]
43extern crate lazy_static;
44
45pub mod agent;
46pub mod collections;
47pub mod config;
48pub mod errorhandling;
49pub mod observer;
50pub mod output;
51pub mod util;
52mod datetime;
53mod event;
54mod modechange;
55mod policies;
56mod record;
57mod variables;
58
59use observer::ObserverData;
60pub use errorhandling::CoalyException;
61pub use record::originator::OriginatorInfo;
62pub use record::RecordLevelId;
63
64#[cfg(feature="net")]
65pub mod net;
66
67/// Result type used throughout the library for error handling
68pub type CoalyResult<T> = Result<T, CoalyException>;
69
70
71/// Initializes the system.
72///
73/// If the function has not been called prior to any message output, the system will assume
74/// default settings. This is also the case, if an error during configuration file processing
75/// occurs.
76/// Calling the function for an already initialized system has no effect.
77///
78/// # Arguments
79/// * `config_file_name` - the name of the configuration file
80#[inline]
81pub fn initialize(config_file_name: &str) { agent::initialize(config_file_name); }
82
83/// Terminates the system.
84#[inline]
85pub fn shutdown() { agent::shutdown(); }
86
87/// Writes a log message with level alert.
88///
89/// # Arguments
90/// * `msg` - the message
91#[macro_export]
92macro_rules! logalert {
93 ($msg: literal) => {
94 agent::write(RecordLevelId::Alert, std::file!(), std::line!(), $msg);
95 };
96 ($($arg:tt)+) => {
97 agent::write(RecordLevelId::Alert, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
98 }
99}
100
101/// Writes a log message with level critical.
102///
103/// # Arguments
104/// * `msg` - the message
105#[macro_export]
106macro_rules! logcrit {
107 ($msg: literal) => {
108 agent::write(RecordLevelId::Critical, std::file!(), std::line!(), $msg);
109 };
110 ($($arg:tt)+) => {
111 agent::write(RecordLevelId::Critical, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
112 }
113}
114
115/// Writes a trace message with level debug.
116///
117/// # Arguments
118/// * `msg` - the message
119#[macro_export]
120macro_rules! logdebug {
121 ($msg: literal) => {
122 agent::write(RecordLevelId::Debug, std::file!(), std::line!(), $msg);
123 };
124 ($($arg:tt)+) => {
125 agent::write(RecordLevelId::Debug, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
126 }
127}
128
129/// Writes a log message with level emergency.
130///
131/// # Arguments
132/// * `msg` - the message
133#[macro_export]
134macro_rules! logemgcy {
135 ($msg: literal) => {
136 agent::write(RecordLevelId::Emergency, std::file!(), std::line!(), $msg);
137 };
138 ($($arg:tt)+) => {
139 agent::write(RecordLevelId::Emergency, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
140 }
141}
142
143/// Writes a log message with level error.
144///
145/// # Arguments
146/// * `msg` - the message
147#[macro_export]
148macro_rules! logerror {
149 ($msg: literal) => {
150 agent::write(RecordLevelId::Error, std::file!(), std::line!(), $msg);
151 };
152 ($($arg:tt)+) => {
153 agent::write(RecordLevelId::Error, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
154 }
155}
156
157/// Writes a log message with level information.
158///
159/// # Arguments
160/// * `msg` - the message
161#[macro_export]
162macro_rules! loginfo {
163 ($msg: literal) => {
164 agent::write(RecordLevelId::Info, std::file!(), std::line!(), $msg);
165 };
166 ($($arg:tt)+) => {
167 agent::write(RecordLevelId::Info, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
168 }
169}
170
171/// Writes a trace message with level notice.
172///
173/// # Arguments
174/// * `msg` - the message
175#[macro_export]
176macro_rules! lognote {
177 ($msg: literal) => {
178 agent::write(RecordLevelId::Notice, std::file!(), std::line!(), $msg);
179 };
180 ($($arg:tt)+) => {
181 agent::write(RecordLevelId::Notice, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
182 }
183}
184
185/// Writes a log message with level warning.
186///
187/// # Arguments
188/// * `msg` - the message
189#[macro_export]
190macro_rules! logwarn {
191 ($msg: literal) => {
192 agent::write(RecordLevelId::Warning, std::file!(), std::line!(), $msg);
193 };
194 ($($arg:tt)+) => {
195 agent::write(RecordLevelId::Warning, std::file!(), std::line!(), &std::fmt::format(format_args!($($arg)+)));
196 }
197}
198
199/// Traces a function's boundaries.
200/// Writes immediately a record upon the entry of the function and another message upon
201/// leaving of the function using the drop method of the instantiated Coaly observer structure.
202/// Depending on the configuration, the system's behaviour may change after the function
203/// entry.
204/// Function parameters can optionally be traced by additional arguments separated with a comma.
205/// Each argument value must be convertible to a string.
206///
207/// # Arguments
208/// * `func_name` - the name of the function
209/// * `args` - optional the arguments of the function call, each argument prepended by a comma
210#[macro_export]
211macro_rules! logfn {
212 ($func_name: literal) => {
213 let _cfn = CoalyObserver::for_fn($func_name, None, std::file!(),std::line!());
214 };
215 ($func_name: literal $(,$arg: expr)+) => {
216 let arg_str = String::new();
217 $(
218 let arg_str = if arg_str.len() == 0 { arg_str + &format!("{}", $arg) }
219 else { arg_str + &format!(",{}", $arg) };
220 )+
221 let _cfn = CoalyObserver::for_fn($func_name, Option::from(arg_str.as_str()),
222 std::file!(),std::line!());
223 };
224}
225
226/// Traces a module's boundaries.
227/// Writes immediately a record upon the entry of the module and another message upon
228/// leaving of the module using the drop method of the instantiated Coaly observer structure.
229/// Depending on the configuration, the system's behaviour may change after the module
230/// entry.
231///
232/// # Arguments
233/// * `module_name` - the name of the module
234#[macro_export]
235macro_rules! logmod {
236 ($module_name: literal) => {
237 let _cmod = CoalyObserver::for_mod($module_name, std::file!(), std::line!());
238 }
239}
240
241/// Writes a log message concerning the specified application object.
242/// Object level is used for the message.
243/// The application object must implement the CoalyObservable trait.
244///
245/// # Arguments
246/// * `msg` - the message
247#[macro_export]
248macro_rules! logobj {
249 ($obj: expr, $msg: literal) => {
250 agent::write_obs($obj, std::file!(), std::line!(), $msg);
251 }
252}
253
254/// Creates and returns an observer structure.
255/// Writes immediately an output record upon instantiation of the structure and another record
256/// upon drop.
257/// Depending on the configuration, the system's behaviour may change after the structure
258/// instantiation.
259///
260/// # Arguments
261/// * `obj_name` - the name of the user defined observer
262/// * `obj_value` - the optional value of the user defined observer
263#[macro_export]
264macro_rules! newcoalyobs {
265 ($obj_name: expr) => {
266 CoalyObserver::for_obj($obj_name, None, std::file!(),std::line!())
267 };
268 ($obj_name: expr ,$obj_value: expr) => {
269 CoalyObserver::for_obj($obj_name, Option::from($obj_value), std::file!(),std::line!())
270 };
271}
272
273/// Coaly observer structure.
274/// An observer structure is created upon entry of a function or during instantiation of a logging
275/// relevant user structure.
276/// An observer structure marks both beginning and end of a function or structure lifetime, it is
277/// the basis for output mode control.
278pub struct CoalyObserver(ObserverData);
279impl CoalyObserver {
280 /// Creates an observer structure for a function
281 ///
282 /// # Arguments
283 /// * `name` - the function's name
284 /// * `args` - the optional function's' arguments
285 /// * `file_name` - the name of the source code file where the structure was created
286 /// * `line_nr` - the line number in the source code file where the structure was created
287 pub fn for_fn(name: &'static str,
288 args: Option<&str>,
289 file_name: &'static str,
290 line_nr: u32) -> CoalyObserver {
291 let data = ObserverData::for_fn(name, args, file_name);
292 agent::observer_created(&data, line_nr);
293 CoalyObserver { 0: data }
294 }
295
296 /// Creates an observer structure for a module.
297 /// Since a module doesn't provide an entry point by itself, it must be created at the
298 /// beginning of a module's public function.
299 ///
300 /// # Arguments
301 /// * `name` - the module's name
302 /// * `file_name` - the name of the source code file where the structure was created
303 /// * `line_nr` - the line number in the source code file where the structure was created
304 pub fn for_mod(name: &'static str,
305 file_name: &'static str,
306 line_nr: u32) -> CoalyObserver {
307 let data = ObserverData::for_mod(name, file_name);
308 agent::observer_created(&data, line_nr);
309 CoalyObserver { 0: data }
310 }
311
312 /// Creates an observer structure for a logging relevant user object
313 ///
314 /// # Arguments
315 /// * `name` - the object's name
316 /// * `value` - the optional object's value
317 /// * `file_name` - the name of the source code file where the structure was created
318 /// * `line_nr` - the line number in the source code file where the structure was created
319 pub fn for_obj(name: &str,
320 value: Option<&str>,
321 file_name: &'static str,
322 line_nr: u32) -> CoalyObserver {
323 let data = ObserverData::for_obj(name, value, file_name);
324 agent::observer_created(&data, line_nr);
325 CoalyObserver { 0: data }
326 }
327}
328impl Drop for CoalyObserver {
329 /// Invoked automatically when the observer structure goes out of scope.
330 /// Writes an output record indicating that the structure has been dropped and may also revert
331 /// the changes in the system behaviour to the status before the struct was created.
332 fn drop(&mut self) { agent::observer_dropped(&self.0); }
333}
334
335pub trait CoalyObservable {
336 /// Returns a reference to the Coaly observer structure
337 fn coaly_observer(&self) -> &CoalyObserver;
338}