Sysklogd 系統日誌記錄器

概述

日誌對於系統的重要性不言而喻,好比對於故障診斷和入侵檢測,沒有日誌幾乎步履維艱。Linux系統中常見的日誌記錄器是 Sysklogd ,當前最新版本是 1.5 。php

Sysklogd 日誌記錄器由兩個守護進程(klogd syslogd)和一個配置文件(syslog.conf)組成。klogd 不使用配置文件,它負責截獲內核消息,它既能夠獨立使用也能夠做爲 syslogd 的客戶端運行。syslogd 默認使用 /etc/syslog.conf 做爲配置文件,它負責截獲應用程序消息,還能夠截獲 klogd 向其轉發的內核消息。支持 internet/unix domain sockets 的特性使得這兩個工具能夠用於記錄本地和遠程的日誌。linux

 

重要信息

  • syslogd 守護進程默認狀況下並不從 syslog/udp 端口接受任何消息,除非在命令行上使用了"-r"選項。此外,你還應當仔細看看"-l"和"-s"命令行選項。
  • syslogd 守護進程默認狀況下並不轉發任何來自遠程主機的消息,這是爲了不可能致使的日誌無限循環。"-h"選項能夠開啓轉發功能。
  • syslogd 會剝除來自同一個域範圍內的主機中的每條消息中的本地域(local domain)信息。若是你使用了日誌分析程序,請將這一特性牢記在心。
  • syslogd 不會更改任何文件的屬性,因此由它建立的文件將是全局可讀的。若是你不想這樣(好比"auth.*"被進行了記錄),你必須手動事先建立這些文件並設置相應的權限。
  • 若是某些程序發送了大量的日誌消息而且致使硬盤很是忙碌,你能夠考慮在每一行後面關閉fsync()特性。不過這樣可能會致使系統崩潰之後丟失一些日誌消息。
  • 若是你使用 init 來直接啓動 klogd 或 syslogd ,那麼須要在命令行上使用"-n"選項。
  • 若是 System.map 文件存在而且在 klogd 命令行上使用了"-k"的話,那麼它能夠解碼 EIP 地址。這個特性對於診斷系統崩潰很是有用,可是你必須確保 System.map 文件正確無誤。
  • 這兩個守護進程都會嘗試在收到退出信號時刪除他們的 .pid 文件,不過若是系統崩潰或者進程被"kill -9"結束,那麼可能就會來不及清理。這樣,下次啓動時就有可能會得到與之前殘留的 .pid 文件中的進程號相同的PID,從而致使沒法啓動(進程號衝突)。解決這個問題的最佳方案是系統的啓動腳本(rc.*)自身可以在系統啓動的最初就對這些 .pid 文件進行清理(一般是清空 /var/run 目錄)。
  • 大文件支持(能夠寫入大於 2 GB 的日誌)並非 syslogd 的功能,而是 glibc 的功能(使用不一樣的內核API進行調用)。要啓用大文件支持,你必須將 Makefile 中的相應註釋取消(兩個含有"-D_FILE_OFFSET_BITS"的行中的一個)。

內核的控制檯日誌等級

內核的控制檯日誌等級控制哪些內核消息會在控制檯上顯示。有兩種途徑能夠修改這個等級,一種是經過內核引導參數,另外一種,也是建議的途徑是經過 sysctl 來控制,一般這個設置位於 /etc/sysctl.conf 中。好比:shell

  kernel.printk = 4 4 1 7

[注意]控制檯日誌等級與內核消息等級是不一樣的概念,默認的內核消息等級(DEFAULT_MESSAGE_LOGLEVEL)是由內核在編譯時肯定的(CONFIG_DEFAULT_MESSAGE_LOGLEVEL),其默認值是"4"(WARNING)。而默認的控制檯日誌等級(DEFAULT_CONSOLE_LOGLEVEL)是"7"(debug),其含義是等級數字小於等於6的消息(優先級更高)都會顯示在控制檯上。緩存

