本篇目的是透過 Rsyslog ruleset 儲存多個來源的日誌,定義從各個 Port 傳入的日誌該儲至何處,搭配 Logrotate 每小時壓縮輪替管理。 為甚麼選擇由 Port 下手呢?因為若來源 IP 如果更動了,那份日誌便無法保留~

以下使用 Debian GNU/Linux 11 (bullseye) 與內建的 Rsyslog 8.2102.0、Logrotate 3.18.0 及 Crontab 操作。

備註 1:創建 /syslog/ 用來存放各個設備傳回的日誌,並以 /syslog/編號-名稱/ 儲存資料。 備註 2:直接使用 $ sudo su 切換為系統 Root 身分進行設定。

Rsyslog 存放日誌

Rsyslog 服務設定檔為 /etc/rsyslog.conf,Rsyslog 會讀取設定檔並進行相對應的操作;首先執行 $ cp /etc/rsyslog.conf /etc/rsyslog.conf.bak 保留原始設定。

透過 Vim、Nano 或其他編輯器修改設定檔,找到 #### MODULES #### 的區塊註解,往下新增一行內容,以引入 imudp 模組。

# ---/etc/rsyslog.conf---

module(load="imudp")

定義第一個 ruleset 為 remote52000,某一遠端主機將日誌以 Port 52000 傳入,系統將內容存入 /syslog/00-first-item/ 且檔名為 00-first-item.log;請先創建好 /syslog/00-first-item/ 存放日誌的目錄。

注意!每條 ruleset 需要搭配 input 函式綁定欲使用的 Port。

# ---/etc/rsyslog.conf---

ruleset(name="remote52000") { action(type="omfile" file="/syslog/00-first-item/00-first-item.log") }

input(type="imudp" port="52000" ruleset="remote52000")

也就是說,若現在有三個遠端主機傳回日誌,則 Rsyslog 設定檔能定義如下。

# ---/etc/rsyslog.conf---

ruleset(name="remote52000") { action(type="omfile" file="/syslog/00-first-item/00-first-item.log") }
ruleset(name="remote52001") { action(type="omfile" file="/syslog/01-second-item/01-second-item.log") }
ruleset(name="remote52002") { action(type="omfile" file="/syslog/02-third-item/02-third-item.log") }

input(type="imudp" port="52000" ruleset="remote52000")
input(type="imudp" port="52001" ruleset="remote52001")
input(type="imudp" port="52002" ruleset="remote52002")

更動 /etc/rsyslog.conf 設定後,需要儲存並重啟 Rsyslog 服務 $ systemctl restart rsyslog,開始觀察日誌是否成功傳入日誌伺服器。

Logrotate 輪替日誌

內建的 Logrotate 服務用來把過舊的日誌刪除,創建一個空白檔案來存入較新的資料。透過滾動式的管理,能根據檔案大小及存在天數來處理。

該服務的設定檔為 /etc/logrotate.conf,可以忽略原有內容,直接在最末行新增以下內容。

# ---/etc/logrotate.conf---

/syslog/*/*.log {
    hourly
    rotate 4500

    su root root
    create 600

    # add suffex to filenames
    dateext
    dateformat -%Y%m%d%H%M

    compress

    sharedscripts
    prerotate
    endscript

    # reload settings of service of syslog and rsyslog 
    sharedscripts
    postrotate
    /usr/bin/systemctl kill -s HUP syslog.socket > /dev/null 2>&1 || true
    /usr/bin/systemctl kill -s HUP rsyslog.service > /dev/null 2>&1 || true
    endscript
}
  • /syslog/*/*.log 以正規表示式匹配目錄內的檔名,找到需要處理的日誌。

  • hourly 將特定檔案以小時為單位進行滾動切割。

  • rotate 4500 保留最近 4500 個小時的內容,約半年多。

  • su root root create 600 以 root 身分創建檔案並定義權限。

  • dateext dateformat -%Y%m%d%H%M 讓處理過的檔案,名稱新增後綴日期時間。

  • compress 讓處理過的檔案被壓縮,以節省硬碟空間。

  • prerotate 沒有針對日誌預處理所以留空。

  • postrotate 使用 /usr/bin/systemctl kill -s HUP 重新載入設定,不重啟服務。

設定完成後手動執行 logrotate -d /etc/logrotate.conf,以參數 -d 開啟測試模式,輸出處理過程,但不異動任何資料,藉此判斷設定檔的可執行性。

Crontab 排程啟動

使用 Cron 排程服務自動觸發 Logrotate,開始編輯內建的 /etc/crontab。

系統已有設定每小時執行 /etc/cron.hourly/ 內定義的排程,但觸發時間為每時 17 分,這裡我們將它改為每時 0 分,能註解原設定並複製內容修改即可。

# ---/etc/crontab---

...
# 17 * * * * root cd / && run-parts --report /etc/cron.hourly
00 * * * * root cd / && run-parts --report /etc/cron.hourly

接著需要定義排程任務內容,讓 Cron 可以準確執行 Logrotate 任務,這裡複製 /etc/cron.daily/logrotate 的內容來用,$ cp /etc/cron.daily/logrotate /etc/cron.hourly/(預設是每天執行一次 Logrotate)。

修改內容如下,主要註解 /run/systemd/system 檢查,並新增 > /dev/null 2>&1 忽略錯誤訊息。

# ---/etc/cron.hourly/logrotate---

#!/bin/sh

## skip in favour of systemd timer
#if [ -d /run/systemd/system ]; then
#    exit 0
#fi

# this cronjob persists removals (but not purges)
if [ ! -x /usr/sbin/logrotate ]; then
    exit 0
fi

#/usr/sbin/logrotate /etc/logrotate.conf
/usr/sbin/logrotate /etc/logrotate.conf > /dev/null 2>&1
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit $EXITVALUE

最後以 $ run-parts --test /etc/cron.hourly 檢查資料夾內可執行的設定(但不執行),結果須包含 /etc/cron.hourly/logrotate,若沒出現,需檢查是否具有 +x 可執行權限。

備註:關於上述提到需要註解 /run/systemd/system 檢查是因為內建 logrotate 定時器 /usr/lib/systemd/system/logrotate.timer 每天執行

指令備註

  • $ grep cron /var/log/syslog 搜尋 syslog 內有關 Cron 的紀錄,檢查 Logrotate 是否正確被觸發,例如下方輸出。

    May 12 22:00:01 hostname-syslog CRON[420967]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
    May 12 23:00:01 hostname-syslog CRON[421202]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
    May 13 00:00:01 hostname-syslog CRON[421434]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
    
  • $ systemctl status cron

  • $ systemctl status rsyslog.service 使用 systemctl 系統服務管理指令來查看 Rsyslog 的狀態。

  • $ rsyslogd -v 以 rsyslogd 來顯示其他資訊

  • $ /var/lib/logrotate/status 紀錄各日誌檔案最新異動時間;讓它能根據所列的項目及時間判斷是否進行轉儲。

    logrotate state -- version 2
    
    "/syslog/00-first-item/00-first-item.log" 2024-5-12-23:0:5
    # ...
    
  • (承上)$ cat /var/lib/logrotate/status | grep -v syslog 若存放的日誌種類多樣,篩選包含 syslog 字串的項目。

  • $ logrotate -f /etc/logrotate.conf 強制執行。

  • $ logrotate -vf /etc/logrotate.conf 強制執行,且顯示過程。

參考資料