Skip to content

Utils_Logger

SweerItTer edited this page Feb 1, 2026 · 3 revisions

Logger API 文档

概述

Logger 是 utilsCore 核心模块的日志系统,提供线程安全的日志记录功能,支持毫秒级时间戳和格式化输出。

职责

  • 线程安全的日志写入
  • 毫秒级时间戳
  • 格式化输出支持
  • 自动管理日志文件描述符

适用场景

  • 调试和问题诊断
  • 系统运行监控
  • 性能分析
  • 时间差测量

依赖关系

  • 依赖: C++ STL
  • 被依赖: 所有需要日志记录的模块

类分析

Logger 类

职责与用途

Logger 是日志系统的封装类,提供:

  • 静态方法调用
  • 线程安全的日志写入
  • 毫秒级时间戳
  • 格式化输出支持
  • 自动管理日志文件描述符

设计模式

  • 静态类: 所有方法都是静态的
  • RAII: 使用 FileStream 自动管理文件资源

FileStream 类

职责与用途

FileStream 是 FILE* 的 RAII 风格包装器,提供:

  • 自动文件关闭
  • 移动语义支持
  • 禁止拷贝

方法定义

class FileStream {
public:
    FileStream() noexcept;                              // 默认构造
    explicit FileStream(FILE* fp) noexcept;             // 从 FILE* 构造,接管所有权
    FileStream(FileStream&& other) noexcept;            // 移动构造
    FileStream& operator=(FileStream&& other) noexcept; // 移动赋值
    FileStream(const FileStream&) = delete;             // 禁止拷贝
    FileStream& operator=(const FileStream&) = delete;  // 禁止拷贝
    ~FileStream();

    FILE* get() const noexcept;                         // 获取原始指针
    FILE* release() noexcept;                           // 释放所有权
    void reset() noexcept;                              // 安全关闭文件
    void reset(FILE* fp) noexcept;                      // 重置为新的文件指针
    explicit operator bool() const noexcept;            // 检查是否有效
};

使用例程

// 创建 FileStream
FileStream fs(fopen("log.txt", "w"));

// 移动构造
FileStream fs2 = std::move(fs);

// 移动赋值
FileStream fs3;
fs3 = std::move(fs2);

// 检查是否有效
if (fs3) {
    fprintf(fs3.get(), "Hello\n");
}

// 自动关闭文件

Logger 公共 API 方法

LogFlag - 日志标志

static bool LogFlag;

说明: 控制日志输出的全局标志,设置为 false 时禁用日志输出。

使用例程:

Logger::LogFlag = true;   // 启用日志
Logger::LogFlag = false;  // 禁用日志

initLogger() - 初始化日志系统

static void initLogger();

参数说明: 无

返回值: 无

所有权归属:

  • 无所有权转移

注意事项:

  1. 创建按时间命名的日志文件,格式为 YYYY-MM-DD_HH-MM-SS.log
  2. 必须在其他日志方法前调用
  3. 建议在 main 函数中使用
  4. 日志文件名示例:2026-02-01_10-30-45.log

使用例程:

int main() {
    Logger::initLogger();  // 初始化日志系统
    
    Logger::log(stdout, "Application started");
    
    return 0;
}

log() - 记录格式化日志

static void log(FILE *stream, const char* format, ...);

参数说明:

  • stream (输入): 输出流(stdout, stderr, 或文件流)
  • format (输入): 格式化字符串,遵循标准 printf 格式规范
  • ... (输入): 可变参数,匹配格式化字符串

返回值: 无

所有权归属:

  • 无所有权转移

注意事项:

  1. 线程安全的日志记录方法
  2. 支持 printf 风格格式化
  3. 自动添加时间戳格式:[YYYY-MM-DD HH:MM:SS.mmm]
  4. 如果日志系统未初始化,消息将被静默丢弃
  5. LogFlag 控制,如果 LogFlag 为 false,不会输出

使用例程:

// 记录简单消息
Logger::log(stdout, "Service started");

// 带参数的格式化日志
int error_code = 404;
Logger::log(stderr, "Request failed with error: %d", error_code);

// 多参数日志
float temp = 23.5f;
Logger::log(stdout, "Temperature: %.1f°C, Humidity: %d%%", temp, 45);

