Настройка Logrotate для файлов Fluentd. Необходимо?

У меня есть следующий 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 справится с этим сам?

2 ответа

Решение

Плагин Fluentd out_file автоматически разбивает выходные файлы по дням, поэтому вам не нужно использовать logrotate.

Если вы хотите разделить с разной степенью детализации, измените параметр "time_slice_format" (по умолчанию это%Y%m%d).

Однако это означает, что для выходного файла нет текущего канонического имени. Для этого вы можете использовать параметр "symlink_path" с "file_type file". Это не особенность out_file как таковой, но любой буферизованный вывод.

Как указал @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")
}

Логика довольно проста:

  1. Идите по пути к директории с журналами.
  2. Возьмите максимальное количество файлов, которые нужно оставить.
  3. Возьмите шаблон файла для поиска в журналах.
  4. Найдите все файлы в каталоге журналов, выполните обратную сортировку по дате создания и возьмите имена старых файлов.
  5. Удалите старые файлы, если они есть.

Пример вызова:

./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 строках, где создаются и регистрируются действие, триггер и задача. В целом рабочий процесс выглядит следующим образом:

  1. Возьмите параметры для delete-old-service-logs.ps1.
  2. Выберите путь к delete-old-service-logs.ps1 сценарий.
  3. Возьмите название задачи, описание и время запуска скрипта.
  4. Попробуйте разрешить и проверить пути.
  5. Создайте действие для вызова PowerShell с аргументами для запуска delete-old-service-logs.ps1.
  6. Создайте ежедневный триггер.
  7. Зарегистрируйте задачу.

Пример вызова, если оба сценария находятся в одном каталоге:

./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"

К сожалению если out_file плагин в настоящее время может разбить файлы журнала по времени (вещь logrotate может сделать также), это не удаление N старых файлов (которые logrotate реализует).

Итак, используя logrotate кажется, все еще необходимо, если вам нужно контролировать количество и размер сохраняемых журналов (источник: https://github.com/fluent/fluentd/issues/2111).

На этом этапе вы можете отключить fluentd функция разделения файлов, связанная со временем, и обязательно используйте append true позволить logrotate сделать это полную работу. Обратите внимание, что нет необходимости postrotate приятности в logrotateконф как fluentd повторно открывать файл при каждой очистке буфера... и это приветствуется fluentd,

fluentd останется полезным для фильтров / копирования потоков журналов, разделения файлов по тегам и буферизации.

Другие вопросы по тегам