為 Fluentd 文件配置 Logrotate。必要的?
我有以下 fluent.conf
<source> type forward </source> <source> type monitor_agent port 24220 </source> # Listen DRb for debug <source> type debug_agent port 24230 </source> <source> type tail path /var/data/www/apps/app/logs/*.log pos_file /tmp/fluent.nginx.pos format syslog tag app.nginx-access # Regex fields format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*) "(?<referer>[^\"]*)" "(?<agent>[^\"]*)"$/ # Date and time format time_format %d/%b/%Y:%H:%M:%S %z </source> <match app.**> type copy <store> type file path /var/log/fluent/app </store> </match>
是否有必要使用 Logrotate @
/var/log/fluent/app/*
還是 Fluent 會自己處理?
Fluentd 的 out_file 外掛會自動按天對輸出文件進行分區,因此您不需要使用 logrotate。
如果要按不同粒度進行分區,請更改“time_slice_format”參數(預設為%Y%m%d)。
但是,這意味著輸出文件沒有目前的規範名稱。為此,您可以將參數“symlink_path”與“buffer_type file”一起使用。這不是 out_file 本身的特性,而是任何緩衝的輸出。
正如@kiyoto-tamura 所指出的,
fluentd
可以按天對輸出文件進行分區,這是預設行為。而且,正如@vaab 所指出的,
fluentd
不能刪除舊文件。因此,顯而易見的解決方案是禁用分區fluentd
並讓logrotate
處理分區以及監視文件的數量。但是,這可能會帶來不必要的複雜性,尤其是對於簡單的情況:必須安裝、配置和監控一項附加服務,即
logrotate
.此外,在 Windows 上進行類比
logrotate
可能會有問題(除非您對在生產環境中安裝cygwin
或使用0.0.0.x
版本感到滿意)。因此,另一個可行的解決方案是讓
fluentd
輸出文件像往常一樣按天分區,但定期刪除舊文件。在類 UNIX 系統中,這很容易實現,可以通過編寫單行 shell 腳本呼叫
find
並通過cron
.相同的邏輯適用於 Windows 環境。例如,可以編寫一個 PowerShell 腳本並通過系統任務調度程序對其進行調度(請參閱 Gist以了解可讀性)。
以下清單定義了這樣一個腳本作為範例:
# delete-old-service-logs.ps1 [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true)] [ValidateScript({ if( -Not ($_ | Test-Path) ){ throw "Specified logs dir path does not exist (path='$_')" } if(-Not ($_ | Test-Path -PathType Container) ){ throw "Specified logs dir path does not point to a directory (path='$_')" } return $true })] [string]$LogsDirPath, [Parameter(Position=1)] [int]$LogsFileMaxN = 31, [Parameter(Position=2)] [ValidateNotNullOrEmpty()] [string]$LogsFileNamePattern = "service.????-??-??.log" ) [string[]]$FileNamesToRemove = Get-ChildItem -Path $LogsDirPath -Filter $LogsFileNamePattern | Sort-Object -Property CreationTime -Descending | Select-Object -Skip $LogsFileMaxN | Select -ExpandProperty "Name" $Shell = new-object -comobject "Shell.Application" $LogsDir = $Shell.Namespace($LogsDirPath) Foreach ($FileName in $FileNamesToRemove) { $Item = $LogsDir.ParseName($FileName) $Item.InvokeVerb("delete") }
邏輯非常簡單:
- 使用日誌獲取目錄的路徑。
- 獲取要保留的最大文件數。
- 採用文件模式來搜尋日誌。
- 查找日誌目錄中的所有文件,按創建日期反向排序並取舊文件的名稱。
- 刪除舊文件(如果有)。
呼叫範例:
./delete-old-service-logs.ps1 "path/to/logs/dir"
或者:
./delete-old-service-logs.ps1 -LogsDirPath "path/to/logs/dir"
由於通過 GUI 在 Windows 中創建計劃任務可能會很痛苦,因此可以使用一個腳本來自動執行此操作:
# create-task_delete-old-service-logs.ps1 [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$LogsDirPath, [Parameter(Position=1)] [int]$LogsFileMaxN = 31, [Parameter(Position=2)] [ValidateNotNullOrEmpty()] [string]$LogsFileNamePattern = "service.????-??-??.log", [Parameter(Position=3)] [ValidateNotNullOrEmpty()] [string]$TaskScriptFilePath = "delete-old-service-logs.ps1", [Parameter(Position=4)] [ValidateNotNullOrEmpty()] [string]$TaskName = "SERVICE NAME - Delete Old Logs", [Parameter(Position=5)] [ValidateNotNullOrEmpty()] [string]$TaskDescription = "Delete old logs of SERVICE NAME aggregated via Fluentd", [Parameter(Position=6)] [ValidateNotNullOrEmpty()] [string]$TaskTriggerTime = "5:00:00 AM" ) try { $LogsDirPath = Resolve-Path -Path $LogsDirPath } catch { throw "Specified logs dir path does not exist (path='$LogsDirPath')" } if(-Not ($LogsDirPath | Test-Path -PathType Container) ){ throw "Specified logs dir path does not point to a directory (path='$LogsDirPath')" } try { $TaskScriptFilePath = Resolve-Path -Path $TaskScriptFilePath } catch { throw "Specified task script file path does not exist (path='$TaskScriptFilePath')" } if( -Not ($TaskScriptFilePath | Test-Path -PathType Leaf) ){ throw "Specified task script file path is not a file (path='$TaskScriptFilePath')" } $TaskAction = New-ScheduledTaskAction -Execute "C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe" ` -Argument "-NoProfile -WindowStyle Hidden -command ""$TaskScriptFilePath -LogsDirPath ""$LogsDirPath"" -LogsFileMaxN $LogsFileMaxN -LogsFileNamePattern ""$LogsFileNamePattern""""" $TaskTrigger = New-ScheduledTaskTrigger -Daily -At $TaskTriggerTime Register-ScheduledTask -TaskName $TaskName -Description $TaskDescription -Action $TaskAction -Trigger $TaskTrigger
實際的邏輯發生在最後 3 行,其中創建並註冊了一個動作、一個觸發器和一個任務。總的來說,工作流程如下:
- 為
delete-old-service-logs.ps1
.- 採取
delete-old-service-logs.ps1
腳本路徑。- 獲取任務名稱、描述和触發腳本的時間。
- 嘗試解析和驗證路徑。
- 使用 args 創建用於呼叫 PowerShell 的操作以執行
delete-old-service-logs.ps1
。- 創建每日觸發器。
- 註冊任務。
呼叫範例,假設兩個腳本位於同一目錄中:
./create-task_delete-old-service-logs.ps1 "path/to/logs/dir"
或者:
./create-task_delete-old-service-logs.ps1 -LogsDirPath "path/to/logs/dir" -TaskScriptFilePath "path/to/delete-old-service-logs.ps1"