linuxkernel如何印log
- Linux
- 2025-08-14
- 2
printk()
函数打印日志,支持多级优先级(如KERN_INFO/WARN/ERR),日志可经syslog传递至/var/log/messages或
基础日志打印函数
printk()
家族
这是最经典的内核日志接口,其原型定义为:
#define printk(fmt, ...) __printk(KERN_DEFAULT, fmt, ##__VA_ARGS__)
实际使用时需指定日志等级作为首个参数,完整形式为 printk(level, format, args)
,支持的日志等级如下表所示:
日志等级宏 | 数值 | 用途 | 典型场景 |
---|---|---|---|
KERN_EMERG |
0 | 系统不可用(Panic级) | 致命错误强制停机 |
KERN_ALERT |
1 | 必须立即处理的动作 | 硬件故障警告 |
KERN_CRIT |
2 | 严重错误 | 内存分配失败 |
KERN_ERR |
3 | 错误条件 | 设备驱动初始化失败 |
KERN_WARNING |
4 | 潜在问题预警 | 资源耗尽前的阈值提示 |
KERN_NOTICE |
5 | 正常但重要的事件 | 模块加载成功通知 |
KERN_INFO |
6 | 常规信息 | 协议协商过程记录 |
KERN_DEBUG |
7 | 调试信息 | 数据结构内容校验 |
示例代码:
// 记录网络包接收异常 printk(KERN_WARNING "eth%d: rx overrun detected, dropped %d packetsn", port_id, drop_count); // 调试USB枚举过程 printk(KERN_DEBUG "usb_probe: vid=%04x pid=%04x speed=%dn", idVendor, idProduct, speed);
dev_info()
/ dev_err()
系列
针对设备驱动设计的专用接口,自动关联设备实例:
struct device dev = &my_device->dev; dev_info(dev, "Temperature sensor reading: %d°Cn", temp); dev_err(dev, "I2C communication failed (err=%d)n", ret);
优势在于日志会自动携带设备路径信息(如input:0003:001A
),便于多设备环境下的问题排查。
子系统专属接口
许多内核子系统提供定制化日志方案:
- PCI子系统:
pci_udev_info()
/pci_udev_err()
- USB Gadget:
gadget_vdbg()
(虚拟调试总线) - Networking:
netdev_dbg()
/nl_info()
- Kobjects:
kobject_uevent()
触发用户态事件
日志控制机制
编译期配置
内核配置文件.config
中的以下选项直接影响日志行为:
| 配置项 | 默认值 | 作用 |
|———————-|——–|—————————————|
| CONFIG_PRINTK
| y | 启用标准printk
输出 |
| CONFIG_PRINTK_TIME
| y | 日志前缀添加时间戳(格式:[MMSS]) |
| CONFIG_DYNAMIC_DEBUG
| y | 支持动态调试标记开关 |
| CONFIG_DEBUG_KERNEL
| n | 全局禁用KERN_DEBUG
级日志 |
运行时过滤
通过/proc/sys/kernel/printk
文件实时调整日志策略:
# 查看当前设置 cat /proc/sys/kernel/printk # 输出示例:4 4 1 7 # 四个字段依次表示:console_loglevel loglevel min_loglevel defloglevel # 临时修改(重启后失效) echo "6 6 1 7" > /proc/sys/kernel/printk # 解释:将控制台和默认日志级别设为INFO(6),最低允许DEBUG(1)
持久化修改需写入/etc/sysctl.conf
或对应启动参数。
动态调试标记(Dynamic Debug)
现代内核提供的细粒度控制方案:
- 定义标记:在源码中添加
DEFINE_DD(name, description)
DEFINE_DD("pci_scan", "PCI bus scan progress");
- 使用标记:替换传统
printk
为dynamic_prin��k(DD_NAME, ...)
dynamic_printk(pci_scan, "Found device at %s irq=%dn", slot, irq);
- 运行时控制:通过
/sys/kernel/debug/dynamic_debug/control
文件启用特定标记:echo 'file pci.ko +p' > /sys/kernel/debug/dynamic_debug/control # 启用pci.ko模块中的所有p开头的调试标记
高级日志技术
Tracing Toolkits
工具名称 | 特点 | 适用场景 |
---|---|---|
FTrace | 轻量级函数调用追踪 | 性能热点分析 |
LTTng | 跨组件关联追踪 | 复杂事务流程可视化 |
SystemTap | 基于探针的实时数据分析 | 生产环境低扰动监控 |
Perf Events | CPU性能计数器集成 | 锁竞争、中断延迟测量 |
示例:使用FTrace记录进程调度延迟
# 挂载tracefs并启用调度器事件 mount -t tracefs none /sys/kernel/tracing echo sched: > /sys/kernel/tracing/set_event # 查看追踪结果 cat /sys/kernel/tracing/trace_pipe
Logbuffer管理
内核预分配环形缓冲区存储日志,可通过以下方式交互:
// 获取当前日志头部偏移量 unsigned long pos = __get_log_start(); // 手动刷新缓冲区到控制台 flush_log_buffer();
当缓冲区满时,旧日志会被覆盖,除非显式调用logbuf_lock()
进行同步。
外部输出渠道
除控制台外,还可重定向日志到:
- 串口终端:通过
ttyS
设备节点 - 网络日志服务器:配合
netconsole
驱动 - RAM磁盘:用于崩溃转储分析(搭配Kdump机制)
- 持久化存储:通过
printk_to_console=0
禁止控制台输出,改存文件系统
最佳实践建议
- 分级原则:严格按严重程度选择日志等级,避免滥用
KERN_DEBUG
被墙生产环境日志。 - 格式化规范:采用类似
"subsystem: event [details]"
的统一格式,方便日志解析工具处理。 - 性能考量:高频日志应使用
GFP_ATOMIC
标志避免睡眠,关键路径考虑禁用彩色转义序列。 - 安全审计:涉及敏感数据的日志需做脱敏处理,防止侧信道攻击。
- 模块化设计:将日志字符串提取到头文件,便于多语言翻译和维护。
相关问答FAQs
Q1: 为什么有时printk
不显示任何输出?
A: 可能原因包括:①日志级别被过滤(检查/proc/sys/kernel/printk
设置);②未启用CONFIG_PRINTK
或CONFIG_PRINTK_TIME
;③在中断上下文中使用了阻塞式日志函数;④日志被重定向到非可见设备(如串口未连接),建议通过dmesg -w
命令强制刷新日志缓冲区查看完整输出。
Q2: 如何在用户态查看内核日志?
A: 常用方法有三种:①dmesg
命令读取/proc/kmsg
管道;②journalctl -k
查看systemd期刊中的内核日志;③直接读取/proc/sys/kernel/printk
了解当前日志策略,对于历史日志,可检查/var/log/kern.log
或`/var/log/messages