Unix/Linux 日誌記錄syslog
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 為沒有指定設施的後續syslog呼叫指定一個預設值.
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輸出結果: