Logging #26
9
config/Cargo.toml
Normal file
9
config/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "config"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
getset = "0.1.2"
|
148
config/src/lib.rs
Normal file
148
config/src/lib.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*!
|
||||||
|
* A singleton, thread-safe struct used for accessing
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use crate::LogVerbosity::Warning;
|
||||||
|
|
||||||
|
use getset::Getters;
|
||||||
|
use getset::Setters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a valid `WANessa` configuration. Intended as a read-only singleton.
|
||||||
|
* See [`DEFAULTS`]
|
||||||
|
*/
|
||||||
|
#[derive(Clone,PartialEq, Eq)]
|
||||||
|
#[derive(Getters, Setters)]
|
||||||
|
#[getset(get = "pub")]
|
||||||
|
#[allow(clippy::struct_excessive_bools)] // False positive, since it is a config struct.
|
||||||
|
pub struct Config {
|
||||||
|
|||||||
|
/// See [`LogVerbosity`].<br>
|
||||||
|
/// Default: [`Warning`]
|
||||||
|
pub log_verbosity: LogVerbosity,
|
||||||
|
/// Logs UTC time and date of message, if true.<br>
|
||||||
|
/// Default: `false`
|
||||||
|
pub log_time: bool,
|
||||||
|
/// Time and date format.<br>
|
||||||
|
/// Defaults to `%F/%T:%f`.<br>
|
||||||
|
/// See [chrono](https://docs.rs/chrono/latest/chrono/format/strftime/index.html).<br>
|
||||||
|
/// Default example : `2001-12-31/23:59:33:26490000`
|
||||||
|
#[getset(skip)]
|
||||||
|
pub log_time_format: Option<String>,
|
||||||
|
/// Logs location in code, where the message was logged, if true.<br>
|
||||||
|
/// Default: `false`
|
||||||
|
pub log_location: bool,
|
||||||
|
/// If `Some(path)` tries to also write the log to `path` in addition to stderr/stderr.<br>
|
||||||
|
/// Default: [None]
|
||||||
|
pub log_path: Option<PathBuf>,
|
||||||
|
/// Logs to standard out, if true.<br>
|
||||||
|
/// Default: `true`
|
||||||
|
pub log_stdout: bool,
|
||||||
|
/// Logs to standard err, if true.<br>
|
||||||
|
/// Default: `true`
|
||||||
|
pub log_stderr: bool,
|
||||||
|
/// Database connection address.
|
||||||
|
/// Is an option to allow constructing a default config during compile time.<br>
|
||||||
|
/// Default: `localhost`.
|
||||||
|
#[getset(skip)]
|
||||||
|
pub db_addr: Option<String>,
|
||||||
|
/// Database connection port.<br>
|
||||||
|
/// Default: `6969` (nice).
|
||||||
|
pub db_port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// Getter for [`Self::db_addr`].
|
||||||
|
pub fn db_addr(&self) -> &str {
|
||||||
|
self.db_addr.as_ref().map_or("localhost", |addr| addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Getter for the [`Self::log_time_format`].
|
||||||
|
pub fn log_time_format(&self) -> &str
|
||||||
|
{
|
||||||
|
self.log_time_format.as_ref().map_or("%F-%T:%f", |fmt| fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`DEFAULTS`].
|
||||||
|
impl Default for Config {
|
||||||
|
/// See [`DEFAULTS`].
|
||||||
|
fn default() -> Self {
|
||||||
|
DEFAULTS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default configuration.
|
||||||
|
/// ```rust
|
||||||
|
/// # use config::Config;
|
||||||
|
/// # use config::LogVerbosity::Warning;
|
||||||
|
/// let DEFAULTS = Config
|
||||||
|
/// {
|
||||||
|
/// log_verbosity: Warning,
|
||||||
|
/// log_time: false,
|
||||||
|
/// log_time_format: None,
|
||||||
|
/// log_location: false,
|
||||||
|
/// log_stdout: true,
|
||||||
|
/// log_stderr: true,
|
||||||
|
/// log_path: None,
|
||||||
|
/// db_addr: None,
|
||||||
|
/// db_port: 6969,
|
||||||
|
/// };
|
||||||
|
/// # assert!(DEFAULTS == config::DEFAULTS)
|
||||||
|
/// ```
|
||||||
|
pub const DEFAULTS: Config = Config {
|
||||||
|
log_verbosity: Warning,
|
||||||
|
log_time: false,
|
||||||
|
log_time_format: None,
|
||||||
|
log_location: false,
|
||||||
|
log_stdout: true,
|
||||||
|
log_stderr: true,
|
||||||
|
log_path: None,
|
||||||
|
db_addr: None,
|
||||||
|
db_port: 6969,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Configuration singleton.
|
||||||
|
pub static CONFIG: RwLock<Config> = RwLock::new(DEFAULTS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each level includes the previous ones.
|
||||||
|
*/
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum LogVerbosity
|
||||||
|
{
|
||||||
|
/// Critical Errors, may lead to crashes or deactivating certain features.
|
||||||
|
Error,
|
||||||
|
/// Very minor and recovered errors, such as invalid configs.
|
||||||
|
Warning,
|
||||||
|
/// Very verbose and detailed. Basically gives a step-by-step instruction on what is currently done.
|
||||||
|
Information,
|
||||||
|
/// Very technical and even more verbose.
|
||||||
|
/// May contain secrets and private information.
|
||||||
|
/// **Do not use in production environments!**
|
||||||
|
Debugging,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for LogVerbosity
|
||||||
|
{
|
||||||
|
/// Some operator overloading of comparison symbols (==, <,>=, etc.) as syntactic sugar.
|
||||||
|
/// See [`PartialOrd`].
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
|
||||||
|
{
|
||||||
|
(*self as usize).partial_cmp(&(*other as usize))
|
||||||
|
}
|
||||||
|
}
|
||||||
hendrik marked this conversation as resolved
Outdated
leon
commented
It is mentioned here, that each level includes the previous ones, but including explicit ordinals is still a good idea. > LogVerbosity doesn't specify values, but logging/src/lib.rs:75 assumes order
> -> Accidental reordering of the enum would lead to errors
It is mentioned here, that each level includes the previous ones, but including explicit ordinals is still a good idea.
leon
commented
@hendrik
|
|||||||
|
|
||||||
|
impl Ord for LogVerbosity
|
||||||
|
{
|
||||||
|
/// Some operator overloading of comparison symbols (==, <,>=, etc.) as syntactic sugar.
|
||||||
|
/// See [`Ord`].
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering
|
||||||
|
{
|
||||||
|
(*self as usize).cmp(&(*other as usize))
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user
I considered this.
I just thought that setters are more convenient than using
mem::swap
or*config = Config::new(...)
. I also was not sure, if the config is truly read-only since we never specified if hot-reloading the config is a desired feature. Depending on how the CLI is implemented, hot-applying config-changes might also be a necessity to disable stdout logging, which would pollute the CLIs visuals.@hendrik
I assumed the config would be read only, because some attribute changes after initialization could easily cause unexpected problems. For example, changing the database server at runtime is not something the current code is designed for, nor would it be a sensible feature to implement. If the log-settings should be mutable after the initialization phase, we should add a mutable reference to some "LogPreferences" structure to our Config instead of generally supporting hot-reload for the whole Config
@leon
Seems sensible. It is also probably a good idea to split the config struct into multiple parts.
See
a787dd93e5