Skip to main content

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}