Nginx 日誌分割

nginx 默認沒有提供對日誌文件的分割功能,所以隨着時間的增長,access.log 和 error.log 文件會越來越大,尤其是 access.log,其日誌記錄量比較大,更容易增長文件大小。影響日誌寫入性能分割 nginx 日誌的方法有很多,這裏推薦利用 Logrotate 來完成。

Logrotate 用法

1. 安裝

logrotate 是一個 Linux 系統日誌的管理工具。可以對單個日誌文件或者某個目錄下的文件按時間 / 大小進行切割,壓縮操作;指定日誌保存數量;還可以在切割之後運行自定義命令。

logrotate 是基於 crontab 運行的,所以這個時間點是由 crontab 控制的,具體可以查詢 crontab 的配置文件 /etc/anacrontab。系統會按照計劃的頻率運行 logrotate,通常是每天。在大多數的 Linux 發行版本上,計劃每天運行的腳本位於 /etc/cron.daily/logrotate。

主流 Linux 發行版上都默認安裝有 logrotate 包,如果你的 Linux 系統中找不到 logrotate, 可以使用 apt-get 或 yum 命令來安裝。

yum install -y logrotate

一般 Linux 都已經自帶 logrotate,下列命令可以查看是否已安裝。

rpm -ql logrotate

2. 基本用法詳解

2.1 入門

/etc/logrotate.conf 這個文件是 logrotate 的主配置文件。

# see "man logrotate" for details
# rotate log files weekly
weekly
# keep 4 weeks worth of backlogs
rotate 4
# create new (empty) log files after rotating old ones
create
# use date as a suffix of the rotated file
dateext
# uncomment this if you want your log files compressed
#compress
# 包含自定義配置目錄
include /etc/logrotate.d
# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}
/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}
# system-specific logs may be also be configured here.

這個主配置文件中定義了日誌文件分割的通用參數。並且 include /etc/logrotate.d 表示其會加載 /etc/logrotate.d 的所有自定義配置文件,自定義配置文件中的配置可以覆蓋掉通用配置。

我們來到自定義配置文件的目錄 / etc/logrotate.d。

嘗試在該目錄中創建一個日誌分割配置 test,對 /opt/logtest 目錄中所有以 .log 結尾的文件進行分割。

