天天看點

syslog的點滴--集中處理日志

syslogd和klogd是很有意思的守護程序,syslogd是一個分發器,它将接收到的所有日志按照/etc/syslog.conf的配置政策發送到這些日志應該去的地方,當然也包括從klogd接收到的日志,klogd首先接收核心的日志,然後将之發送給syslogd,klogd是怎麼接收核心的日志,接收到的日志又是怎麼發給syslogd的呢?過程其實很簡單,klogd通過讀取/proc/kmsg來接收核心的日志,通過strace -p可以看到:

read(0, "<6>ACPI: PCI interrupt 0000:05:0"..., 4095) = 95

time([1278013550])                      = 1278013550

write(1, "<6>Jul  1 15:45:50 kernel: ACPI:"..., 97) = 97

為了看清楚0和1分别代表什麼,看一下/proc檔案系統:

ll /proc/XX/fd/

total 3

lr-x------    1 root     root           64 2010-07-01 15:43 0 -> /proc/kmsg

lrwx------    1 root     root           64 2010-07-01 15:43 1 -> socket:[7974]

lr-x------    1 root     root           64 2010-07-01 15:43 2 -> /boot/System.map...

或者通過lsof -p XX檢視也是可以的。經過解析指令的輸出,發現klogd從/proc/kmsg中讀取了核心資訊,然後寫入了一個套接字,這個套接字的另一端肯定是syslogd使用的套接字,并且syslogd肯定從該套接字的另一端接收了資料,用strace和lsof/ll /proc/YY/fd/證明一下:

ll /proc/YY/fd

total 18

lrwx------    1 root     root           64 2010-07-01 15:21 0 -> socket:[4146]

l-wx------    1 root     root           64 2010-07-01 15:21 1 -> /var/log/auth.log

...

l-wx------    1 root     root           64 2010-07-01 15:21 8 -> /var/log/uucp.log

l-wx------    1 root     root           64 2010-07-01 15:21 9 -> /var/log/mail.info

确實是這樣的,syslogd中确實使用了一個套接字,為了證明确實從該套接字接收到了klogd發來的資料,在兩個終端上同時strace -p syslogd和klogd,然後加載一個驅動或者自己寫一個printk的核心子產品,然後觀察兩個終端的輸出,确實klogd從0讀出了資訊abc,然後寫入了1,syslogd從0讀出了abc,然後寫入了一個配置好的日志檔案,它們之間是通過套接字來完成通信的。同樣的,庫函數syslog将klogd的大緻過程進行了封裝,這樣任何程式都可以調用syslog函數進行日志記錄了,syslogd成了整個系統統一的一個日志記錄器,下面是在syslog的manpage上得到的函數原型:

void openlog(const char *ident, int option, int facility); //ident設定為一個可被過濾的特征字元串,一般為應用程式的名字

void syslog(int priority, const char *format, ...);

void closelog(void);

此處的syslog庫函數内部實作的就是套接字發送過程,沒有什麼好說的,可是千萬不要将這個syslog和linux的系統調用sys_syslog搞混淆了,後者的原型是:

asmlinkage long sys_syslog(int type, char __user *buf, int len);

而dmesg調用的正是這個函數,該函數内部通過type分成了若幹個類型,其實klogd也是可以通過直接調用這個函數來實作的(/proc/kmsg的read方法就是調用do_syslog,而sys_syslog也是調用do_syslog)。

     syslogd和syslog庫函數中使用的套接字就是unix族套接字,是unix本地程序間通信的一種好辦法,這種套接字必須有一對,本質上實作了一個管道,在接口和語義上又和bsd套接字相統一,實際上bsd套接字沒有網絡的概念,它隻承認自己可以實作程序間通信,它将網絡通信也統一看作了程序間通信,隻是後來的AF_INET等實作的不同機器間的程序間通信,而原始的AF_UNIX實作的是本機的程序間通信。既然AF_UNIX實作了本機的程序間通信,那麼它的位址隻需要本機内唯一即可,是以采用普通檔案是一個不錯的選擇,其位址就是檔案的全路徑:

struct sockaddr_un {

    sa_family_t  sun_family; 

    char         sun_path[UNIX_PATH_MAX]; //檔案路徑

};

比如syslogd使用的/dev/log就是一個處于一般檔案系統的套接字。套接字建立函數socket的第二個參數是類型,AF_UNIX族的套接字也分stream類型和datagram類型,隻是在語義限制上松了很多,datagram僅僅在資料邊界等不多的方面和stream類型的套接字有差別,有無連接配接的概念已經退化了。不管是stream還是datagram類型的AF_UNIX套接字,send的本質就是将資料放入接收者的接收隊列,recv則相反。

     上述套接字和管道的差別是什麼?僅僅是使用時的語義不同,管道的限制很少,也不很規範,很難擴充,而套接字擁有位址空間的概念,有協定的概念,很容易進行擴充,并且語義也很清晰。也正是這種統一,使得syslog很容易支援遠端日志記錄,本機日志記錄和遠端記錄都使用套接字,所不同的隻是套接字的位址族不同,這樣很多編碼都可以參數化,配置化,不必再寫備援的代碼了。

 本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1271806

繼續閱讀