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