Додавання штампа часової позначки разом із рядками файлів журналу


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.

ФІФО

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

Виберіть приклад:

$ 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приймає його, обробляє і записує в звичайний файл.

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

Для вашої конкретної ситуації ви просто налаштовуєте свою програму на запис журналів у файл fifo. Якщо ви не можете його налаштувати - просто видаліть оригінальний файл журналу та створіть файл fifo. Але зауважте ще раз, що якщо sedцикл загине з якоїсь причини - ваша програма буде заблокована при спробі переходу writeу файл, поки хтось не вийде readз файлового каналу.

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

Асинхронна обробка з 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. Мінуси - менш точні часові позначки та дублювання файлів журналів.


Дякую. Fіfo здається дуже придатним для мого використання. ! Тож як я можу перенаправити свій вміст у файлі журналу оновлення до цього foo.log.fifo, щоб він міг також додавати час.
Кратос

Просто покращили відповідь. Пояснив, чому fifo блокує ваш tailf, додав правильний спосіб його використання. Насправді шлях із tailfздається більш елегантним, але я покинув шлях фіфо з надією, що комусь це стане в нагоді.
Дмитро Василянов

Використання вашої відповіді sed для анотування виводу vmstat дає часову позначку, яка не змінюється, vmstat 1 | sed -e "s / ^ / $ (дата -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
    
  • Або надрукуйте часову позначку та увійдіть до stdout

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

Для тестування кактусів я використовую, randщоб додати деякі випадкові значення, які використовую для графіків температури для моніторингу температури моєї системи.

Pushmonstats.sh - це сценарій, який збирає статистику температур системи мого ПК та надсилає його до Raspberry Pi, на якому працюють кактуси. Деякий час тому мережа застрягла. У моєму журналі помилок я отримав лише тайм-аути 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.