安裝注意事項

  1. 仔細閱讀 README 和 man page 會減小你很多痛苦。目前全部文檔都已經放在man page中了。
  2. 按照你的需求修改 Makefile 而後再進行編譯。若是你沒有認真對待第一步,那麼可能會編譯出不合格的二進制程序。
  3. FSSTND(Linux文件系統標準)要求二進制文件和其配置文件必須位於不一樣的目錄。這個包默認狀況下遵照FSSTND的約定。你能夠經過修改 Makefile 文件和源代碼來修改配置文件的位置。
  4. 建議讓這兩個守護進程都以root身份運行,若是你想了解更多安全方面的問題,請閱讀 man page 。

下面是 Makefile 文件開頭的一部分節選,這部分是在安裝前可能須要改動的:安全

CC= gcc
SKFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce
# 啓用大文件支持,根據你的系統是32位仍是64位進行選擇
# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
# $(shell getconf LFS_SKFLAGS)
LDFLAGS= -s

# 指定 install 程序的位置
INSTALL = /usr/bin/install

# 安裝目錄
BINDIR = $(prefix)/usr/sbin
MANDIR = $(prefix)/usr/share/man

# 有bug報告說在一個純 ELF 系統上須要明確指定鏈接到 libresolv.a 庫。
# 若是你在鏈接 syslogd 時失敗,能夠試一試取消下面的註釋。
# LIBS = /usr/lib/libresolv.a

# 若是你在 ALPHA 平臺上鍊接失敗,能夠試一試取消下面的註釋。
# LIBS = ${LIBS} -linux

# 取消下面的註釋可讓 klogd 實現啓動延遲,這在 klogd 和 syslogd 並行啓動或啓動順序靠的很是近的時候頗有用。
# KLOGD_START_DELAY = -DKLOGD_DELAY=5

# 下面的定義表示文件位置遵照FSSTND標準。
FSSTND = -DFSSTND

# 下面的定義指定了 man page 的宿主和權限。
MAN_USER = root
MAN_GROUP = root
MAN_PERMS = 644

# 下面的定義指定了 syslogd 守護進程的 .pid 文件名,
# 源代碼(paths.h)中默認的文件名是"syslog.pid",但不少人認爲應當叫"syslogd.pid"。
# 你能夠在這裏指定你喜歡的名字。
SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\"

syslog.conf

syslog.conf 是 syslogd 進程的配置文件,將在程序啓動時讀取,默認位置是 /etc/syslog.conf 。它指定了一系列日誌記錄規則。規則的格式以下:服務器

facility.level    action

這個配置文件中的空白行和以"#"開頭的行將被忽略。"facility.level"部分也被稱爲選擇符(seletor)。 seletor 和 action 之間使用一個或多個空白分隔。dom

選擇符(seletor)

選擇符由 facility 和 level 兩部分組成,之間用一個句點(.)鏈接。這兩部分將在後面 syslogd 小節中詳細描述。下面提到的名字和 /usr/include/syslog.h 中的 LOG_-values 相一致。ssh

facility 指定了產生日誌的子系統,能夠是下面的關鍵字之一:socket

auth		由 pam_pwdb 報告的認證活動。
authpriv	包括私有信息(如用戶名)在內的認證活動
cron		與 cron 和 at 有關的信息。
daemon		與 inetd 守護進程有關的信息。
ftp		與 FTP 有關的信息
kern		內核信息,首先經過 klogd 傳遞。
lpr		與打印服務有關的信息。
mail		與電子郵件有關的信息
mark		syslog 內部功能用於生成時間戳
news		來自新聞服務器的信息
syslog		由 syslog 生成的信息
user		由用戶程序生成的信息
uucp		由 uucp 生成的信息
local0 ~ local7	由自定義程序使用,例如使用 local5 作爲 ssh 功能
*		通配符表明除了 mark 之外的全部功能

在大多數狀況下,任何程序均可以經過任何 facility 發送日誌消息,可是通常都遵照約定俗成的規則。好比,只有內核才能使用"kern" facility 。tcp

level 指定了消息的優先級,能夠是下面的關鍵字之一(降序排列,嚴重性愈來愈低):

