У меня есть следующий файл 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 справится с этим сам?
Плагин out_file от Fluentd автоматически разбивает выходные файлы по дням, поэтому вам НЕ нужно использовать logrotate.
Если вы хотите разделить по разной степени детализации, измените параметр time_slice_format (по умолчанию это% Y% m% d).
Однако это означает, что у выходного файла нет текущего канонического имени. Для этого вы можете использовать параметр "symlink_path" с "buffer_type file". Это не особенность out_file как таковая, но любой буферизованный вывод.
К сожалению, если out_file
плагин является в настоящее время может разделить файлы журнала по времени (вещь logrotate
может также), это не удаляет N старых файлов (который logrotate
инвентарь).
Итак, используя logrotate
кажется все еще необходимым если вам нужно контролировать количество и размер хранимых журналов (источник: https://github.com/fluent/fluentd/issues/2111 ).
На этом этапе вы можете отключить fluentd
функция разделения файлов, связанная со временем, и обязательно используйте append true
позволить logrotate
делай это полноценно. Обратите внимание, что нет необходимости postrotate
тонкости в logrotate
конф, как fluentd
повторно открывать файл при каждой очистке буфера ... и это долгожданный бонус использования fluentd
.
fluentd
останется полезным для фильтров / копирования потоков журнала, разделения файлов по тегам и буферизации.
Как указал @ kiyoto-tamura, fluentd
может разбивать выходные файлы по дням, и это поведение по умолчанию.
И, как указывает @vaab, fluentd
не может удалить старые файлы. Следовательно, очевидным решением было бы отключить разделение fluentd
и разреши logrotate
для обработки разбиения на разделы с отслеживанием количества файлов.
Однако это может создать ненужную сложность, особенно в простых случаях: нужно будет установить, настроить и контролировать дополнительную службу, которая logrotate
.
Более того, получить аналог logrotate
в Windows (если вам не нравится установка cygwin
или используя 0.0.0.x
версии в производстве).
Итак, другое возможное решение было бы позволить fluentd
для разделения выходных файлов по дням как обычно, но периодически удаляйте старые файлы.
В UNIX-подобных системах это несложно и может быть достигнуто путем написания однострочного сценария оболочки. призывая find
и планирование его через cron
.
Та же логика применима к среде Windows. Например, можно написать сценарий PowerShell и запланировать его через системный планировщик задач (увидеть суть для удобочитаемости).
Следующий листинг определяет такой сценарий как пример:
# 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"
Так как создание запланированной задачи в 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
сценарий.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"