Сохранить вывод команды в кольцевой буфер

16

У меня есть длительная команда, которая генерирует большой вывод на стандартный вывод. Я хотел бы иметь возможность сохранить, например, только последние три дня или последний гибибайт (избегая линий разреза посередине) и, если возможно, в файловых фрагментах размером не более 20 МБ. Каждому фрагменту файла присваивается числовой суффикс или отметка времени.

Что-то вроде:

my-cmd | magic-command --output-file-template=my-cmd-%t \
                       --keep-bytes=1G \
                       --keep-time=3d \
                       --max-chunk-size=20M \
                       --compress=xz

Написал бы:

my-cmd-2014-09-05T10:04:23Z

Когда он достигает 20M, он сжимает его, открывает новый и т. Д., А через некоторое время начинает удалять самые старые файлы.

Существует ли такая команда?

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

Стефан Шазелас
источник
Что такое "гибибайт"?
Питер Мортенсен
@PeterMortensen Википедия: Гибибайт
jw013

Ответы:

6

Вы можете получить то, что вам нужно, через pipelog , который «позволяет вращать или очищать журнал запущенного процесса, пропуская его через промежуточное звено, которое реагирует на внешние сигналы», например:

spewstuff | pipelog spew.log -p /tmp/spewpipe.pid -x "gzip spew.log.1"

Затем вы можете получить pid от /tmp/spewpipe.pid:

kill -s USR1 $(</tmp/spewpipe.pid)

Но это вы должны настроить cron или что-то. Однако здесь есть одна загвоздка. Обратите внимание: gzip spew.log.1это потому, что -xкоманда выполняется после ротации журнала. Таким образом, у вас есть дальнейшая проблема перезаписи spew.log.1.gzкаждый раз, если вы не напишете короткий скрипт, чтобы выполнить gzip, затем переместить файл и использовать его в качестве -xкоманды.

Полное раскрытие: я написал это, так что, конечно, работает отлично . ;) Я буду иметь в виду вариант сжатия или что-то, что лучше облегчает его, для версии 0.2 (цель предназначения -xнесколько иная, но она будет работать, как указано выше). Также неплохо использовать автоматическое переключение ... первая версия преднамеренно минимальна, так как я не поддался соблазну добавить ненужные функции (в конце концов, для этого не так сложно настроить работу cron).

Обратите внимание, что он предназначен для вывода текста ; если есть потенциальные нулевые байты, вы должны использовать -z- который заменяет ноль чем-то другим. Это был компромисс для упрощения реализации.

лютик золотистый
источник
Благодарю. Я с нетерпением жду pipelog-0.3;-). Я также наткнулся на metacpan.org/release/File-Write-Rotate . Обратите внимание, что задания cron мало помогут при ротации в зависимости от размера файла.
Стефан Шазелас
Вращающийся в зависимости от размера!?! Он сохраняет данные в чистом виде, так что вы можете проверять файл с интервалами ...
goldilocks
Таким образом, вы не сможете надежно сохранить размер менее 20 м (как в моих требованиях к вопросу).
Стефан Шазелас
Другое дело, что это в основном только текст (я добавил последний абзац об этом).
Златовласка
4

Dan Бернштейна Multilog , по- видимому это сделать - или , возможно , большинство из них, обеспечивая при этом выход через дескрипторы файлов для процессора! Чтобы компенсировать разницу , как вам нравится - хотя размер спецификации 20M / 1G может занять некоторое finagling , как это кажется 16М является его внешний лимит на бревно. Далее следует, в большинстве случаев, выбор «копировать + вставить» по приведенной выше ссылке, хотя в ссылке также указаны другие параметры, такие как отметка времени на строку, поддержание [других] файлов, содержащих только самые последние шаблоны соответствия строк, и многое другое. ,

Интерфейс

 multilog script

... скрипт состоит из любого количества аргументов. Каждый аргумент определяет одно действие. Действия выполняются по порядку для каждой строки ввода.

Выбор линий

Каждая строка изначально выбрана. Действие...

-pattern

... отменяет выбор линии, если шаблон соответствует линии. Действие...

+pattern

выбирает линию, если шаблон соответствует линии.

... шаблон представляет собой цепочку звезд и не звезд. Он соответствует любой последовательности строк, совпадающей со всеми звездами и не звездами в одном и том же порядке. Не звезда соответствует самому себе. Звезда перед концом шаблона соответствует любой строке, которая не включает следующий символ в шаблоне. Звезда в конце шаблона соответствует любой строке.

