Как я могу обрезать файлы журналов с помощью Perl?

Недавно я столкнулся с ситуацией, когда мне нужно обрезать некоторые довольно большие файлы журналов, когда они превышают определенный размер. Все, кроме последних 1000 строк в каждом файле, удаляется, задание запускается каждые полчаса с помощью cron. Мое решение состояло в том, чтобы просто просмотреть список файлов, проверить размер и при необходимости обрезать.

for $file (@fileList) {
  if ( ((-s $file) / (1024 * 1024)) > $CSize) {
      open FH, "$file" or die "Cannot open ${file}: $!\n";
      $lineNo = 0;
      my @tLines;

      while(<FH>) {
        push @tLines, $_;
        shift @tLines if ++$lineNo < CLLimit;
      }
      close FH;

      open FH, ">$file" or die "Cannot write to ${file}: $!\n";
      print FH @tLines;
      close FH;
}

Это работает в текущей форме, но для больших файлов журналов (особенно тех, которые содержат более 100_000 строк) возникает много накладных расходов из-за необходимости читать каждую строку и при необходимости сдвигать.

Есть ли способ, которым я мог бы прочитать только часть файла, например. в этом случае я хочу иметь доступ только к последним строкам «CLLimit». Поскольку сценарий развертывается в системе, которая знавала лучшие дни (например, Celeron 700 МГц с 64 МБ ОЗУ), я ищу более быструю альтернативу с использованием Perl.


person aks    schedule 10.02.2009    source источник


Ответы (3)


Я понимаю, что вы хотите использовать Perl, но если это система UNIX, почему бы не использовать утилиту «хвост» для обрезки? Вы можете сделать это в BASH с помощью очень простого скрипта:

if [ `stat -f "%z" "$file"` -gt "$MAX_FILE_SIZE" ]; then
    tail -1000 $file > $file.tmp
    #copy and then rm to avoid inode problems
    cp $file.tmp $file
    rm $file.tmp
fi

При этом вы, вероятно, найдете этот пост очень полезно, если вы решили использовать для этого Perl.

person Jay    schedule 10.02.2009
comment
Спасибо за пример bash, у меня есть что-то похожее на это для задачи, но я нахожусь в процессе преобразования всех своих сценариев bash в Perl, и поэтому мне нужно некоторое руководство. Учебник Perl Monks выглядит многообещающе, я рассмотрю его позже. - person aks; 10.02.2009

Оцените среднюю длину строки в журнале — назовите ее N байт.

Поиск назад от конца файла на 1000*1,10*N (10% погрешность при коэффициенте 1,10). Читайте вперед оттуда, сохраняя только самые последние 1000 строк.


Был задан вопрос - какая функция или модуль?

Встроенная функция seek выглядит как инструмент, который стоит использовать?

person Jonathan Leffler    schedule 10.02.2009
comment
Я думал о чем-то подобном, но с моим довольно ограниченным знанием Perl я не знал, какие модули использовать для выполнения задачи. Например, какую функцию я бы использовал для поиска назад в файле в Perl? - person aks; 10.02.2009

Попробуйте просто использовать утилиту logrotate; он включен в большинство современных дистрибутивов Linux. Родственный инструмент для систем BSD называется newsyslog. Эти инструменты разработаны более или менее для вашей предполагаемой цели: они атомарно перемещают файл журнала с места, создают новый файл (с тем же именем, что и раньше) для хранения новых записей журнала, инструктируют программу, генерирующую сообщения, использовать новый файл, а затем (необязательно) сжимает старый файл. Вы можете указать, сколько ротируемых журналов нужно хранить. Вот потенциальное руководство: http://www.debian-administration.org/articles/117

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

person Emil Sit    schedule 10.02.2009
comment
Я уже решал эту проблему, и я согласен с вами в управлении кэшированием сообщений на стороне предложения. Если вы не используете интерфейс системного журнала, при перемещении файла будут происходить странные вещи. - person Owen Beresford; 17.12.2014