Expand description
内核日志子系统
该模块提供了一个类似 Linux 内核风格的日志系统,并在裸机环境中实现了无锁环形缓冲区。
§组件
buffer- 用于日志存储的无锁环形缓冲区config- 配置常量(缓冲区大小、消息长度限制)context- 上下文信息收集(CPU ID、任务 ID、时间戳)log_core- 核心日志实现 (LogCore)entry- 日志条目结构和序列化level- 日志级别定义(从 Emergency 到 Debug)macros- 面向用户的日志宏 (pr_info!,pr_err!, 等)
§设计概览
§双输出策略
日志系统采用两层方法:
- 即时控制台输出:达到控制台级别阈值(默认:Warning 及以上)的日志会直接打印到控制台,以实现紧急可见性。
- 环形缓冲区存储:所有达到全局级别阈值(默认:Info 及以上)的日志都会被写入无锁环形缓冲区,用于异步消费或事后分析。
§性能特点
- 无锁并发:使用原子操作(fetch_add, CAS)而非互斥锁,支持多生产者日志记录而不会阻塞。
- 早期过滤:日志级别检查在宏展开时发生,避免对禁用级别的日志进行格式化字符串评估。
- 固定大小分配:没有动态内存分配;所有结构体使用编译时已知的大小,适用于裸机环境。
- 缓存优化:读写器数据结构经过缓存行填充(64 字节),以防止多核系统上的伪共享。
- 尽可能零拷贝:在可行的情况下,日志条目是就地构造的,以最大限度地减少内存操作。
§架构特定集成
日志系统与架构特定组件集成:
- 定时器:通过
arch::timer::get_time()收集时间戳 - 控制台:通过
console::Stdout输出(通常是 UART) - CPU ID:通过
arch::kernel::cpu::cpu_id()获取当前 CPU ID - 任务 ID:通过
kernel::cpu::current_cpu()获取当前任务的 tid(若无任务则为 0)
§使用示例
use crate::log::*;
// 基本日志记录
pr_info!("内核已初始化");
pr_err!("分配 {} 字节失败", size);
// 配置日志级别
set_global_level(LogLevel::Debug); // 记录所有级别
set_console_level(LogLevel::Error); // 只打印错误及以上的级别
// 读取缓冲的日志
while let Some(entry) = read_log() {
// 处理日志条目
}Re-exports§
pub use config::DEFAULT_CONSOLE_LEVEL;pub use config::DEFAULT_LOG_LEVEL;pub use config::GLOBAL_LOG_BUFFER_SIZE;pub use config::MAX_LOG_MESSAGE_LENGTH;pub use entry::LogEntry;pub use level::LogLevel;pub use log_core::format_log_entry;
Modules§
- buffer 🔒
- 锁无关的日志存储环形缓冲区
- config 🔒
- 日志系统配置常量
- context 🔒
- 日志上下文收集
- entry 🔒
- 日志条目结构和序列化
- level 🔒
- 日志级别定义
- log_
core 🔒 - 日志系统核心实现
- macros
- 日志宏
Statics§
- GLOBAL_
LOG 🔒 - 全局日志系统实例
Functions§
- get_
console_ level - 获取当前控制台输出级别
- get_
global_ level - 获取当前全局日志级别
- log_
dropped_ count - 返回已丢弃日志的计数
- log_len
- 返回未读日志条目的数量
- log_
reader_ index - 获取当前可读取的起始索引
- log_
unread_ bytes - 返回未读日志的总字节数(格式化后)
- log_
writer_ index - 获取当前写入位置
- peek_
log - 非破坏性读取:按索引 peek 日志条目,不移动读指针
- read_
log - 从缓冲区读取下一个日志条目
- set_
console_ level - 设置控制台输出级别阈值
- set_
global_ level - 设置全局日志级别阈值