Автоматически вращаемые журналы

Если dir начинается с точки или косой черты, то действие ...

 dir

... добавляет каждую выбранную строку в журнал с именем dir . Если dir не существует, multilogсоздает его.

Формат журнала выглядит следующим образом:

  1. dir - это каталог, содержащий некоторое количество старых файлов журнала, файл журнала с именем current и другие файлы для multilogотслеживания его действий.

  2. Каждый старый файл журнала имеет имя, начинающееся с @ , продолжающееся точной отметкой времени, показывающей, когда файл был завершен, и заканчивающееся одним из следующих кодов:

    • .s : Этот файл полностью обработан и безопасно записан на диск.
    • .u : Этот файл создавался в момент сбоя. Возможно, было усечено. Это не было обработано.

Действие...

 ssize

... устанавливает максимальный размер файла для последующих действий dir . multilogрешит, что ток достаточно велик, если ток имеет размер в байтах. ( multilogтакже решит, что current будет достаточно большим, если увидит новую строку в пределах 2000 байт от максимального размера файла; он попытается завершить файлы журнала на границах строк.) Размер должен быть между 4096 и 16777215. Максимальный размер файла по умолчанию - 99999.

В версиях 0.75 и выше: если multilogполучает сигнал ALRM , он немедленно решает, что ток достаточно велик, если ток непустой.

(Примечание: я подозреваю, что zsh scheduleвстроенную функцию можно легко убедить отправить через ALRMопределенные интервалы, если это необходимо.)

Действие...

 nnum

... устанавливает количество файлов журнала для последующих действий dir . После переименования текущего , если multilogвидит num или более старых файлов журнала, он удаляет старый файл журнала с наименьшей отметкой времени. num должно быть не менее 2. Число файлов журнала по умолчанию - 10.

Действие...

 !processor

... устанавливает процессор для последующих действий dir . multilogбудет передавать ток через процессор и сохранять вывод как старый файл журнала вместо текущего . multilogтакже сохранит любой вывод, который процессор записывает в дескриптор 5, и сделает этот вывод читаемым в дескрипторе 4, когда он запустит процессор в следующем файле журнала. Для надежности процессор должен выходить не равным нулю, если у него есть какие-либо проблемы при создании выходных данных; multilogзатем запустим его снова. Обратите внимание, что работающий процессор может заблокировать любую входную информацию для программы multilog.

mikeserv
источник
2

Лучшее, что я смог найти в качестве приближения, не связанного с написанием огромных кусков кода, это следующий zshкод:

autoload zmv
mycmd |
  while head -c20M > mycmd.log && [ -s mycmd.log ]; do
    zmv -f '(mycmd.log)(|.(<->))(|.gz)(#qnOn)' '$1.$(($3+1))$4'
    {rm -f mycmd.log.1 mycmd.log.50.gz; (gzip&) > mycmd.log.1.gz} < mycmd.log.1
  done

Здесь разбиваются и вращаются не более 51 20MiB больших файлов.

Стефан Шазелас
источник
может быть ... шлейфы? btrfsтакже может быть установлен с compress-force=zlib.
mikeserv
2

Вот взломанный скрипт на python, чтобы сделать что-то вроде того, что вы запрашиваете:

#!/bin/sh
''':'
exec python "$0" "$@"
'''

KEEP = 10
MAX_SIZE = 1024 # bytes
LOG_BASE_NAME = 'log'

from sys import stdin
from subprocess import call

log_num = 0
log_size = 0
log_name = LOG_BASE_NAME + '.' + str(log_num)
log_fh = open(log_name, 'w', 1)

while True:
        line = stdin.readline()
        if len(line) == 0:
                log_fh.close()
                call(['gzip', '-f', log_name])
                break
        log_fh.write(line)
        log_size += len(line)
        if log_size >= MAX_SIZE:
                log_fh.close()
                call(['gzip', '-f', log_name])
                if log_num < KEEP:
                        log_num += 1
                else:
                        log_num = 0
                log_size = 0
                log_name = LOG_BASE_NAME + '.' + str(log_num)
                log_fh = open(log_name, 'w', 1)
Марк Вагнер
источник
1
Есть ли причина использовать его в качестве сценария оболочки, который execв первую очередь использует python вместо использования pythonили env pythonhashbang?
Петер