Форум русскоязычного сообщества Ubuntu


Получить помощь и пообщаться с другими пользователями Ubuntu можно
на irc канале #ubuntu-ru в сети Freenode
и в Jabber конференции ubuntu@conference.jabber.ru

Автор Тема: bash скрипт слежения за искомым выраженим в логах.  (Прочитано 2664 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн dazm

  • Автор темы
  • Новичок
  • *
  • Сообщений: 3
    • Просмотр профиля
Всем доброго дня.
Не могу решить следующюю задачу, точнее связть всё воедино.
Необходимо написать скрипт, который бы запускался по крону и отслеживал появление выражения в log-файле.
Причем при последующем запуске скрипта, ненадо просматривать весь лог сначала, т.к. размеры логов могут быть довольно большими.
Поэтому одним из параметров передаваемых скрипту должен быть ключ, на последнюю строку в предидущем запуске скрипта.

Найти номер последний строки можно с помощью выражения :
awk '{last=NR} END {print last}' namefile.log >> lastline

Вывести строки от 10-ой и до конца файла :
sed -n '10,$p' namefile.log >> last10lines

Небольшой пример.
Допустим я запустил скрипт первый раз, он прошёл весь лог-файл до конца и не нашел искомого выражения.
В конце он записал номер строки, на которой заверишился поиск. В следующий раз, например через 15 мин, скрипт запускается повторно (p.s. за это время появилась запись в логе об искомой ошибке)
Необходимо запустить поиск по лог-файлу, с последней запомненной строки и найденное выражение записать в файл.

sed -n '10,$p' namefile.log | grep ERROR > error.log

И вот тут у меня проблема. Я не могу всё это связать в единый скрипт, так, чтобы номер строки, с которой надо начать поиск передавался через аргумент (читался из файла), а в конце работы скрипта номер последней строки сохранялся в файл, перетирая прошлое значение.
Плюс вторым аргументом должен передаватся путь до наблюдаемого файла (в примере namefile.log)

andrey_p

  • Гость
1. Готовим среду:

mkdir -p ~/work/logseek
cd $_                               # or cd <ALT-_> or cd <ALT-.>
seq 1 10 > test.log
sed -i 's/5/5 ERROR/; s/7/7 ERROR/' t<TAB>
cat t<TAB>
2. Где-то надо хранить значение строки. Можно в БД, в облаке, но
реально нам нужен простой файл:

echo 3 > nline
3. Сам не знаю, почему `cat nline` работает без убирания символа
перевода строки:

sed -n "$(cat nline)"',$p' test.log | grep ERROR
4. Соображаем, что № последней проверенной строки равен количеству строк:

wc -l test.log
Смотрим на вывод:

wc -l test.log | sed -r 's/(^[0-9]+).*/\1/'
5. Сводим все в тестовый скрипт:

lf=test.log
nf=nline
ef=errors.log
msg=ERROR
sed -n $(cat "$nf")',$p' "$lf" | grep "$msg" >> "$ef"
wc -l "$lf" | sed -r 's/(^[0-9]+).*/\1/' >"$nf"
6. Тестируем:

sh -x script
cat nline
cat errors.log
seq 11 15 | sed 's/12/12 ERROR/; s/13/13 ERROR/' >> test.log
sh script
cat nline
cat errors.log

7. Выбираем место для "nline"-файла, меняем скрипт на работу с
аргументами, добавляем шибанг, атрибут выполнения, тестируем с
реальными параметрами и файлами, документируем, прописываем в cron.

8. Думаем о том, что grep, когда используется sed, ненужен. Меняем.
Думаем, что используя tail скрипт может вообще летать. Меняем,
возвращаем grep. Тестируем на время, убеждаемся, что разницы во всех
трех скриптах нет. Через пару лет обнаруживаем, что действительно
скоростным решением было бы использование tac, но поскольку работаем
на гораздо более мощной машине - плюем на это.

ЗЫ До чего же очередной утренний приступ нехотения работать доводит. :)
« Последнее редактирование: 26 Январь 2012, 07:25:43 от andrey_p »

