Logging #26
10
logging/Cargo.toml
Normal file
10
logging/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "logging"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.34", default-features = false, features = ["now"] }
|
||||
config = { path = "../config"}
|
149
logging/src/lib.rs
Normal file
149
logging/src/lib.rs
Normal file
@ -0,0 +1,149 @@
|
||||
/*!
|
||||
* This module handles logging messages asynchronously and is thread-safe.
|
||||
* It should mostly be called statically.
|
||||
*/
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
|
||||
use config::LogVerbosity;
|
||||
|
||||
use chrono::Utc;
|
||||
|
||||
use LogVerbosity::Warning;
|
||||
use LogVerbosity::Information;
|
||||
|
||||
use LogMessageType::GenericErr;
|
||||
use LogMessageType::GenericWarn;
|
||||
use LogMessageType::GenericInfo;
|
||||
use LogMessageType::GenericDebug;
|
||||
|
||||
/**
|
||||
* Logs the given message.
|
||||
*
|
||||
* # Panics
|
||||
* Panics if readlock on [`config::CONFIG`] could not be acquired
|
||||
* or if another error occurs, such as a full disk.
|
||||
*/
|
||||
// TODO: Create macro to make last three parameters optional.
|
||||
pub fn log_message(msg: &LogMessage, file: &str, line: &str, column: &str)
|
||||
{
|
||||
let conf = config::CONFIG.read().expect(&format!("Failed aqcuire read lock on config\nTried to log message: {msg}"));
|
||||
|
||||
if conf.log_verbosity() < &msg.1 { return; }
|
||||
|
||||
let mut log_line = String::new();
|
||||
|
||||
// add time substring
|
||||
if *conf.log_time()
|
||||
{
|
||||
log_line += &format!("{} ", Utc::now().format(conf.log_time_format()));
|
||||
}
|
||||
|
||||
// add code location substring
|
||||
if *conf.log_location()
|
||||
{
|
||||
log_line += &format!("{file}:{line},{column} ");
|
||||
}
|
||||
|
||||
log_line += &msg.to_string();
|
||||
|
||||
// May panic if file cannot be opened or written to.
|
||||
conf.log_path().as_ref().map_or_else(
|
||||
|| {}, |path|
|
||||
{
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.open(path)
|
||||
.expect(
|
||||
&format!("Could not open log file: {path:#?}")
|
||||
);
|
||||
writeln!(file, "{log_line}").expect(&format!("Could not write log to file: {path:#?}"));
|
||||
}
|
||||
);
|
||||
|
||||
if msg.1 <= Warning && *conf.log_stderr()
|
||||
{
|
||||
// May panic if writing to stderr fails.
|
||||
eprintln!("{log_line}");
|
||||
}
|
||||
else if msg.1 >= Information && *conf.log_stdout()
|
||||
{
|
||||
// May panic if writing to stdout fails.
|
||||
println!("{log_line}");
|
||||
}
|
||||
|
||||
drop(conf); // remove read lock
|
||||
}
|
||||
|
||||
/**
|
||||
* A named typle assigning a log [`LogVerbosity`] to a [`LogMessageType`]
|
||||
*/
|
||||
pub struct LogMessage(LogMessageType, LogVerbosity);
|
||||
|
||||
impl Display for LogMessage
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>
|
||||
{
|
||||
self.0.fmt(f) // just display LogMessageType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Every possible Message, which may be logged. Grouped the following:
|
||||
*
|
||||
* These groups correspond to the four levels of logging verbosity. See [`LogVerbosity`].
|
||||
*/
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum LogMessageType {
|
||||
/// Errors
|
||||
/// An error of any type; please avoid using this.
|
||||
GenericErr(String),
|
||||
/// Warnings
|
||||
/// A warning of any type; please avoid using this.
|
||||
GenericWarn(String),
|
||||
/// Info
|
||||
/// Some information of any type; please avoid using this.
|
||||
GenericInfo(String),
|
||||
/// Debug
|
||||
/// a debug message of any type; please avoid using this.
|
||||
GenericDebug(String),
|
||||
}
|
||||
|
||||
/*
|
||||
* Please don't put anything other except new match arms below this comment, since it is expected that
|
||||
* the following code will have a lot of lines, due to exhausting all possible enum values
|
||||
* respectively and (hopefully) detailed messages.
|
||||
*/
|
||||
|
||||
impl LogMessageType
|
||||
{
|
||||
/// Returns a new [`LogMessage`] based on the default verbosity of the given [`LogMessageType`].
|
||||
pub fn log_message(&self) -> LogMessage
|
||||
{
|
||||
let verbosity = match self
|
||||
{
|
||||
GenericErr(_) => LogVerbosity::Error,
|
||||
GenericWarn(_) => LogVerbosity::Warning,
|
||||
GenericInfo(_) => LogVerbosity::Information,
|
||||
GenericDebug(_) => LogVerbosity::Debugging,
|
||||
};
|
||||
|
||||
LogMessage(self.clone(), verbosity)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LogMessageType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>
|
||||
{
|
||||
match self
|
||||
{
|
||||
GenericErr(err) => { write!(f, "Generic Error: {err}") },
|
||||
GenericWarn(warn) => { write!(f, "Generic Warning: {warn}") },
|
||||
GenericInfo(info) => { write!(f, "Generic Information: {info}") },
|
||||
GenericDebug(debug) => { write!(f, "Generic Debug Message: {debug}") },
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user