Добавление метки времени вместе со строками файла журнала


11

У меня есть файл журнала, и мне нужно добавлять метки времени к каждой строке по мере их добавления. Поэтому я ищу сценарий, который добавляет временные метки к каждой записи в строках журнала и может работать как задание cron.

Ответы:


18

Общий путь

$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log

Как это работает:

  1. catчитает вызываемый файл input.logи просто печатает его в стандартный поток вывода.

    Обычно стандартный вывод подключен к терминалу, но этот небольшой скрипт содержит |так, что оболочка перенаправляет стандартный вывод catна стандартный ввод sed.

  2. sedчитает данные (как catпроизводит их), обрабатывает их (согласно сценарию, предоставленному с -eопцией), а затем печатает их в стандартный вывод. Под сценарием "s/^/$(date -R) /"подразумевается замена каждого начала строки текстом, сгенерированным date -Rкомандой (общая конструкция для команды замены:) s/pattern/replace/.

  3. Затем в соответствии с >> bashперенаправляет вывод sedв файл с именем output.log( >означает заменить содержимое файла и >>означает добавить в конец).

Проблема $(date -R)оценивается один раз при запуске скрипта, поэтому он вставляет текущую метку времени в начало каждой строки. Текущая временная метка может быть далека от момента, когда было сгенерировано сообщение. Чтобы избежать этого, вы должны обрабатывать сообщения так, как они записаны в файл, а не с помощью задания cron.

ФИФО

Стандартное перенаправление потока, описанное выше, называется pipe . Вы можете перенаправить его не только |между командами в скрипте, но и через файл FIFO (он же именованный канал ). Одна программа запишет в файл, а другая прочитает данные и получит их при первой отправке.

Выберите пример:

$ mkfifo foo.log.fifo
$ while true; do cat foo.log.fifo | sed -e "s/^/$(date -R) /" >> foo.log; done;

# have to open a second terminal at this point
$ echo "foo" > foo.log.fifo
$ echo "bar" > foo.log.fifo
$ echo "baz" > foo.log.fifo

$ cat foo.log      

Tue, 20 Nov 2012 15:32:56 +0400 foo
Tue, 20 Nov 2012 15:33:27 +0400 bar
Tue, 20 Nov 2012 15:33:30 +0400 baz

Как это работает:

  1. mkfifo создает именованную трубу

  2. while true; do sed ... ; doneзапускает бесконечный цикл и на каждой итерации выполняет sedперенаправление foo.log.fifoна стандартный ввод; sed блокирует ожидание входных данных, а затем обрабатывает полученное сообщение и печатает его на стандартный вывод, перенаправленный на foo.log.

    В этот момент вы должны открыть новое окно терминала, потому что цикл занимает текущий терминал.

  3. echo ... > foo.log.fifoвыводит сообщение на его стандартный вывод, перенаправленное в файл fifo, sedпринимает его, обрабатывает и записывает в обычный файл.

Важное замечание - это fifo, так же как и любой другой канал не имеет смысла, если одна из его сторон не связана с каким-либо процессом. Если вы попытаетесь записать в канал, текущий процесс будет заблокирован, пока кто-нибудь не прочитает данные на другой стороне канала. Если вы хотите читать из канала, процесс будет блокироваться, пока кто-нибудь не запишет данные в канал. sedЦикл в примере выше ничего не делает (спит) , пока вы не сделаете echo.

Для вашей конкретной ситуации вы просто настраиваете свое приложение для записи сообщений журнала в файл fifo. Если вы не можете настроить его - просто удалите оригинальный файл журнала и создайте файл fifo. Но обратите внимание еще раз: если sedцикл по какой-то причине прекратится - ваша программа будет заблокирована при попытке открыть writeфайл, пока кто-то не выйдет readиз fifo.

Преимущество заключается в том, что текущая временная метка оценивается и прикрепляется к сообщению, когда программа записывает его в файл.

Асинхронная обработка с tailf

Чтобы сделать запись в журнал и обработку более независимой, вы можете использовать два обычных файла с tailf. Приложение запишет сообщение в необработанный файл, а другой процесс прочитает новые строки (выполните асинхронную запись) и обработает данные с записью во второй файл.

Давайте возьмем пример:

# will occupy current shell
$ tailf -n0 bar.raw.log | while read line; do echo "$(date -R) $line" >> bar.log; done;

$ echo "foo" >> bar.raw.log
$ echo "bar" >> bar.raw.log
$ echo "baz" >> bar.raw.log

$ cat bar.log

Wed, 21 Nov 2012 16:15:33 +0400 foo
Wed, 21 Nov 2012 16:15:36 +0400 bar
Wed, 21 Nov 2012 16:15:39 +0400 baz

