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


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.