1. syslogd守護進程
我們知道, 守護進程(daemon)是
在后台運行且不與任何控制終端關聯的進程.
參見: Linux 系統編程學習筆記 - 終端、作業控制與守護進程 守護進程章節.
那么如何得知守護進程的狀態, 和某些事情發生呢?守護進程如何輸出消息, 或者告知管理員?
可以調用syslog函數輸出這些消息, 函數把消息發送給syslogd守護進程, 而syslogd守護進程可以將消息寫入同一個文件或者發送至另一個主機, 方便系統管理人員查看.
1.1 BSD syslog組織結構:
有以下3種產生日志消息的方法:
1)內核例程調用log函數
任何一個用戶進程都可以通過open, read /dev/klog設備來讀取這些消息. 不過, 編寫內核例程時, 才會用到.
2)大多數用戶進程(守護進程)調用syslog(3)函數來產生日志消息
3)本機上的用戶進程, 或者網絡上的用戶進程, 都可以通過TCP/IP網絡連接到此主機, 可將日志消息發向UDP port 514.
syslog函數本身不會產生UDP數據報, 而是要求產生此日志消息的進程進行顯式的網絡編程.
1.2 syslogd守護進程的啟動
syslond守護進程是由某個系統初始化腳本啟動, 而且在系統工作期間一直運行.
源自Berkeley的syslogd的啟動實現步驟:
1)讀取配置文件
通常為/ect/syslog.conf 的配置文件指定本守護進程可能收取的各種日志消息(log message)應該如何處理. 這些消息可能被添加到一個文件(特例/dev/console), 或被寫到指定用戶的登錄窗口(若該用戶已登錄到本守護進程所在系統中), 或被轉發給另一個主機上的syslogd進程.
2)創建一個Unix Domain數據報套接字, 給他捆綁路徑名/var/run/log(某些系統是/dev/log)
3)創建一個UDP套接字, 捆綁端口514(syslog服務使用端口號)
4)打開路徑名/dev/klog
來自內核中的任何出錯消息看着像是這個設備的輸入.
5)此后, syslogd守護進程在一個無限循環中運行: 調用select以等待它的3個描述符(來自上面的1),2),3))之一可讀, 讀入日志消息, 並按照配置文件進行處理. 如果守護進程收到SIGHUP信號, 那么就重新讀取配置文件.
注意: 較新的syslogd實現禁止創建UDP套接字, 除非管理員明確要求. 理由: 允許任何進程往該套接字發送UDP數據報, 會讓系統易遭拒絕服務攻擊, 其文件系統可能被填滿, 而合法進程的日志消息可能被排擠掉.
2. 日志記錄函數
2.1 syslog
守護進程沒有控制終端, 不能打印消息到stdout, stderr. 用戶進程從syslogd守護進程中登記消息的常用方法是調用syslog函數.
調用syslog產生一個日志消息.
#include <syslog.h>
void syslog(int priority, const char *format, ...);
- 參數
priority 是facility和level的組合. level見下表, facility見openlog的facility.
syslog的level:
level | 說明 |
---|---|
LOG_EMERG | 緊急(系統不可使用)(最高優先級) |
LOG_ALERT | 必須立即修復的情況 |
LOG_CRIT | 嚴重情況(如硬件設備出錯) |
LOG_ERR | 出錯情況 |
LOG_WARNING | 警告情況 |
LOG_NOTICE | 正常但重要的情況 |
LOG_INFO | 信息性消息 |
LOG_DEBUG | 調試消息(最低優先級) |
2.2 openlog, closelog
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
void closelog(void);
void vsyslog(int priority, const char *format, va_list ap);
openlog 可選調用, 如果不調用openlog, 則在第一次調用syslong時, 自動調用openlog. openlog可以在首次調用syslog前調用.
closelog 可選調用, 因為它只是關閉曾被用於與syslogd守護進程進行通信的描述符. 這些描述符在進程正常終止以后, 也會自動關閉. closelog可以在應用進程不再需要發送日志消息時調用, 以關閉與syslogd通信的描述符.
- 參數
options 調用openlog時, 通常不立即創建Unixo Domain socket, 而該socket到首次調用syslog時才打開. openlog的options能影響log的行為, 如指定LOG_NDELAY選項將迫使該socket在openlog調用后立即創建, 而不是到調用syslog時才創建.
openlog的options由一個或多個常值的構成(邏輯或):
options | 說明 |
---|---|
LOG_CONS | 若無法發送到syslogd守護進程則登記到控制台 |
LOG_NDELAY | 不延遲打開, 立即創建套接字 |
LOG_PERROR | 既發送到syslogd守護進程, 又登記到標准錯誤輸出 |
LOG_PID | 隨每個日志消息登記進程ID |
facility 設施, 標識消息發送進程的類型, 來自不同設施的消息將以不同的方式進行處理. openlog的facility參數, 為沒有指定設施的后續syslog調用指定一個默認值, i.e. openlog如果指定了facility, syslog可不必另外指定facility.
facility | XSI | 說明 |
---|---|---|
LOG_AUDIT | 審計設施 | |
LOG_AUTH | 授權程序: login, su, getty等 | |
LOG_AUTHPRIV | 與LOG_AUTH相同, 但寫日志文件時具有權限限制 | |
LOG_CONSOLE | 消息寫入 /dev/console | |
LOG_CRON | cron和at | |
LOG_DAEMON | 系統守護進程: inetd, routed等 | |
LOG_FTP | FTP守護進程(ftpd) | |
LOG_KERN | 內核產生的消息 | |
LOG_LOCAL0 | ● | 保留本地使用 |
LOG_LOCAL1 | ● | 保留本地使用 |
LOG_LOCAL2 | ● | 保留本地使用 |
LOG_LOCAL3 | ● | 保留本地使用 |
LOG_LOCAL4 | ● | 保留本地使用 |
LOG_LOCAL5 | ● | 保留本地使用 |
LOG_LOCAL6 | ● | 保留本地使用 |
LOG_LOCAL7 | ● | 保留本地使用 |
LOG_LPR | 行式打印機系統: lpd, lpc等 | |
LOG_MAIL | 郵件系統 | |
LOG_NEWS | Usenet網絡新聞系統 | |
LOG_NTP | 網絡時間協議系統 | |
LOG_SECURITY | 安全子系統 | |
LOG_SYSLOG | syslogd守護進程本身 | |
LOG_USER | ● | 來自其他用戶進程的消息(默認) |
LOG_UUCP | UUCP系統 |
3. syslog文件
3.1 syslog文件存放位置
Linux下調用syslog函數輸出的消息就放在syslog文件, 存放在/var/log/syslog
. syslog文件, 通常用於存放應用程序(守護進程)警告信息.
其他日志存放位置, 詳見: linux系統各種日志存儲路徑和詳細介紹 | 博客園
3.2 手動刪除syslog文件
步驟:
- 刪除syslog文件
到/var/log/目錄下rm文件
$ cd /var/log
$ rm -f syslog # 需要root權限
- 重啟syslog服務
$ service syslog restart
4. 例程
同時向控制台和syslog輸出包含PID的進度信息, 1秒鍾更新10%, 到100%為止.
#include <syslog.h>
#include <unistd.h>
#include <stdio.h>
/**
* linux下syslog存放位置 : /var/log/syslog
*/
int main()
{
int i;
puts("hello");
/* LOG_CONS: 若無法發送到syslogd守護進程則登記到控制台;
LOG_PID: 隨每個日志消息登記進程PID;
LOG_PERROR: 既發送到syslogd守護進程,也發送到stderr;
LOG_USER: 任意的用戶級消息(默認) */
openlog("mysyslog", LOG_CONS | LOG_PID | LOG_PERROR, LOG_USER);
syslog(LOG_INFO, "system is starting..." );
for (i = 0; i < 10; ++i) {
syslog(LOG_WARNING | LOG_USER, "process %d\n", (i + 1) * 10);
sleep(1);
}
closelog();
return 0;
}
控制台輸出結果:
$ ./a.out
hello
mysyslog[26710]: system is starting...
mysyslog[26710]: process 10
mysyslog[26710]: process 20
mysyslog[26710]: process 30
mysyslog[26710]: process 40
mysyslog[26710]: process 50
mysyslog[26710]: process 60
mysyslog[26710]: process 70
mysyslog[26710]: process 80
mysyslog[26710]: process 90
mysyslog[26710]: process 100
syslog輸出結果: