一.printk
printk函數主要做兩件事情:第一件就是將信息記錄到log中,而第二件事就是調用控制台驅動來將信息輸出。printk的相關函數定義在linux/printk.h。
1.日志級別
printk需要設置日志級別,用來控制printk打印的這條信息是否在終端上顯示的,當printk設置的日志級別高於控制台級別時,printk要打印的信息才會在控制台打印出來。
內核日志一共有8種級別:
#define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ #define KERN_ERR "<3>" /* error conditions */ #define KERN_WARNING "<4>" /* warning conditions */ #define KERN_NOTICE "<5>" /* normal but significant condition */ #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */
2.控制台級別
#define MINIMUM_CONSOLE_LOGLEVEL 1 /*可以使用的最小日志級別*/ #define DEFAULT_CONSOLE_LOGLEVEL 7 /*默認的控制台級別*/ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* 默認的日志級別 */ int console_printk[4] = { DEFAULT_CONSOLE_LOGLEVEL,/*控制台日志級別:優先級高於該值的消息將被打印至控制台*/ DEFAULT_MESSAGE_LOGLEVEL,/*缺省的消息日志級別:將用該優先級來打印沒有優先級的消息*/ MINIMUM_CONSOLE_LOGLEVEL,/*最低的控制台日志級別:控制台日志級別可被設置的最小值(最高優先級)*/ DEFAULT_CONSOLE_LOGLEVEL,/*缺省的控制台日志級別:控制台日志級別的缺省值*/ }; #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])
使用命令 cat /proc/sys/kernel/printk來查看這四個值
其中的 4 4 1 7,分別對應與:console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel
default_message_loglevel是缺省時的消息日志級別,因此當printk未指定優先級時,將以該默認級別輸出,也就是DEFAULT_MESSAGE_LOGLEVEL =4, 對應KERN_WARNING。
也就是說printk("hello world\n");就表示printk(KERN_WARNING "hello world\n");
那如果我們將控制台級別設成<4,如:
Echo 3 > /proc/sys/kernel/printk
那么printk("hello world\n");就無法輸出到控制台。
3.如何修改控制台級別
Echo "n" > /proc/sys/kernel/printk
Eg: Echo 8 > /proc/sys/kernel/printk
那么此時所有的printk日志級別都會被輸出到控制台,如下圖所示。
printk ( KERN_EMERG "Hello, EMERG.\n" ) ; printk ( KERN_ALERT "Hello, ALERT.\n" ) ; printk ( KERN_CRIT "Hello, CRIT.\n" ) ; printk ( KERN_ERR "Hello, ERR.\n" ) ; printk ( KERN_WARNING "Hello, WARNING.\n" ) ; printk ( KERN_NOTICE "Hello, NOTICE.\n" ) ; printk ( KERN_INFO "Hello, INFO.\n" ) ; printk ( KERN_DEBUG "Hello, DEBUG.\n" ) ;
除了上面的方法修改console打印級別外,還可以修改bootargs來設定:
Uboot中修改“console=ttyS0,115200”改為“loglevel=7 console=ttyS0,115200”,表示設置內核的console_loglevel 值=7,開機cat /proc/sys/kernel/printk,可以看到控制台級別被設置成了7。
4. printk帶時間戳訊息
make menuconfig開啟如下:
二 linux/prink.h相關函數
#define pr_emerg(fmt, ...) \ printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) #define pr_alert(fmt, ...) \ printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) #define pr_crit(fmt, ...) \ printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) #define pr_err(fmt, ...) \ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) #define pr_warning(fmt, ...) \ printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) #define pr_warn pr_warning #define pr_notice(fmt, ...) \ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) #define pr_info(fmt, ...) \ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
/* If you are writing a driver, please use dev_dbg instead */ #if defined(CONFIG_DYNAMIC_DEBUG) #include <linux/dynamic_debug.h> /* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */ #define pr_debug(fmt, ...) \ dynamic_pr_debug(fmt, ##__VA_ARGS__) #elif defined(DEBUG) #define pr_debug(fmt, ...) \ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #else #define pr_debug(fmt, ...) \ no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #endif
pr_emerg到pr_info都是一些基本的kernel打印函數,用來設置內核日志打印級別,可以看到它和下面這種打印本質上並無差異。
printk ( KERN_EMERG "Hello, EMERG.\n" ) ; printk ( KERN_ALERT "Hello, ALERT.\n" ) ; printk ( KERN_CRIT "Hello, CRIT.\n" ) ; printk ( KERN_ERR "Hello, ERR.\n" ) ; printk ( KERN_WARNING "Hello, WARNING.\n" ) ; printk ( KERN_NOTICE "Hello, NOTICE.\n" ) ; printk ( KERN_INFO "Hello, INFO.\n" ) ; printk ( KERN_DEBUG "Hello, DEBUG.\n" ) ;
而pr_debug則有3種輸出方式,當開啟dynamic_debug后,則走dynamic_pr_debug流程(dynamic_debug見下一節)。當用戶開啟了DEBUG宏,則走printk流程,否則什么都不打印。
三 dmesg命令
那kernel中printk所有日志級別的打印都會將開機信息存儲在ring buffer中。dmesg命令是從kernel ring buffer中讀取內核日志信息。開機信息亦保存在/var/log目錄中,名稱為dmesg的文件里。因此可以用dmesg
命令查看。
-c: 當完成打印顯示后清除環緩沖內的內容。
-s: 緩沖區大小
定義一個大小為"緩沖區大小"的緩沖區用於查詢內核環緩沖區。默認大小為 8196,如果你設置了一個大於默認值的環緩沖區,那你就可以用這個選項定義一個相當的緩沖區來查看完整的環緩沖區內容。
-n:級別
其實用dmesg -n也是可以設置控制台打印級別。
有時候在調試kernel驅動時內核panic了or死鎖了,那么無法敲命令,如何查看日志呢?重啟后日志就沒了,那么可以敲如下命令:
cat /proc/kmsg > /mnt/data/ker.log & 2>&1
用后台進程將日志導入到文件。