emerg	系統不可用
alert	須要當即被修改的條件
crit	阻止某些工具或子系統功能實現的錯誤條件
err	阻止工具或某些子系統部分功能實現的錯誤條件
warning	預警信息
notice	具備重要性的普通條件
info	提供信息的消息
debug	不包含函數條件或問題的其餘信息
none	沒有優先級,一般用於排錯
*	除了none以外的全部級別

facility 部分能夠是用逗號(,)分隔的多個子系統,而多個 seletor 之間也能夠經過分號(;)組合在一塊兒。須要注意的是,多個組合在一塊兒的選擇符,後面的會覆蓋前面的,這樣就容許從模式中排除一些優先級。

默認將對指定級別以及更嚴重級別的消息進行操做,可是能夠經過下面2個操做符進行修改。

等於操做符(=)表示僅對這個級別的消息進行操做,不等操做符(!)表示忽略這個級別以及更嚴重級別的消息。這兩個操做符能夠同時使用,不過"!"必須出如今"="的前面。

動做(action)

這個字段定義了對符合條件的消息進行何種操做,能夠選擇下列操做之一:

普通文件
將消息記錄到這個文件中,必須使用絕對路徑。若是在文件名以前加上減號(-),則表示不將日誌信息同步刷新到磁盤上(也就是使用寫入緩存),這樣能夠提升日誌寫入性能,可是增長了系統崩潰後丟失日誌的風險。
命名管道
在絕對路徑表示的FIFO文件(使用mkfifo命令建立)前加上管道符號(|)便可。一般用於調試。好比:|/usr/adm/debug
終端或者控制檯
好比:/dev/tty1 或 /dev/console
遠程主機
syslogd 可以將消息發送到遠程主機或從遠程主機接收消息,不過默認並不轉發接收到的消息。要將消息發送到遠程主機,能夠在主機名前加一個"@"便可。
逗號分隔的用戶名列表
critical 級別的消息除了記錄到日誌以外,一般還轉發到root用戶。
全部當前登陸的用戶
若是寫上一個星號(*)則表示向當前全部登陸的用戶顯示這條消息。

實例

下面的例子來自於實踐,但願可以對上面的內容作一個很好的示範以幫助理解。

              # 將全部 crit 級別的消息(排除全部內核消息)記錄在 critical 文件中
              #
              *.=crit;kern.none            /var/adm/critical

              # 首先記錄全部內核消息到 kernel 文件,
              # crit 級別以上的消息轉發到遠程同時在本地控制檯也顯示
              # 最後將info(包含)~err(不含)範圍的內核消息記錄到kernel-info文件(err和更高的級別被忽略)
              #
              kern.*                       /var/adm/kernel
              kern.crit                    @finlandia
              kern.crit                    /dev/console
              kern.info;kern.!err          /var/adm/kernel-info

              # 將剛好等於mail.info的消息顯示在第12個終端(tcpd默認使用mail.info)
              #
              mail.=info                   /dev/tty12

              # 將除mail.info以外的全部mail子系統消息記錄到mail文件
              #
              mail.*;mail.!=info           /var/adm/mail

              # 將全部mail.info和news.info消息記錄到info文件
              #
              mail,news.=info              /var/adm/info

              # 記錄全部info和notice級別的消息,來自mail子系統的除外
              #
              *.=info;*.=notice;mail.none  /var/log/messages

              # 記錄全部info級別的消息,來自mail和news子系統的除外
              #
              *.=info;mail,news.none       /var/log/messages

              # 向全部登陸用戶通知emerg級別的消息
              #
              *.=emerg                     *

              # 將全部alert以及更高級別的消息轉發到root,joey用戶的終端上(若是他們已經登陸)
              #
              *.alert                      root,joey

              # 將全部子系統的全部消息都發送到遠程名爲"finlandia"的主機
              *.*                          @finlandia

syslogd

syslogd 默認經過 /dev/log 這個 unix domain socket 來接收應用程序發送過來的消息,這個位置是由系統的基本C庫決定的。

這個程序的命令行參數以下:

