天天看點

Linux 日志級别(loglevel)詳解

前幾天,我在想printk中到底是哪些資訊會列印到console上,哪些東西可以通過dmesg來檢視。參考了網上一些資料以及自己做的一些實驗,總結一下Linux中的console loglevel以及printk, dmesg知識。

隻有當printk列印資訊時的loglevel小于console loglevel的值(即:優先級高于console loglevel),這些資訊才會被列印到console上。

改變console loglevel的方法有如下幾種:

1.啟動時Kernel boot option:loglevel=level

2.運作時Runtime: dmesg -n level

(注意:demsg -n level 改變的是console上的loglevel,dmesg指令仍然會列印出所有級别的系統資訊。)

3.運作時Runtime: echo $level > /proc/sys/kernel/printk

4.運作時Runtime:寫程式使用syslog系統調用(可以man syslog)

#include <unistd.h>

#include <sys/syscall.h>

static inline int syslog(int type, char *bufp, int len)

{

return syscall(SYS_syslog, type, bufp, len);

}

int main()

{

/* Set the console loglevel to 4 */

syslog(8, 0, 4);

return 0;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#include <unistd.h>

#include <sys/syscall.h>

static inline intsyslog(inttype,char *bufp,int len)

{

returnsyscall(SYS_syslog,type,bufp,len);

}

intmain()

{

/*Set theconsole loglevel to 4*/

syslog(8,0,4);

return0;

}

在kernel boot option中:

loglevel Set the default console log level. loglevel=level Specify the initial console log level. Any log messages with levels less than this (that is, of higher priority) will be printed to the console, whereas any messages with levels equal to or greater than this will not be displayed. The console log level can also be changed by the klogd program, or by writing the specified level to the /proc/sys/kernel/printk file. (在2.6.32及之上kernel的Linux系統中,我沒有找到klogd這個程式了,應該是有所變化了)​

​The kernel log levels are: 0 (KERN_EMERG) The system is unusable. 1 (KERN_ALERT) Actions that must be taken care of immediately. 2 (KERN_CRIT) Critical conditions. 3 (KERN_ERR) Noncritical error conditions. 4 (KERN_WARNING) Warning conditions that should be taken care of. 5 (KERN_NOTICE) Normal, but significant events. 6 (KERN_INFO) Informational messages that require no action. 7 (KERN_DEBUG) Kernel debugging messages, output by the kernel if the developer enabled debugging at compile time.

KERN_ERR, KERN_DEBUG等是一些宏定義,在$Linux_SRC/include/linux/printk.h中可以檢視到。

dmesg是從kernel的ring buffer(環緩沖區)中讀取資訊的.

man dmesg得到如下資訊:

​dmesg is used to examine or control the kernel ring buffer. The program helps users to print out their bootup messages. Instead of copying the messages by hand, the user need only: dmesg > dmesg.log​

那什麼是ring buffer呢?

在LINUX中,所有的系統資訊(包核心資訊)都會傳送到ring buffer中。而核心産生的資訊由printk()列印出來。系統啟動時所看到的資訊都是由該函數列印到螢幕中。printk()打出的資訊往往以 <0>…<2>… 這的數字表明消息的重要級别。高于一定的優先級别(目前的console loglevel)就會列印到console上,否則隻會保留在系統的緩沖區中(ring buffer)。

至于dmesg具體是如何從ring buffer中讀取的,大家可以看dmesg.c源代碼。$Linux-SRC/arch/m68k/tools/amiga/dmesg.c,很短,比較容易讀懂。

預設的loglevel在kernel/printk.c中有定義:

/* printk's without a loglevel use this.. */

#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL

/* We show everything that is MORE important than this.. */

#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */

#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */

DECLARE_WAIT_QUEUE_HEAD(log_wait);

int console_printk[4] = {

DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */

DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */

MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */

DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */

};

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/*printk'swithout aloglevel use this..*/

#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL

/*We show everythingthat isMORE important than this..*/

#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */

#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */

DECLARE_WAIT_QUEUE_HEAD(log_wait);

int console_printk[4]= {

        DEFAULT_CONSOLE_LOGLEVEL,      /*console_loglevel */

        DEFAULT_MESSAGE_LOGLEVEL,      /*default_message_loglevel*/

        MINIMUM_CONSOLE_LOGLEVEL,      /*minimum_console_loglevel*/

        DEFAULT_CONSOLE_LOGLEVEL,      /*default_console_loglevel*/

};

cat /proc/sys/kernel/printk

4 4 1 7

所得到的資訊是$Linux_SRC/include/linux/printk.h中定義的宏:

#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])

依次分别為:

控制台日志級别:優先級高于該值的消息将被列印至控制台

預設的消息日志級别:将用該優先級來列印沒有優先級的消息

最低的控制台日志級别:控制台日志級别可被設定的最小值(最高優先級)

預設的控制台日志級别:控制台日志級别的預設值

為了下面我做的一個實驗:

首先,需要一個module,我的loglevel.c代碼如下:

#include <linux/module.h> /* Needed by all modules */

#include <linux/kernel.h> /* Needed for log level */

#include <linux/init.h> /* Needed for the macros */

MODULE_AUTHOR("Jay, <Jay's email> ");

MODULE_DESCRIPTION("To test: console log level.");

MODULE_LICENSE("GPL");

MODULE_VERSION("Version-0.0.1");

static int __init hello_start(void)

{

printk(KERN_INFO "Loading loglevel module...\n");

printk(KERN_INFO "Hello, Jay.\n");

printk(KERN_EMERG "------------------------------------\n");

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");

printk(KERN_EMERG "------------------------------------\n");

return 0;

}

static void __exit hello_end(void)

{

printk(KERN_INFO "Goodbye, Jay.\n");

}

module_init(hello_start);

module_exit(hello_end);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

#include <linux/module.h>       /* Needed by all modules */

#include <linux/kernel.h>       /* Needed for log level */

#include <linux/init.h>         /* Needed for the macros */

MODULE_AUTHOR("Jay, <Jay's email> ");

MODULE_DESCRIPTION("To test: console log level.");

MODULE_LICENSE("GPL");

MODULE_VERSION("Version-0.0.1");

static int__init hello_start(void)

{

printk(KERN_INFO"Loading loglevel module...\n");

printk(KERN_INFO"Hello, Jay.\n");

printk(KERN_EMERG"------------------------------------\n");

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");

printk(KERN_EMERG"------------------------------------\n");

return0;

}

static void __exithello_end(void)

{

printk(KERN_INFO"Goodbye, Jay.\n");

}

module_init(hello_start);

module_exit(hello_end);

将這個module編譯好之後,有了loglevel.ko這個module檔案。

[root@vt-snb9 ~]# cat /proc/sys/kernel/printk

7 4 1 7

[root@vt-snb9 ~]# insmod /root/loglevel/loglevel.ko

1

2

3

[root@vt-snb9~]# cat /proc/sys/kernel/printk

7      4      1       7

[root@vt-snb9~]# insmod /root/loglevel/loglevel.ko

console上列印的資訊如下:

##注意DEBUG級别的資訊沒有列印在console上

Loading loglevel module…

Hello, Jay.

————————————

Hello, EMERG.

Hello, ALERT.

Hello, CRIT.

Hello, ERR.

Hello, WARNING.

Hello, NOTICE.

Hello, INFO.

————————————

改變console loglevel之後,

[root@vt-snb9 ~]# cat /proc/sys/kernel/printk

4 4 1 7

[root@vt-snb9 ~]# insmod /root/loglevel/loglevel.ko

1

2

3

[root@vt-snb9~]# cat /proc/sys/kernel/printk

4      4      1       7

[root@vt-snb9~]# insmod /root/loglevel/loglevel.ko

##注意”Hello, Jay.”這樣的INFO級别的就沒有列印到console上

————————————

Hello, EMERG.

Hello, ALERT.

Hello, CRIT.

Hello, ERR.

————————————

在kernel啟動項目中加入了debug,則啟動後:

[root@vt-snb9 ~]# cat /proc/sys/kernel/printk

10 4 1 7

[root@vt-snb9 ~]# insmod /root/loglevel/loglevel.ko

1

2

3

[root@vt-snb9~]# cat /proc/sys/kernel/printk

10      4      1       7

[root@vt-snb9~]# insmod /root/loglevel/loglevel.ko

##注意這次DEBUG等級的資訊也被列印在console上了

Loading loglevel module…

Hello, Jay.

————————————

Hello, EMERG.

Hello, ALERT.

Hello, CRIT.

Hello, ERR.

Hello, WARNING.

Hello, NOTICE.

Hello, INFO.

Hello, DEBUG.

————————————

而dmesg始終都是可以列印出module所print出來的所有資訊的,不管console loglevel為多少,當insmod loglevel之時,dmesg始終會列印如下資訊:

Loading loglevel module... Hello, Jay. ------------------------------------ Hello, EMERG. Hello, ALERT. Hello, CRIT. Hello, ERR. Hello, WARNING. Hello, NOTICE. Hello, INFO. Hello, DEBUG. ------------------------------------

另外,最後見說一下syslogd吧(或者新的叫做rsyslogd程序)。 在比較新的系統(比如RHEL6.1)中,syslogd已經存在了,取而代之的是rsyslogd,功能是差不多的,配置檔案在/etc/rsyslogd.conf

syslogd這個守護程序根據/etc/syslog.conf,将不同的服務産生的Log記錄到不同的檔案中.

LINUX系統啟動後,由/etc/init.d/sysklogd先後啟動klogd,syslogd兩個守護程序。

其中klogd會通過syslog()系統調用或者讀取/proc/kmsg檔案來從系統緩沖區(ring buffer)中得到由核心printk()發出的資訊.而syslogd是通過klogd來讀取系統核心資訊.

(1)所有系統資訊是輸出到ring buffer中去的,dmesg所顯示的内容也是從ring buffer中讀取的.

(2)LINUX系統中/etc/init.d/sysklogd會啟動2個守護程序:Klogd, Syslogd

(3)klogd是負責讀取核心資訊的,有2種方式:

syslog()系統調用(這個函數用法比較全,大家去MAN一下看看);

直接的對/proc/kmsg進行讀取(再這提一下,/proc/kmsg是專門輸出核心資訊的地方)

(4)Klogd的輸出結果會傳送給syslogd進行處理,syslogd會根據/etc/syslog.conf的配置把log資訊輸出到/var/log/下的不同檔案中.

可以将printk與syslog接合使用, 用在核心開發方面很不錯的應用:

修改/etc/syslog.conf (或者是/etc/rsyslogd.conf)

kern.* /tmp/my_kernel_debug.txt

就可将kernel的資訊輸出到檔案中了,這樣更友善檢視。

日志檔案詳細地記錄了系統每天發生的各種各樣的事件。使用者可以通過日志檔案檢查錯誤産生的原因,或者在受到攻擊和黑客入侵時追蹤攻擊者的蹤迹。日志的兩個比較重要的作用是:稽核和監測。

Linux系統的日志主要分為兩種類型:

1.程序所屬日志

由使用者程序或其他系統服務程序自行生成的日志,比如伺服器上的access_log與error_log日志檔案。

2.syslog消息 【syslogd, klogd協同作用,前面以及提及,新版本中都沒了klogd了】

系統syslog記錄的日志,任何希望記錄日志的系統程序或者使用者程序都可以給調用syslog來記錄日志。

日志系統可以劃分為三個子系統:

1.連接配接時間日志–由多個程式執行,把紀錄寫入到/var/log/wtmp和/var/run/utmp,login等程式更新wtmp和utmp檔案,使系統管理者能夠跟蹤誰在何時登入到系統。

2.程序統計–由系統核心執行。當一個程序終止時,為每個程序往程序統計檔案(pacct或acct)中寫一個紀錄。程序統計的目的是為系統中的基本服務提供指令使用統計。

3.錯誤日志–由syslogd(8)執行。各種系統守護程序、使用者程式和核心通過syslog(3)向檔案/var/log/messages報告值得注意的事件。

Related posts:

  1. ​​Linux kernel啟動參數

    ​​

  2. ​​更新Linux核心頭檔案(linux headers)

    ​​

  3. ​​Linux kernel編譯生成的版本多一個加号“+”

    ​​

  4. ​​Linux Kernel核心配置方式詳解

    ​​

繼續閱讀