logger_utc 0.2.0

Logging with time stamp library for Rust
Documentation
//! # logger_utc: Logging with time stamp for Rust
//!
//! logger_utc provides a handful of functions to log
//! a given message with a time stamp to stdout, a fixed file name,
//! or a dynamic file name, based on the UTC date.

use std::fs;
use std::fs::OpenOptions;
use std::io::{BufWriter, Result, Write};

use chrono::Utc;

/// This function logs the given message with the current UTC time stamp to stdout.
///
/// # Arguments
///
/// * `to_log` - The message to be logged.
///
/// # Examples
///
/// ```rust
/// use logger_utc::log;
///
/// fn main() {
///     log("MSG");
///     log(String::from("MSG"));
/// }
/// ```
///
/// This will print `[%Y-%m-%d] - [%H:%M:%S] - MSG` to the console.
pub fn log<S: AsRef<str>>(to_log: S) {
    println!("{}", mk_str(to_log.as_ref()));
}

/// Write a log message including the current UTC time stamp to a file.
///
/// # Arguments
///
/// * `to_log` - The log message to write.
/// * `file_name` - The name of the log file to write to.
///
/// # Example
///
/// ```rust
/// use logger_utc::log_to_file;
///
/// fn main() {
///     log_to_file("MSG", "err.log").unwrap();
/// }
/// ```
///
/// This will log `[%Y-%m-%d] - [%H:%M:%S] - MSG` to the file `err.log`.
///
/// # Errors
///
/// This function will return an error if it is unable to write to the log file
/// or if the parent directories cannot be created.
pub fn log_to_file<S: AsRef<str>, T: AsRef<str>>(to_log: S, file_name: T) -> Result<()> {
    let file_name = file_name.as_ref();
    if let Err(_) = OpenOptions::new()
        .create(true)
        .open(file_name) {
        mkdirs(file_name)?;
    }

    let file;

    if let Ok(f) = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(file_name) { file = f; } else {
        mkdirs(file_name)?;
        file = OpenOptions::new()
            .create(true)
            .write(true)
            .append(true)
            .open(file_name)?;
    }

    let mut writer = BufWriter::new(file);

    let msg = mk_str(to_log.as_ref());

    writeln!(writer, "{msg}")?;
    Ok(())
}

fn mkdirs(path: &str) -> Result<()> {
    let slash = get_slash();
    let vec = path.rsplitn(2, slash).collect::<Vec<_>>();
    if let Some(path) = vec.get(1) {
        return fs::create_dir_all(path);
    }
    Ok(())
}

#[cfg(target_os = "linux")]
fn get_slash() -> &'static str {
    "/"
}

#[cfg(target_os = "windows")]
fn get_slash() -> &'static str {
    "\\"
}

/// The file name will be a combination of the current date in the format of `%Y-%m-%d`
/// and the provided name.
///
/// # Arguments
///
/// - `to_log`: The log String to be written to the file.
/// - `file_path`: Optional file path where the file will be saved at the end.
/// If not provided, the file will be saved in the current working directory.
/// - `file_name`: The name of the file without date prefix.
///
/// # Example
///
/// ```rust
/// use logger_utc::log_to_dyn_file;
///
/// fn main() {
///     log_to_dyn_file("MSG", Some("logs/"), "err.log").unwrap();
/// }
/// ```
///
/// This will log `[%Y-%m-%d] - [%H:%M:%S] - MSG` to the file `logs/%Y-%m-%d-err.log`.
///
/// # Errors
///
/// This function will return an error if it is unable to write to the log file or
/// the target directory cannot be created.
pub fn log_to_dyn_file<S: AsRef<str>, T: AsRef<str>, U: AsRef<str>>
(to_log: S, file_path: Option<T>, file_name: U) -> Result<()> {
    let date = Utc::now()
        .format("%Y-%m-%d")
        .to_string();

    let file_name = file_name.as_ref();

    let path;

    if let Some(p) = file_path {
        let p = p.as_ref();
        let slash = get_slash();
        if !p.ends_with(slash) {
            path = format!("{p}{slash}");
        } else { path = String::from(p) }
    } else { path = String::new() }

    let combined_file_path = format!("{path}{date}-{file_name}");

    log_to_file(to_log, &combined_file_path)?;
    Ok(())
}

/// Returns a string slice with a formatted log message.
///
/// # Arguments
///
/// * `to_log` - The message to include in the log.
///
/// # Examples
fn mk_str(to_log: &str) -> String {
    let now = Utc::now()
        .format("[%Y-%m-%d] - [%H:%M:%S]")
        .to_string();
    let msg = format!("{now} - {to_log}");

    msg
}