syslogd  [ -a socket ] [ -f config-file ] [ -h ] [ -l hostlist ] [ -m interval ]
           [ -n ] [ -p socket ] [ -r ] [ -s domainlist ] [ -v ]

參數說明:

-a socket
指定額外須要監聽的 socket ,最多指定19個,能夠經過修改 syslogd.c 文件中的 MAXFUNIX 宏修改這個默認值。若是你將某些進程在chroot環境下運行,那麼這個選項就頗有用了。
-f config-file
指定配置文件的位置,默認是 /etc/syslog.conf 。
-h
默認狀況下 syslogd 並不轉發它接收到的遠程主機消息。指定這個選項後,進程將會把它接收到的遠程主機消息轉發到另外一個指定的遠程主機。
-l hostlist
指定一個分號(:)分隔的主機名列表,只記錄這些主機的 hostname 而不是全限定域名。
-m interval
syslogd 默認每隔20分鐘產生一個時間戳標記(-- MARK --)。這個選項用於修改這個默認值。設爲零將關閉這個特性。
-n
避免自動做爲後臺進程運行。若是由 init 來直接啓動和控制的話這個選項就必須使用。
-p socket
你能夠指定一個 unix domain socket 來代替默認的 /dev/log [這個位置是由libc決定的]
-r
從 internet domain socket 上接收遠程消息,也就是監遵從514端口上進來的UDP包。 默認不接受任何遠程消息。
-s domainlist
指定一個分號(:)分隔的域名列表,這些域名在記錄前都會被剝除。只能指定完整的域名。好比"-s north.de"並不會剝除"satu.infodrom.north.de"的尾巴,你必須這樣寫才行:
-s north.de:infodrom.north.de
-v
打印版本信息後退出。

信號

在運行時,syslogd 會將本身的進程號保存在 /var/run/syslogd.pid 文件中。因此可使用下面的命令向運行中的進程發送信號:

 kill -信號 `cat /var/run/syslogd.pid`
HUP
使得 syslogd 進程從新初始化。全部打開的文件都會被關閉,而後從新讀取配置文件,從新開始記錄。
TERM
安全退出
CHLD
若是當前正在向全部登陸的用戶發送消息,那麼等待這些子進程結束。

安全問題

流氓程序能夠經過向 syslogd 進程發送大量日誌信息來淹沒日誌文件或者耗盡磁盤空間。下面是一些建議:

  1. 經過防火牆來限制僅容許某些特定的主機訪問 514/UDP socket
  2. 將日誌文件放在獨立的分區上,這樣即便磁盤滿了也不會有很大的影響。
  3. ext2文件系統能夠保留必定的空間僅給root用戶使用。這要求將 syslogd 以非root身份運行。
  4. 禁止監聽 inet domain sockets 將會減小很多風險。

相關文件

/etc/syslog.conf
syslogd的配置文件
/dev/log
默認將從這個 Unix domain socket 讀取本地 syslog 消息
/var/run/syslogd.pid
包含 syslogd 進程號的文件

klogd

klogd 是一個專門截獲並記錄 Linux 內核消息的守護進程。其命令行語法以下:

klogd  [ -f file ] [ -iI ] [ -n ] [ -o ] [ -p ] [ -s ] [ -k file ] [ -v ] [ -x ] [ -2 ]

命令行參數說明:

-f file
將日誌直接記錄到指定的file中,而不是轉發到 syslogd 進程。
-i
-I
要求當前正在運行的 klogd 守護進程從新裝載內核符號表。
-i 用於讓守護進程從新裝載內核模塊符號。
-I 用於讓守護進程從新裝載靜態內核符號和內核模塊符號。
-n
禁止自動後臺運行,在 klogd 由 init 啓動並直接被 init 控制的狀況下必須使用此開關。
-o
klogd 在讀取並記錄全部內核消息緩衝區中的消息以後當即退出(不做爲守護進程)。
-p
只要 klogd 檢測到內核消息流中包含了一個 Oops 字符串,那麼就從新加載內核符號表。
-s
能夠經過兩個途徑獲取內核消息: /proc 文件系統和 sys_syslog 系統調用接口。雖然二者本質上徹底等價,但 klogd 會優先使用 /proc/kmsg 文件。這個開關則強制 klogd 使用系統調用獲取內核消息。
-k file
將指定的 file 做爲內核符號表文件,也就是System.map文件的位置。
-v
打印版本信息後退出。
-x
忽略 EIP 轉換信息,這樣就不須要讀取 System.map 文件。
-2
當展開符號時打印兩行,一行將地址轉換爲符號,一行是原始文本。這樣就容許一些外部程序(好比ksymoops)在原始數據上作一些處理。