Оффлайн Yurror

  • Старожил
  • *
  • Сообщений: 1966
    • Просмотр профиля
Запускаем демона
Код: Bash
  1.  
  2. on_ahtung_action() {
  3.    echo MEGA $1
  4. }
  5.  
  6. for line in $(tail -f /var/log/log_file | grep AHTUNG)
  7. do
  8.   on_ahtung_action($line)
  9. done
  10.  
  11.  
по желанию пишем для него watchdog

Оффлайн dazm

  • Автор темы
  • Новичок
  • *
  • Сообщений: 3
    • Просмотр профиля
Большое спасибо за разъяснение, но есть пару вопросов.


sed -i 's/5/5 ERROR/; s/7/7 ERROR/' t<TAB>

Параметр -i на моём сервере не работает, но суть понятна :)
Я сделал так :
sed 's/5/5 ERROR/; s/7/7 ERROR/' test.log > test1.log
sed -n "$(cat nline)"',$p' test.log | grep ERROR
То что сюда можно подсунуть аргумент, - очень хорошая мысль.
wc -l test.log | sed -r 's/(^[0-9]+).*/\1/'
Зачем всё это, если
awk '{last=NR} END {print last}' namefile.log >> lastline
даёт сразу номер последней строки ? (sed -r у меня на сервере не рабоает)

Еще хотелось бы, чтобы проверка номера последней строки осуществлялась не с начала файла, а с
ранее сохраненной позиции...на 100Мб файле работает около 5-10 сек.
По всей видимости awk прогоняет файл с самого начала.
А еще мне что-то подсказывает, что проверка номера последней строки делается несколько раз, т.е. после
каждого выполнения
sed -n $(cat "$nf")',$p' "$lf" | grep "$msg" >> "$ef"
идёт проверка awk номера последней строки, и поэтому скрипт работает дольше.
В конечном итоге у меня скрипт выглядит так:

lf=/oracle/admin/rmsprod/bdump/alert_rmsprod.log
nf=/retek_data/retek/production/prod_bat/scripts/nline
ef=/retek_data/retek/production/prod_bat/scripts/errors.log
msg=ORA-
sed -n $(cat "$nf")',$p' "$lf" | grep "$msg" >> "$ef"
awk '{last=NR} END {print last}' $lf > $nf

Запускается ли awk один раз, или столько раз, сколько появилось строк с последней позиции $nf ?

Запускаем демона
по желанию пишем для него watchdog

Идея с демоном несомненно самая простая, и скорее всего даже лучшая, только вот скрипт
у меня будет запускатся из под виндовой софтины, которая мониторит всю систему в целом.
« Последнее редактирование: 27 Январь 2012, 02:50:12 от dazm »

andrey_p

  • Гость
awk '{last=NR} END {print last}' namefile.log >> lastline :)
В Практике программирования предлагается написать программу сортировки, которая была реальной, но самой медленной из возможных. Если бы задача стояла написать самую медленную программу определения количества строк в файле, то здесь победа была бы однозначна. Awk считывает каждую строку, и, для каждой(!) строки выполняет присваивание текущего номера строки переменной. На последней строке это совпадает с количеством строк и становится значением для блока END.

wc -l test.log | sed  's!\(^[0-9][0-9]*\).*!\1!'

Оффлайн dazm

  • Автор темы
  • Новичок
  • *
  • Сообщений: 3
    • Просмотр профиля
wc -l test.log | sed  's!\(^[0-9][0-9]*\).*!\1!'

Так результатом этого sed является и номер строки и имя файла (т.е. для файла test.log из 10 строк результатом будет
'  10 test.log', что потом приводит к ошибке при выполнении
sed -n $(cat "$nf")',$p' "$lf" | grep "$msg" > $ef

p.s. проблему решил, написал вот такой sed
wc -l test.log | sed 's/[^0-9]//g'
« Последнее редактирование: 28 Январь 2012, 02:26:30 от dazm »

 

Страница сгенерирована за 0.069 секунд. Запросов: 24.