vim test
# test配置文件的內容
/opt/logtest/*.log {
    daily
    rotate 2
    copytruncate
    missingok
}

test 配置的第一行指定要對哪個路徑的哪些文件進行分割,然後攜帶的 4 個參數解釋如下:

創建好配置以後,系統會在每天利用 cron 定時執行 logrotate 日誌分割指令。這裏我們爲了看到效果,不等到系統自動執行,可以手動強制執行一次日誌分割。強制執行會立即進行一次日誌。

# -v:顯示執行日誌
# -f:強制執行分割
logrotate -vf /etc/logrotate.d/test

執行前,事先在日誌所在目錄中創建 2 個測試日誌文件。

touch test1.log
touch test2.log

手動執行一次日誌分割,觀察執行日誌可以發現,過程如下:

此時分割後的文件名爲源文件名後面加上 . 序號,序號從 1 開始。

然後我們再次手動執行一次分割,此時執行過程如下:

  1. 將第一次分割後的日誌文件 test1.log.1 重命名爲 test1.log.2;

  2. 將源日誌文件拷貝到此次分割後的文件,命名序號重新從 1 開始,爲 test1.log.1;

  3. 清空源日誌文件。

接着再次手動執行一次分割,此時執行過程如下:

  1. 將之前分割後的日誌文件 test1.log.2 重命名爲 test1.log.3,test1.log.1 重命名爲 test1.log.2;

  2. 分割源日誌文件,拷貝其內容到 test1.log.1;

  3. 由於設置了 rotate 爲 2,即最多保留 2 個日誌文件,所以此時要刪除最早分割出的那個日誌文件,即 test1.log.3。

總結一下 logrotate 日誌分割的步驟:

  1. 默認分割後日志的命名爲源日誌名稱 +. 序號(從 1 開始)。分割之前將所有之前分割出的日誌文件重命名,序號往後移一位;

  2. 執行分割,將源日誌文件分割爲源日誌文件名 .1。這樣就保證了所有分割後的文件中,序號最小的是最新分割出的,序號最大的是最早分割出的;

  3. 根據 rotate 設置,如果此次分割後文件數量大於 rotate 設置,那麼刪除序號最大的那個分割文件,也就是最舊的分割日誌。

實際開發中可以使用 create 代替 copytruncate,它們的區別如下:

/opt/logtest/*.log {
    daily
    rotate 2
    create  # 創建與源文件名稱相同的新文件,用於後續日誌寫入,新文件的歸屬用戶、權限與源文件相同
    missingok
}

但是要注意 create 即使創建新的文件後,如果沒有主動通知應用程序,那麼應用程序仍然會往舊的文件 (即被重命名的那個分割後的文件) 寫入日誌。所以此時在分割後要通知應用程序重新打開新的日誌文件進行寫入。

以通知 nginx 爲例,配置如下:

/var/log/nginx/*.log {
    daily                      
    rotate 30              
    create
    sharedscripts              # 所有的文件切割之後只執行一次下面腳本,通知nginx重新打開新的日誌文件進行後續寫入
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 `cat /run/nginx.pid`  # 通過USER1信號通知nginx重新打開日誌文件
        fi
    endscript
}

綜上,一般情況下如果應用程序提供了通知其打開新的日誌文件的接口,那麼推薦使用 create 續寫日誌;否則推薦使用 copytruncate 續寫日誌。

注意:

2.2 分割文件壓縮

我們可以通過如下設置對分割後的日誌文件開啓壓縮:

/opt/logtest/*.log {
    daily
    rotate 2
    copytruncate
    missingok
    compress           # 以gzip方式壓縮
    nodelaycompress    # 所有分割後的文件都進行壓縮
}

此時刪除原有所有文件,重新創建測試日誌文件 test1.log 和 test2.log,然後手動執行分割,可以生成壓縮後的 .gz 文件。

一般可以將 nodelaycompress 改爲 delaycompress,這樣分割後對最新的序號爲 1 的文件不會進行壓縮,對其他序號的文件進行壓縮,這樣可以方便我們查看最新的分割日誌。

2.3 按照時間分割

按照時間分割可以定時分割出一個日誌,比如每天分割一次,配合其他參數可以完成保留最近 n 天日誌的功能。以下配置可以實現每天分割一次日誌,並且保留最近 30 天的分割日誌。

/opt/logtest/*.log {
    daily      # 每天分割一次
    rotate 30  # 保留最近30個分割後的日誌文件
    copytruncate
    missingok
    dateext  # 切割後的文件添加日期作爲後綴
    dateyesterday # 配合dateext使用,添加前一天的日期作爲分割後日志的後綴
}

還是先刪除原來的所有文件,重新創建。

touch test{1,2}.log

再手動執行分割,此時生成的分割後的文件將不再以序號作爲文件名結尾,而是以昨天的日期作爲結尾。

並且如果馬上再手動執行一次分割,由於日期相同,不會像原來一樣生成序號遞增的新日誌文件,此時相當於沒有執行任何分割操作。即同一天只能分割一次,第二天再次執行纔會分割出新的日期結尾的文件,所以此時設置 rotate 的值即爲保留最近多少天日誌的意思。

此外,默認添加的日期後綴格式爲 yyyyMMdd,可以用 dateformat 自定義。

/opt/logtest/*.log {
    daily      # 每天分割一次
    rotate 30  # 保留最近30個分割後的日誌文件
    copytruncate
    missingok
    dateext  # 切割後的文件添加日期作爲後綴
    dateyesterday # 配合dateext使用,添加前一天的日期作爲分割後日志的後綴
    dateformat -%Y-%m-%d  # 格式爲2022-02-08
}

2.4 按照文件大小分割

我們可以利用 size 配置指定當日誌文件達到多大體積時才進行分割。以下配置指定了每天執行分割,但是隻有當日誌文件大於 5M 時才真正執行分割操作。

/opt/logtest/*.log {
    daily      # 每天分割一次
    size 5M    # 源文件小於5M時不分割
    rotate 30  # 保留最近30個分割後的日誌文件
    create
    missingok
    dateext  # 切割後的文件添加日期作爲後綴
    dateyesterday # 配合dateext使用,添加前一天的日期作爲分割後日志的後綴
}

注意:這個配置並不是說日誌文件達到指定大小就自動執行分割,它還是要遵循定時任務。比如配置了 daily 只有到每天指定時間執行分割任務時,纔會檢查文件大小,對超過指定大小的文件進行分割。

2.5 自定義每小時分割

logrotate 實現每日定時執行日誌分割的原理是通過 cron 定時任務,默認在 /etc/cron.daily 中包含 logrotate 可執行命令,所以系統每天會定時啓動 logrotate,然後它會根據配置中具體分割頻率(daily、weekly 等)以及其他條件(比如 size)決定是否要真正執行分割操作。

如果我們想要實現每小時進行一次分割,需要如下步驟:

  1. logrotate 配置文件中指定分割頻率爲 hourly;

  2. 配置完以後,還需要在 cron 的每小時定時任務中加入 logrotate,因爲默認情況下只有 /etc/cron.daily 中包含 logrotate 可執行命令,我們要將它往 /etc/cron.hourly 中也拷貝一份,這樣系統纔會每小時調用一次 logrotate 去執行分割。

cp /etc/cron.daily/logrotate /etc/cron.hourly/

2.6 自定義分割執行時間

logrotate 是基於 cron 運行的,所以這個時間是由 cron 控制的,具體可以查詢 cron 的配置文件 /etc/crontab 。舊版 CentOS 的 cron 的配置文件是 /etc/crontab ,新版 CentOS 改爲 /etc/anacrontab。

從上面的內容可以看出:

如果我們覺得每天凌晨 3 點多執行日誌分割不合適,那麼可以自定義分割執行時間。實現方式可以是:

推薦採用 crontab 方式自定義執行時間,步驟如下:

  1. 在非 /etc/logrotate.d 目錄創建 logrotate 配置文件,這是爲了避免被系統的定時任務掃描到該配置而導致重複執行分割。

  2. 添加 crontab 計劃任務,在 root 用戶下執行 crontab -e 進入 vim 模式,進行編輯。

crontab -e
# 每天 23點59分進行日誌切割
59 23 * * * /usr/sbin/logrotate -f /etc/logrotate_mytime/nginx
  1. 重啓 crontab。
# centos6: 
service crond restart
# centos7: 
systemctl restart crond

nginx 日誌分割步驟

在 /etc/logrotate.d 中創建文件 nginx,作爲 nginx 日誌分割的配置文件。指定每天執行一次分割,並且當文件大於 5M 時才進行分割。同時指定 notifempty,當日志文件爲空時不分割。

/opt/docker-ws/nginx/logs/*.log {
    daily      # 每天分割一次
    size 5M    # 源文件小於5M時不分割
    rotate 30  # 保留最近30個分割後的日誌文件
    copytruncate
    notifempty # 當日志文件爲空時不分割
    missingok
    dateext  # 切割後的文件添加日期作爲後綴
}

這樣配置了以後系統會在凌晨 3 點多執行分割操作,執行結果會保存到 /var/spool/mail/root 中。

查看結果發現提示權限不夠而分割失敗,這是因爲開啓了 selinux 導致,解決方案有如下 2 種:

# 開放/opt/logtest目錄的權限
semanage fcontext -a -t var_log_t "/opt/logtest(/.*)?"
restorecon -Rv /opt/logtest

轉自: 包包,

鏈接:https://baobao555.tech/archives/57

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/lyUn318LhEdORzTr40gUgA