Как это работает:

  1. Запустите tailfпроцесс, который будет следовать за записью, bar.raw.logи распечатайте их на стандартный вывод, перенаправленный в бесконечный while read ... echoцикл. Этот цикл выполняет два действия: считывает данные из стандартного ввода в вызываемую переменную буфера lineи затем записывает сгенерированную временную метку со следующими буферизованными данными в bar.log.

  2. Напишите несколько сообщений в bar.raw.log. Вы должны сделать это в отдельном окне терминала, потому что первое будет занято, tailfкоторое будет следовать за операциями записи и выполнять свою работу. Достаточно просто.

Плюсы в том, что ваше приложение не заблокирует, если вы убьете tailf. Минусы - менее точные временные метки и дублирующие файлы журналов.


Спасибо .ififo кажется очень подходящим для моего использования. Моя программа уже пишет в журнале file.txt, но этот файл необходимо перенаправить на ваш файл foo.log.fifo. Но выполнение $ tailf file.txt> foo.log.fifo зависает ! Итак, как я могу перенаправить свое содержимое в файле журнала обновлений на этот файл foo.log.fifo, чтобы он также мог добавить время.
— Кратос

Просто улучшил ответ. Объяснил, почему fifo блокирует ваш tailf, добавил правильный способ его использования. На самом деле путь с tailfболее элегантным выглядит, но я оставил путь с надеждой, что он кому-нибудь пригодится.
— Дмитрий Василянов

Использование вашего ответа sed для аннотирования вывода vmstat дает временную метку, которая не изменяется, vmstat 1 | sed -e "s / ^ / $ (date -R) /"
— ChuckCottrill


2

Модифицировано из ответа Дмитрия Васильянова.

В bash-скрипте вы можете перенаправлять и переносить вывод с меткой времени строка за строкой на лету.

Когда использовать:

  • Для заданий сценария bash вставьте строку перед основным сценарием
  • Для не скриптовых заданий создайте скрипт для вызова программы.
  • Для контроля сервисов системой лучше использовать tailfфайл журнала, как сказал Дмитрий Василянов.

Пример с именем foo.sh:

#!/bin/bash
exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)

echo "foo"
sleep 1
echo "bar" >&2
sleep 1
echo "foobar"

И результат:

$ bash foo.sh
$ cat foo.log
May 12 20:04:11 foo
May 12 20:04:12 bar
May 12 20:04:13 foobar

Как это работает

  1. exec &> Перенаправить stdout и stderr в одно и то же место
  2. >( ... ) труба выводит в асинхронную внутреннюю команду
  3. Остальная часть работает, как Дмитрий Василянов расширил.

Например:

  • временная метка канала и журнал в файл

    #!/bin/bash        
    exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)
    
    echo "some script commands"
    /path-to/some-thrid-party-programs
    
  • Или напечатайте метку времени и войдите в стандартный вывод

    #!/bin/bash        
    exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line"; done;)
    
    echo "some script commands"
    /path-to/some-thrid-party-programs
    

    затем сохраните их в /etc/crontabнастройках

    * * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
    

1

Я использовал tsэтот способ, чтобы получить запись с отметкой времени в журнале ошибок для сценария, который я использую, чтобы заполнить Cacti статистикой удаленного хоста.

Чтобы проверить Cacti, я использую, randчтобы добавить некоторые случайные значения, которые я использую для температурных графиков, чтобы контролировать температуру моей системы.

Pushmonstats.sh - это скрипт, который собирает статистику температуры системы моего ПК и отправляет ее Raspberry Pi, на которой работает Cacti. Некоторое время назад сеть застряла. Я только получил тайм-ауты SSH в моем журнале ошибок. К сожалению, нет записей времени в этом журнале. Я не знал, как добавить отметку времени к записи в журнале. Итак, после некоторых поисков в Интернете, я наткнулся на этот пост, и это то, что я сделал, используя ts.

Чтобы проверить это, я использовал неизвестную опцию rand. Который дал ошибку в stderr. Чтобы захватить его, я перенаправляю его во временный файл. Затем я использую cat, чтобы показать содержимое файла и передать его ts, добавить формат времени, который я нашел в этом посте, и, наконец, записать его в файл ошибок. Затем я очищаю содержимое временного файла, в противном случае я получаю двойные записи для той же ошибки.

Crontab:

* * * * * /home/monusr/bin/pushmonstats.sh 1>> /home/monusr/pushmonstats.log 2> /home/monusr/.err;/bin/cat /home/monusr/.err|/usr/bin/ts %F-%H:%M:%.S 1>> /home/monusr/pushmonstats.err;> /home/monusr/.err

Это дает следующее в моем журнале ошибок:

2014-03-22-19:17:53.823720 rand: unknown option -- '-l'

Может быть, это не очень элегантный способ сделать это, но это работает. Интересно, есть ли более элегантный подход к этому.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.