flogging 0.6.0

This is a fast, flexible logging crate, loosely based on the Java logging package: java.util.logging.
Documentation
//
// File Name:    log_entry.rs
// Directory:    src/logger
// Project Name: flogging
//
// Copyright (C) 2025 Bradley Willcott
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This library (crate) is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This library (crate) is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library (crate).  If not, see <https://www.gnu.org/licenses/>.
//

//!
//! # Log Entry
//!

use chrono::{DateTime, Local};
use std::{fmt, time::Instant};
use super::Level;

///
/// Used to provide relevant information about each log entry.
///
#[derive(Debug)]
pub struct LogEntry {
    pub(crate) timestamp: DateTime<Local>,
    pub(crate) mod_path: String,
    ///
    /// This is the name of the function/method inside which this
    /// log entry was generated.
    ///
    pub(crate) fn_name: String,
    pub(crate) level: Level,
    pub(crate) message: String,
}

impl fmt::Display for LogEntry {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} : {}->{} ({}) {}",
            self.timestamp, self.mod_path, self.fn_name, self.level, self.message
        )
    }
}

#[allow(unused)]
impl LogEntry {
    pub(crate) fn create(level: Level, fn_name: String, message: String) -> LogEntry {
        LogEntry {
            timestamp: Local::now(),
            mod_path: String::new(),
            fn_name,
            level,
            message,
        }
    }

    pub(crate) fn fn_name(&self) -> String {
        self.fn_name.clone()
    }

    pub(crate) fn level(&self) -> Level {
        self.level
    }

    pub(crate) fn message(&self) -> String {
        self.message.clone()
    }

    pub(crate) fn mod_path(&self) -> String {
        self.mod_path.clone()
    }

    pub(crate) fn set_fn_name(&mut self, fn_name: String) {
        self.fn_name = fn_name.clone();
    }

    pub(crate) fn set_mod_path(&mut self, mod_path: String) {
        self.mod_path = mod_path.clone();
    }

    pub(crate) fn timestamp(&self) -> DateTime<Local> {
        self.timestamp
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn to_string() {
        let mut log_entry =
            LogEntry::create(Level::INFO, "to_string".to_string(), "message".to_string());

        log_entry.set_mod_path(module_path!().to_owned());
        println!("\nlog_entry: {log_entry}\n");

        assert_eq!(log_entry.level(), Level::INFO);
        assert_eq!(log_entry.message(), "message".to_string());
        assert_eq!(log_entry.fn_name(), "to_string".to_string());
        assert_eq!(log_entry.mod_path(), module_path!());
        assert!(log_entry.timestamp().timestamp() > 0);

        log_entry.set_fn_name("fn_name".to_owned());
        assert_eq!(log_entry.fn_name(), "fn_name".to_string());
    }
}