rlg 0.0.8

A Rust library that implements application-level logging with a simple, readable output format. Features include log rotation, network logging, and support for multiple structured formats like JSON, CEF, and more.
Documentation
#![cfg(not(miri))]
// Copyright © 2024-2026 RustLogs (RLG). All rights reserved.
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

//! Tests for the log format functionality of RustLogs (RLG).

#[cfg(test)]
mod tests {
    use rlg::log_format::LogFormat;

    #[test]
    fn test_log_format_display() {
        assert_eq!(format!("{}", LogFormat::CLF), "CLF");
        assert_eq!(format!("{}", LogFormat::JSON), "JSON");
        assert_eq!(format!("{}", LogFormat::CEF), "CEF");
        assert_eq!(format!("{}", LogFormat::ELF), "ELF");
        assert_eq!(format!("{}", LogFormat::W3C), "W3C");
        assert_eq!(format!("{}", LogFormat::GELF), "GELF");
        assert_eq!(
            format!("{}", LogFormat::ApacheAccessLog),
            "Apache Access Log"
        );
        assert_eq!(format!("{}", LogFormat::Logstash), "Logstash");
        assert_eq!(format!("{}", LogFormat::Log4jXML), "Log4j XML");
        assert_eq!(format!("{}", LogFormat::NDJSON), "NDJSON");
        assert_eq!(format!("{}", LogFormat::MCP), "MCP");
        assert_eq!(format!("{}", LogFormat::OTLP), "OTLP");
        assert_eq!(format!("{}", LogFormat::Logfmt), "logfmt");
        assert_eq!(format!("{}", LogFormat::ECS), "ECS");
    }

    #[test]
    fn test_log_format_from_str() {
        assert_eq!("CLF".parse::<LogFormat>().unwrap(), LogFormat::CLF);
        assert_eq!(
            "JSON".parse::<LogFormat>().unwrap(),
            LogFormat::JSON
        );
        assert_eq!("CEF".parse::<LogFormat>().unwrap(), LogFormat::CEF);
        assert_eq!("ELF".parse::<LogFormat>().unwrap(), LogFormat::ELF);
        assert_eq!("W3C".parse::<LogFormat>().unwrap(), LogFormat::W3C);
        assert_eq!(
            "GELF".parse::<LogFormat>().unwrap(),
            LogFormat::GELF
        );
        assert_eq!(
            "ApacheAccessLog".parse::<LogFormat>().unwrap(),
            LogFormat::ApacheAccessLog
        );
        assert_eq!(
            "Logstash".parse::<LogFormat>().unwrap(),
            LogFormat::Logstash
        );
        assert_eq!(
            "Log4jXML".parse::<LogFormat>().unwrap(),
            LogFormat::Log4jXML
        );
        assert_eq!(
            "NDJSON".parse::<LogFormat>().unwrap(),
            LogFormat::NDJSON
        );
        assert!("Invalid".parse::<LogFormat>().is_err());
    }

    #[test]
    fn test_log_format_validate() {
        assert!(LogFormat::CLF.validate(
        "127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326"
    ));
        assert!(LogFormat::JSON.validate("{\"key\":\"value\"}"));
        assert!(LogFormat::CEF.validate("CEF:0|security|threat|1.0|100|Something happened|5|msg=hello"));
        assert!(LogFormat::W3C.validate("#Fields: date time c-ip cs-method cs-uri-stem sc-status\n2024-01-01 12:34:56 192.168.0.1 GET /index.html 200"));
        assert!(LogFormat::GELF.validate("{\"version\":\"1.1\",\"host\":\"localhost\",\"short_message\":\"A short message\"}"));
        assert!(LogFormat::Log4jXML.validate(
            "<log4j:event logger=\"myLogger\" timestamp=\"1234567890\">"
        ));

        // Invalid cases
        assert!(!LogFormat::CLF.validate("Invalid CLF log"));
        assert!(!LogFormat::JSON.validate("Invalid JSON"));
        assert!(!LogFormat::CEF.validate("Invalid CEF log"));
        assert!(!LogFormat::W3C.validate("Invalid W3C log"));
        assert!(!LogFormat::GELF.validate("Invalid GELF log"));
        assert!(
            !LogFormat::Log4jXML.validate("<invalid>XML</invalid>")
        );
    }

    #[test]
    fn test_log_format_format_log() {
        // Valid formatting
        assert_eq!(
            LogFormat::CLF
                .format_log(
                    "127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326"
                )
                .unwrap(),
            "127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326"
        );

        assert_eq!(
            LogFormat::JSON.format_log("{\"key\":\"value\"}").unwrap(),
            "{\n  \"key\": \"value\"\n}"
        );

        assert_eq!(
            LogFormat::CEF
                .format_log("CEF:0|security|threat|1.0|100|Something happened|5|msg=hello")
                .unwrap(),
            "CEF:0|security|threat|1.0|100|Something happened|5|msg=hello"
        );

        assert_eq!(
            LogFormat::Log4jXML
                .format_log("<log4j:event logger=\"myLogger\" timestamp=\"1234567890\">")
                .unwrap(),
            "<log4j:event logger=\"myLogger\" timestamp=\"1234567890\">"
        );

        // Invalid JSON
        let invalid_json = "Invalid JSON";
        assert!(LogFormat::JSON.format_log(invalid_json).is_err());
    }

    // Additional tests for edge cases and specific format validations

    #[test]
    fn test_log_format_validate_edge_cases() {
        // Empty string
        assert!(!LogFormat::CLF.validate(""));
        assert!(!LogFormat::JSON.validate(""));

        // Very long string
        let long_string = "a".repeat(10000);
        assert!(!LogFormat::CLF.validate(&long_string));
        assert!(
            LogFormat::JSON
                .validate(&format!("{{\"key\":\"{}\"}}", long_string))
        );

        // Special characters
        assert!(
            LogFormat::JSON.validate(
                "{\"key\":\"value with spaces and 特殊字符\"}"
            )
        );
    }

    #[test]
    fn test_log_format_case_insensitivity() {
        assert_eq!("clf".parse::<LogFormat>().unwrap(), LogFormat::CLF);
        assert_eq!(
            "JSON".parse::<LogFormat>().unwrap(),
            LogFormat::JSON
        );
        assert_eq!("Cef".parse::<LogFormat>().unwrap(), LogFormat::CEF);
    }

    #[test]
    fn test_log_format_error_messages() {
        let result = "InvalidFormat".parse::<LogFormat>();
        assert!(result.is_err());
        assert_eq!(
            result.unwrap_err().to_string(),
            "Log format parse error: Unknown log format: InvalidFormat"
        );
    }

    #[test]
    fn test_log_format_validate_new_formats() {
        assert!(LogFormat::OTLP.validate("{}"));
        assert!(LogFormat::ECS.validate("{}"));
        assert!(LogFormat::Logfmt.validate("key=value"));
        assert!(!LogFormat::Logfmt.validate("no_equals"));
        assert!(!LogFormat::Logfmt.validate("=starts_with_equals"));
    }

    #[test]
    fn test_log_format_format_log_others() {
        assert_eq!(LogFormat::ELF.format_log("elf").unwrap(), "elf");
        assert_eq!(LogFormat::W3C.format_log("w3c").unwrap(), "w3c");
        assert_eq!(
            LogFormat::ApacheAccessLog.format_log("apache").unwrap(),
            "apache"
        );
        assert_eq!(LogFormat::CEF.format_log("cef").unwrap(), "cef");
        assert_eq!(
            LogFormat::Log4jXML.format_log("xml").unwrap(),
            "xml"
        );
        assert_eq!(
            LogFormat::Logfmt.format_log("key=val").unwrap(),
            "key=val"
        );

        // JSON-based others
        let json = "{\"k\":\"v\"}";
        assert!(LogFormat::Logstash.format_log(json).is_ok());
        assert!(LogFormat::NDJSON.format_log(json).is_ok());
        assert!(LogFormat::GELF.format_log(json).is_ok());
        assert!(LogFormat::MCP.format_log(json).is_ok());
        assert!(LogFormat::OTLP.format_log(json).is_ok());
        assert!(LogFormat::ECS.format_log(json).is_ok());

        // Invalid JSON for JSON-based formats
        let invalid = "not json";
        assert!(LogFormat::Logstash.format_log(invalid).is_err());
        assert!(LogFormat::NDJSON.format_log(invalid).is_err());
        assert!(LogFormat::GELF.format_log(invalid).is_err());
        assert!(LogFormat::MCP.format_log(invalid).is_err());
        assert!(LogFormat::OTLP.format_log(invalid).is_err());
        assert!(LogFormat::ECS.format_log(invalid).is_err());
    }
}