Просмотр исходного кода

日志配置第三版,json格式的打印

skyffire 6 месяцев назад
Родитель
Сommit
474af54d6e
2 измененных файлов с 50 добавлено и 96 удалено
  1. 2 3
      Cargo.toml
  2. 48 93
      src/utils/log_setup.rs

+ 2 - 3
Cargo.toml

@@ -45,9 +45,6 @@ tracing-subscriber = { version = "0.3", features = ["json", "fmt", "env-filter",
 # 用于日志文件按日期滚动
 tracing-appender = "0.2"
 
-# 简化错误处理的库,方便快速构建可链式调用的错误
-anyhow = "1"
-
 # 日期和时间处理
 chrono = "0.4"
 # 时区数据库,用于获取 Asia/Shanghai 时区
@@ -55,6 +52,8 @@ chrono-tz = "0.8"
 # 确保 time crate 的特性被启用
 time = { version = "0.3", features = ["macros", "formatting", "parsing", "local-offset"] }
 
+# 简化错误处理的库,方便快速构建可链式调用的错误
+anyhow = "1"
 
 # 用于定义自定义错误类型的库,与 anyhow 配合使用,让错误更具语义
 thiserror = "1"

+ 48 - 93
src/utils/log_setup.rs

@@ -92,25 +92,17 @@ mod tests {
     use super::*;
     use chrono::{Local};
     use chrono_tz::Asia::Shanghai;
-    use std::{fs, io::Read, path::Path, thread, time::Duration};
-
-    // // 辅助函数:清理日志文件 (保持不变)
-    // fn cleanup_log_file(filename: &str) {
-    //     // ... (代码不变) ...
-    //     if Path::new(filename).exists() {
-    //         let _ = fs::remove_file(filename);
-    //         println!("Cleaned up log file: {}", filename);
-    //     }
-    //     let log_dir = Path::new("logs");
-    //     if log_dir.exists() {
-    //         if let Ok(mut read_dir) = log_dir.read_dir() {
-    //             if read_dir.next().is_none() { // 检查目录是否为空
-    //                 let _ = fs::remove_dir(log_dir);
-    //                 println!("Cleaned up empty log directory: logs");
-    //             }
-    //         }
-    //     }
-    // }
+    use serde::Serialize;
+
+    // 定义一个用于测试的可序列化结构体
+    #[derive(Serialize)]
+    #[derive(Debug)]
+    struct TestData {
+        id: u32,
+        name: String,
+        is_active: bool,
+        tags: Vec<String>,
+    }
 
     #[test]
     fn test_logging_setup_and_output() {
@@ -120,86 +112,49 @@ mod tests {
             "logs/pin_trading_tool.log.{}",
             now_shanghai.format("%Y-%m-%d")
         );
-        println!("Expected log file: {}", expected_log_filename);
-
-        // // 测试开始前清理
-        // cleanup_log_file(&expected_log_filename);
-        //
-        // // 使用 RAII 清理,确保即使 panic 也会执行
-        // struct LogCleaner<'a>(&'a str);
-        // impl<'a> Drop for LogCleaner<'a> {
-        //     fn drop(&mut self) {
-        //         cleanup_log_file(self.0);
-        //         println!("Log cleaner finished cleanup for: {}", self.0);
-        //     }
-        // }
-        // let _cleaner = LogCleaner(&expected_log_filename);
+        println!("--- Log Test Start ---");
+        println!("Logging to console and file: {}", expected_log_filename);
+        println!("NOTE: This test will *not* assert content and *not* clean up the log file.");
 
         // --- 执行 ---
-        // 1. 初始化日志系统并获取 guards
-        // 注意:全局日志记录器只能初始化一次。如果多个测试需要初始化,
-        // 需要使用 `serial_test` crate 或类似的机制来确保测试串行执行。
+        // 1. 初始化日志
         let setup_result = setup_logging();
-        assert!(setup_result.is_ok(), "Failed to setup logging: {:?}", setup_result.err());
-        let guards = setup_result.unwrap(); // <-- 获取 guards
-        println!("Logging setup successful, guards acquired.");
+        let _guards = match setup_result {
+            Ok(g) => {
+                println!("Logging setup successful, guards acquired.");
+                g // 返回 guards
+            },
+            Err(e) => {
+                // 如果初始化失败,打印错误并提前退出测试
+                eprintln!("FATAL: Failed to setup logging: {:?}. Test cannot continue.", e);
+                // 在测试函数中使用 panic! 来表示严重失败是合适的
+                panic!("Logging setup failed: {:?}", e);
+            }
+        };
 
-        // 2. 记录日志消息
-        // 现在 guards 还存活,日志应该能被处理
-        let test_message = "这是测试信息\n这是测试信息换行"; // 使用唯一字符串便于查找
+        // 2. 记录各种日志
+        let test_message = "这是测试信息\n这是测试信息换行";
         tracing::error!(target: "test_target", param = "value1", "错误消息内容 Error = {:?}", std::io::Error::new(std::io::ErrorKind::Other, "测试错误"));
         tracing::warn!("警告信息。 Value = {}", 42);
-        tracing::info!(message = test_message);
-        tracing::debug!("调试信息 (可能被过滤)"); // 默认INFO级别,这个可能不显示
-        tracing::trace!("追踪信息 (可能被过滤)"); // 默认INFO级别,这个可能不显示
-
-        // 3. **显式丢弃 guards 以触发刷新**
-        // 在读取文件之前,确保所有缓冲的日志都已刷新。
-        // drop(guards) 会调用每个 WorkerGuard 的 drop 实现,这会负责 flush。
-        println!("Dropping logging guards to force flush...");
-        drop(guards); // <-- 在这里显式 drop guards
-        println!("Guards dropped.");
-
-        // 4. (可选)短暂等待,以防万一文件系统写入有延迟
-        // 在显式 drop guards 后,这个等待通常不再是必需的,但保留也无妨。
-        thread::sleep(Duration::from_millis(100)); // 可以尝试缩短或移除
-
-        // --- 验证 ---
-        // 5. 检查日志文件
-        println!("Checking log file: {}", expected_log_filename);
-        assert!(
-            Path::new(&expected_log_filename).exists(),
-            "Log file '{}' was not created.", expected_log_filename
-        );
-
-        let mut file = match fs::File::open(&expected_log_filename) {
-            Ok(f) => f,
-            Err(e) => panic!("Failed to open log file '{}': {}", expected_log_filename, e),
+        tracing::info!(plain_message = test_message, "记录普通文本信息");
+
+        // --- 记录 JSON 数据 ---
+        let json_data = TestData {
+            id: 123,
+            name: "示例 \"数据\"".to_string(), // 包含引号的字符串
+            is_active: true,
+            tags: vec!["tag1".to_string(), "tag2".to_string()],
         };
-        let mut contents = String::new();
-        match file.read_to_string(&mut contents) {
-            Ok(_) => (),
-            Err(e) => panic!("Failed to read log file '{}': {}", expected_log_filename, e),
-        };
-
-        println!("Log file content length: {}", contents.len());
-        // 打印一部分内容用于调试
-        // println!("Log content sample: {}", contents.chars().take(500).collect::<String>());
-
-        assert!(!contents.is_empty(), "Log file is empty. File: '{}'", expected_log_filename);
-
-        // 检查关键内容
-        assert!(contents.contains(test_message), "Log content missing info message");
-        assert!(contents.contains("ERROR"), "Log content missing ERROR level");
-        assert!(contents.contains("test_target"), "Log content missing target 'test_target'");
-        assert!(contents.contains("错误消息内容"), "Log content missing error message body");
-        assert!(contents.contains("WARN"), "Log content missing WARN level");
-        assert!(contents.contains("警告信息"), "Log content missing warn message");
-        assert!(contents.contains("INFO"), "Log content missing INFO level");
-        // 检查文件名和行号模式 (注意行号会变)
-        assert!(contents.contains("log_setup.rs:"), "Log content missing file/line info indicator ('log_setup.rs:')");
-
-        println!("Log content verified successfully.");
-        // _cleaner 会在函数结束时自动调用 drop 进行清理
+        tracing::info!("json_data: {}", serde_json::to_string_pretty(&json_data).unwrap());
+        // match serde_json::to_string_pretty(&json_data) {
+        //     Ok(json_string) => {
+        //         tracing::info!(json_payload = %json_string, "记录 JSON 数据为字段");
+        //         // tracing::info!("直接嵌入 JSON 示例:\n{}", json_string); // 也可以选择这种方式记录
+        //     }
+        //     Err(e) => {
+        //         tracing::error!("序列化 JSON 失败: {:?}", e);
+        //     }
+        // }
+        // --- 结束 JSON 记录 ---
     }
 }