消息轉發

若是 klogd 將內核消息轉發給 syslogd 進程,那麼它能夠分揀出某些特定的消息。原始內核消息的格式以下:

    <[0-7]>Something said by the kernel.

尖括號中的數字表示內核消息的優先級,這些數字的定義位於 kernel.h 文件中。當 klogd 收到內核消息以後,將會讀取這個數字,並在將此消息轉發給 syslogd 時按照這個數字分配適當的優先級。

若是使用 -f 將內核消息直接記錄到特定的文件中,那麼這條消息將保持原樣。

內核地址解析

klogd 會嘗試將內核地址解析爲對應的符號,若是你想獲得原始的地址信息,那麼可使用"-2"開關。若是沒有使用"-k"選項,那麼將會依次嘗試下面的路徑:

       /boot/System.map
       /System.map
       /usr/src/linux/System.map

由於內核模塊動態加載因此地址並不固定,這時就要使用"-i"/"-I"通知 klogd 內核模塊的變化。這兩個開關都將致使當前正在運行的 klogd 守護進程從新加載內核符號表。應當在每一次加載或者卸載內核模塊後當即運行下列命令:

       klogd -i

-p 開關也能夠用於更新內核符號表。它會讓 klogd 在檢測到保護性錯誤的時候從新加載內核符號表。使用這個開關須要當心,由於操做系統在出現保護性錯誤(protection fault)的時候已經變得不穩定了,而 klogd 必須執行系統調用才能從新裝載內核符號表,因此這樣作可能會致使更糟糕的結果。

控制檯日誌等級

內核默認的控制檯日誌等級(DEFAULT_CONSOLE_LOGLEVEL)是"7"(debug),也就是等級數字小於等於6的消息(優先級更高)都會顯示在控制檯上。這些不一樣等級所表明的意思位於 kernel.h 文件內,這個包內的 syslog.h 中也有一份拷貝。可使用 sysctl 來指定控制檯日誌等級,這一般是在 /etc/sysctl.conf 文件中設置的,好比下面這一行:

              kernel.printk = 4 4 1 7

就是把內核的控制檯日誌等級設爲了"4"。

信號處理

klogd 能夠響應8種信號: SIGHUP, SIGINT, SIGKILL, SIGTERM, SIGTSTP, SIGUSR1, SIGUSR2, SIGCONT 。SIGINT, SIGKILL, SIGTERM, SIGHUP 信號會讓進程優雅的正常退出。SIGTSTP 信號會讓進程中止記錄日誌並進入休眠狀態;SIGCONT 信號會讓處於休眠狀態的進程從新開始記錄日誌。組合使用 SIGSTOP 和 SIGCONT 能夠在不退出進程的狀況下切換日誌消息的來源。好比須要卸載 /proc 文件系統的時候,可使用下面的命令:

            # kill -TSTP pid
            # umount /proc
            # kill -CONT pid

SIGUSR1 和 SIGUSR2 用於加載/從新加載內核符號表。SIGUSR1 表示從新加載內核模塊的符號信息;SIGUSR2 表示同時從新加載模塊和靜態內核的符號信息。若是 System.map 文件位置正確,那麼 SIGUSR1 信號將很是有用。特別是在內核模塊改變的時候。

相關文件

/proc/kmsg
klogd 默認首選的獲取內核消息的來源
/var/run/klogd.pid
保存 klogd 的 PID 的文件
/boot/System.map, /System.map, /usr/src/linux/System.map
默認搜索的內核符號表位置
相關文章
相關標籤/搜索