目錄

Syslog 解釋

正文

根據維基百科定義,syslog 是一個系統日誌相關的通訊協定,定義紀錄擋訊息格式的標準,最早在 1980 由 Eric Paul Allman 發明的。

信息

Eric Allman 是現代電子郵件傳輸系統的奠基者,在 1980 年代初期,網際網路尚未統一,存在著 ARPANET、UUCP 等互不相容的網路。Allman 在加州大學柏克萊分校 (UC Berkeley) 開發了 sendmail(前身是 delivermail)。 它是第一個能夠在這些不同網路架構之間「路由」電子郵件的軟體 (MTA)。在很長一段時間裡,網際網路上 80% 以上 的電子郵件都是靠 Sendmail 傳送的。

Syslog 是他在 1980 年左右發明的。當時他在開發複雜的 Sendmail 時,發現除錯非常困難,且每個程式都把 Log 寫在不同的檔案或用不同的格式,管理極為混亂。 為了讓 Sendmail 能統一報告狀態,他設計了 Syslog。

Marshall Kirk McKusick 是他的伴侶,他是 BSD Unix (Berkeley Software Distribution) 的核心開發者,主導了許多檔案系統(如 FFS)的開發。

相關的 RFC 標準為:

  • RFC 3164 (舊標準):訊息包含 TAG (程式名稱) 和 CONTENT (內容)
  • RFC 5424 (新標準):格式更嚴謹。原本的 TAG 被拆解為 APP, NAME、, ROCID 和 MSGID
    • 目前的流行工具如 Rsyslog 或 NXLog 都遵循這個新標準
    • 內容建議使用 UTF-8 編碼

Syslog 使用主從式的架構,訊息會被送到你自己電腦的 syslogd 上面,根據設定會送到自己電腦上或者透過網路到另外一台電腦或者裝置,因為很多裝置像是印表機、路由器, syslog 都有支援。

Syslog 使用 UDP 514 port and TCP 601 port。

訊息

一條完整的 Syslog 訊息通常由以下幾部分組成:

  • 來源提供的資訊:設施代碼 (Facility) + 嚴重程度 (Severity)
  • Syslog 軟體添加的資訊: 為了讓紀錄更完整,系統會自動加上表頭 (Header),包含:發送者的 Process ID (程序識別碼)、時間戳記 (Timestamp)、主機名稱或 IP 地址

FreeBSD

介紹一下 FreeBSD syslog 相關實做。

syslogd(8)

syslogd 會預設開啟 /var/run/log socket,讓別人可以 open 此 local socket,傳東西。

它還開了另外一個 socket /var/run/logpriv,讓 root 可以用這個傳,root 預設使用這個傳。

有些系統管理員可能會為了防止一般使用者惡意灌爆 Log,而移除或限制 /var/run/log 的權限。但這時候,系統的重要服務(如 SSH 登入紀錄)不能因此中斷。保留一個 /var/run/logpriv 確保了即使一般日誌通道被阻塞或關閉,系統關鍵服務依然能正常記錄日誌。

syslogd 的 pid 可以透過 cat /var/run/syslog.pid 看到,設定檔則是 /etc/syslog.conf,裡面指定訊息怎麼轉發到檔案、終端機、遠端主機或通知特定使用者。

設定檔指定,A. 設施 (Facility) + B. 等級 (Level) + C. 特殊符號 + 最後寫入位置,例子如下:

# 1. 核心訊息與嚴重錯誤,丟到 console (終端機畫面) 給管理員看
# 核心的所有訊息 + 任何設施的 critical 以上等級
kern.debug;*.crit                       /dev/console

# 2. 這是最主要的 Log 檔案 (messages)
# 記錄所有 notice 以上的訊息,但排除 authpriv (私密認證)
*.notice;authpriv.none                  /var/log/messages

# !*: 重置程式過濾器。取消剛剛 !-devd 的限制,讓後面的設定恢復正常
# include: 這是現代化的設計
# 如果你安裝了 Nginx、Apache 或 Docker,它們的 Log 設定檔不需要硬塞進這個主檔案,而是丟進 /usr/local/etc/syslog.d/ 目錄下即可自動生效。這讓管理更乾淨
!*
include                     /etc/syslog.d
include                     /usr/local/etc/syslog.d

最後 syslogd 有一個專門給 kernel 寫 log 的 socket /dev/klog,注意此檔案用 file 看是一個 character special (0/37),他是一個 character device,因為核心產生 Log (例如驅動程式崩潰、硬體偵測) 時,它是直接把文字寫入記憶體中的一塊 Ring Buffer,使用環狀是因為滿了會覆蓋原本的資料。因此 syslogd 只要 read 此檔案就好了。

信息

dmesg 也是讀此 buffer,但讀取的方式(介面)不同。dmesg 使用 sysctl 系統呼叫(具體來說是讀取 kern.msgbuf 變數),它會把核心記憶體裡的 Ring Buffer 整個複製出來顯示給你看。

如果 dmesg 去讀 /dev/klog,它可能會把資料「讀走」,導致正在背景跑的 syslogd 讀不到那幾行 Log,造成資料遺失。

syslog(3)

可以看看 syslog C library:

  1. syslog: 傳訴參數優先度 (priority),還有 message
  2. openlog: 雖然你不呼叫它,直接用 syslog() 也能跑(系統會自動 lazy open),但寫 Daemon 通常都會呼叫它來做初始化。它可以讓你設定你的 ID/Facility/logopt … 等
  3. setlogmask: 如果你的程式裡充滿了 LOG_DEBUG,但在正式環境你不想浪費 System Call 的效能去送這些廢話,你可以用這個函式直接在 Client 端擋掉,讓使用者像是有 -v 參數可以指定只看某種類型的 LOG
  4. closelog: 關掉 syslog
  5. vsyslog: 它們接受的不是 …,而是一個已經處理過的參數列表指標 va_list,更好的輸出內容

比較特別的是,LOG_CONS 選項,當 syslogd 掛掉或者有任何問題,就直接 log 到 /dev/console

並且有可能還會使用 time 相關的函式讀取時間 (/etc/localtime) 來紀錄 Log。

Linux

Linux 早期使用 syslogd + klogd

  • syslogd:只負責聽 /dev/log (Unix Socket),它不懂怎麼跟核心講話

  • klogd:這是專門的「核心日誌搬運工」。它的工作是讀取 Linux 的核心介面 (/proc/kmsg 或 sys_syslog)。然後它把讀到的東西,轉發給 syslogd。

    特別功能: Linux 的 klogd 還會負責解析核心符號 (Kernel Symbol Decoding)。例如核心崩潰時顯示記憶體地址 0x123456,klogd 會去查表把它翻譯成函式名稱 sys_read,方便除錯。

現在的 Linux 也漸漸淘汰 klogd 了:

  • Rsyslog: 透過模組 (imklog) 直接讀核心,不用 klogd
  • Systemd-journald: 直接接管一切,連 syslogd 都不一定需要了