当前位置:首页 > Linux > 正文

linuxkernel如何印log

Linux内核通过 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),便于多设备环境下的问题排查。

linuxkernel如何印log  第1张

子系统专属接口

许多内核子系统提供定制化日志方案:

  • PCI子系统pci_udev_info()/pci_udev_err()
  • USB Gadgetgadget_vdbg()(虚拟调试总线)
  • Networkingnetdev_dbg()/nl_info()
  • Kobjectskobject_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)

现代内核提供的细粒度控制方案:

  1. 定义标记:在源码中添加DEFINE_DD(name, description)
    DEFINE_DD("pci_scan", "PCI bus scan progress");
  2. 使用标记:替换传统printkdynamic_prin��k(DD_NAME, ...)
    dynamic_printk(pci_scan, "Found device at %s irq=%dn", slot, irq);
  3. 运行时控制:通过/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禁止控制台输出,改存文件系统

最佳实践建议

  1. 分级原则:严格按严重程度选择日志等级,避免滥用KERN_DEBUG被墙生产环境日志。
  2. 格式化规范:采用类似"subsystem: event [details]"的统一格式,方便日志解析工具处理。
  3. 性能考量:高频日志应使用GFP_ATOMIC标志避免睡眠,关键路径考虑禁用彩色转义序列。
  4. 安全审计:涉及敏感数据的日志需做脱敏处理,防止侧信道攻击。
  5. 模块化设计:将日志字符串提取到头文件,便于多语言翻译和维护。

相关问答FAQs

Q1: 为什么有时printk不显示任何输出?

A: 可能原因包括:①日志级别被过滤(检查/proc/sys/kernel/printk设置);②未启用CONFIG_PRINTKCONFIG_PRINTK_TIME;③在中断上下文中使用了阻塞式日志函数;④日志被重定向到非可见设备(如串口未连接),建议通过dmesg -w命令强制刷新日志缓冲区查看完整输出。

Q2: 如何在用户态查看内核日志?

A: 常用方法有三种:①dmesg命令读取/proc/kmsg管道;②journalctl -k查看systemd期刊中的内核日志;③直接读取/proc/sys/kernel/printk了解当前日志策略,对于历史日志,可检查/var/log/kern.log或`/var/log/messages

0