Linux内核日志分级
内核printk分级
定义
内核代码source/kernel_src/kernel/kernel-4.9/include/linux/kernel.h
中,定义了控制台console的级别:
#define CONSOLE_LOGLEVEL_SILENT 0 /* Mum's the word */
#define CONSOLE_LOGLEVEL_MIN 1 /* Minimum loglevel we let people use */
#define CONSOLE_LOGLEVEL_QUIET 4 /* Shhh ..., when booted with "quiet" */
#define CONSOLE_LOGLEVEL_DEFAULT 7 /* anything MORE serious than KERN_DEBUG */
#define CONSOLE_LOGLEVEL_DEBUG 10 /* issue debug messages */
#define CONSOLE_LOGLEVEL_MOTORMOUTH 15 /* You can't shut this one up */
extern int console_printk[];
#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])
#define default_devkmsg_loglevel (console_printk[4])
内核代码source/kernel_src/kernel/kernel-4.9/kernel/printk/printk.c
中,定义了console_printk结构体:
int console_printk[5] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
MESSAGE_LOGLEVEL_DEFAULT, /* default_devkmsg_loglevel */
};
使用
内核中使用printk函数时加上信息级别,例如:
printk(KERN_WARNING "there is a warning here!\n");
KERN_WARNING就表示信息的级别,相关宏在函数source/kernel_src/kernel/kernel-4.9/include/linux/kernel.h
中定义:
#define KERN_SOH "\001" /* ASCII Start Of Header */
#define KERN_EMERG KERN_SOH "0" /* system is unusable */
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
#define KERN_CRIT KERN_SOH "2" /* critical conditions */
#define KERN_ERR KERN_SOH "3" /* error conditions */
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
#define KERN_INFO KERN_SOH "6" /* informational */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
如果没有指明信息级别的话,就会采用默认的信息级别:
#define default_message_loglevel (console_printk[1])
设置
控制台console的级别默认是"6 6 1 7 4",可以修改用户空间的/proc/sys/kernel/printk
,例如:
echo “1 1 4 1 7” > /proc/sys/kernel/printk
自定义printk分级
在工作中,log分级只需要划分debug和release,因此设计自定义的printk分级。
定义
添加source/kernel_src/kernel/custom/include/linux/custom_debug.h
,定义custom_printk:
#define CUSTOM_ERROR(f, arg...) \
printk(KERN_ERR "custom_error: %s->%s->%d: " f, __FILE__, __func__, __LINE__, ## arg)
#define CUSTOM_WARNING(f, arg...) \
printk(KERN_WARNING "custom_warning: " f, ## arg)
#define CUSTOM_NOTICE(f, arg...) \
printk(KERN_NOTICE "custom_notice: " f, ## arg)
#define CUSTOM_INFO(f, arg...) \
printk(KERN_INFO "custom_info: " f, ## arg)
#define CUSTOM_DEBUG(f, arg...) \
do { \
if (custom_loglevel) \ // 修改Makefile, 编译时添加到generated.h
printk(KERN_DEBUG "custom_debug: %s->%s->%d: " f, __FILE__, __func__, __LINE__, ## arg); \
}while (0)
接口
添加cutom_printk.c
:
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/custom_debug.h>
int custom_loglevel = CUSTOM_DEBUG_ON;
static char *custom_printk[] = {"release", "debug"};
static int loglevel_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%s\n", custom_printk[custom_loglevel]);
return 0;
}
static int loglevel_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, loglevel_proc_show, NULL);
}
static ssize_t loglevel_proc_write(struct file *file, const char *buffer, unsigned long count, loff_t *pos)
{
unsigned long ret = count;
char *log_type = kzalloc(10, GFP_KERNEL);
if (copy_from_user((void *)log_type, (const void __user *)buffer, count))
ret = -EFAULT;
if (sysfs_streq(log_type, custom_printk[0])) // release
custom_loglevel = 0;
else if (sysfs_streq(log_type, custom_printk[1])) // debug
custom_loglevel = 1;
else
ret = -EINVAL;
kfree(log_type);
return ret;
}
static const struct file_operations loglevel_proc_fops = {
.open = loglevel_proc_open,
.write = loglevel_proc_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init proc_loglevel_init(void)
{
proc_create("loglevel", 0666, NULL, &loglevel_proc_fops);
return 0;
}
fs_initcall(proc_loglevel_init);
使用
// 包含头文件
#include <linux/custom_debug.h>
// 打印一般信息
CUSTOM_INFO("%s: the platform-name is %s\n", __func__, str);
// 打印错误信息
CUSTOM_ERROR("%s: no platform-name property\n", __func__);
// 打印DEBUG信息
CUSTOM_DEBUG("%s", __func__);
设置
修改用户空间的/proc/loglevel
,可以控制是否打印log(到console和syslog):