mk 命名空间

makeTimestamp() - 生成时间戳字符串

inline std::string makeTimestamp(uint64_t &out_us_epoch);

参数说明:

  • out_us_epoch (输出): 输出微秒时间戳(基于 CLOCK_MONOTONIC)

返回值: 时间戳字符串,格式为 YYYY-MM-DD HH:MM:SS.mmm

所有权归属:

  • 无所有权转移

注意事项:

  1. 使用 CLOCK_MONOTONIC 获取微秒时间戳
  2. 使用系统实际时间生成时间戳字符串
  3. 线程安全

使用例程:

uint64_t timestamp;
std::string ts = mk::makeTimestamp(timestamp);
printf("Timestamp: %s, epoch: %lu\n", ts.c_str(), timestamp);

timeDiffMs() - 输出时间差

inline auto timeDiffMs(uint64_t t1, const char* msg) -> uint64_t;

参数说明:

  • t1 (输入): 上一个时间点(微秒时间戳)
  • msg (输入): 描述时间差的字符串

返回值: 当前时间点(微秒时间戳)

所有权归属:

  • 无所有权转移

注意事项:

  1. 如果 LogFlag 为 false,返回 0
  2. 自动计算时间差并输出到日志
  3. 时间差以毫秒为单位
  4. 线程安全

使用例程:

uint64_t t = 0;
mk::makeTimestamp(t);

// 执行操作
process_frame();

// 输出时间差
t = mk::timeDiffMs(t, "[Frame processing]");
// 输出: [Frame processing] = 15.234 ms

日志格式

默认格式

[YYYY-MM-DD HH:MM:SS.mmm] 消息

示例

[2026-02-01 10:30:45.123] Service started
[2026-02-01 10:30:46.456] Request failed with error: 404
[2026-02-01 10:30:47.789] Temperature: 23.5°C, Humidity: 45%

线程安全说明

同步机制

  • 日志输出: 使用 std::mutex 保护日志写入
  • 文件访问: 使用 FileStream RAII 管理文件资源

线程安全建议

  • 可以从多个线程并发记录日志
  • 日志格式化是线程安全的
  • 不要在日志函数中递归调用日志

典型使用场景

场景 1: 基本使用

int main() {
    Logger::initLogger();  // 初始化日志系统
    
    Logger::log(stdout, "Application started");
    Logger::log(stdout, "Version: %s", "1.0.0");
    
    return 0;
}

场景 2: 错误日志

try {
    initialize_device();
} catch (const std::exception& e) {
    Logger::log(stderr, "Exception caught: %s", e.what());
}

场景 3: 性能监控

uint64_t t = 0;
mk::makeTimestamp(t);

// 执行操作
process_frame(frame);

// 输出时间差
t = mk::timeDiffMs(t, "[Frame processing]");

场景 4: 多线程日志

std::thread t1([]() {
    for (int i = 0; i < 100; ++i) {
        Logger::log(stdout, "Thread 1: %d", i);
    }
});

std::thread t2([]() {
    for (int i = 0; i < 100; ++i) {
        Logger::log(stdout, "Thread 2: %d", i);
    }
});

t1.join();
t2.join();

场景 5: 禁用日志

// 禁用日志
Logger::LogFlag = false;

// 这些日志不会被输出
Logger::log(stdout, "This won't be logged");

// 重新启用日志
Logger::LogFlag = true;

Logger::log(stdout, "This will be logged");

注意事项

  1. 初始化: 必须先调用 initLogger() 才能使用其他日志方法
  2. LogFlag: 设置 LogFlag 为 false 可以禁用日志输出
  3. 线程安全: 日志记录是线程安全的
  4. 格式化: 使用 printf 风格的格式化字符串
  5. 时间戳: 自动添加毫秒级时间戳
  6. 文件管理: 使用 FileStream RAII 管理文件资源
  7. 移动语义: FileStream 支持移动语义,禁止拷贝
  8. 静默丢弃: 如果日志系统未初始化,消息将被静默丢弃

相关文档


参考资料

主页

API 文档

DMA 模块

DRM 模块

NET 模块

V4L2 模块

V4L2Param 模块

RGA 模块

MPP 模块

Sys 模块

Mouse 模块

Utils 模块

Clone this wiki locally