Я чувствую, что это должно быть просто, но мне трудно это понять.
Я пытаюсь написать сценарий, который будет отслеживать один из файлов журнала apache и предпринимать определенные действия. Но как мне следить за файлом журнала?
Каждый раз, когда в журнал записывается новая строка, я хочу, чтобы эта запись проверялась, чтобы увидеть, соответствует ли она тому, что я ищу, и если да, то происходит x. Когда я делаю это вручную, я использовал cat или tail -f. Я не хочу запускать сценарий каждые 30 секунд через cron и просматривать весь журнал (или даже последние 5 строк), выяснять, какие из этих строк являются новыми с момента последнего запуска сценария, а затем и некоторые вещи.
Есть ли способ проверить только одну новую запись в журнале?
Вы можете использовать уже доступные инструменты Linux, такие как tail
, grep
, и named pipes
. Сначала создайте именованный канал (fifo), используя:
$ mkfifo /tmp/myfifo
Во-вторых, создайте простой сценарий, который будет читать из этого файла fifo. Вот простой пример:
#!/bin/bash
pipe=/tmp/myfifo
while true
do
if read line <$pipe; then
if [[ "$line" == 'quit' ]]; then
break
fi
echo $line
fi
done
echo "Reader exiting"
Этот скрипт читает из именованного канала и выводит строку на стандартный вывод, пока не получит слово «выйти». Это просто пример, который можно настроить.
В-третьих, используйте tail
для чтения новых строк, добавленных в файл журнала apache, и перенаправления вывода в именованный канал.
$ tail -n0 -F /var/log/apache2/access.log | grep some_text > /tmp/myfifo
В -F
option означает следовать за файлом по имени, что должно сделать его невосприимчивым к logrotate. Таким образом, он всегда будет следовать за одним и тем же именем файла. В -n0
означает не получать старую строку. В grep
полезно направлять только соответствующие строки.
Используя это решение, вам не потребуется никакого задания cron. Просто запустите сценарий и указанную выше команду tail.
Запуск вашего скрипта через cron, но с использованием logtail
или logtail2
чтение файла позволит избежать чтения всего файла каждую минуту. Logtail отслеживает, где он в последний раз читал, и переходит к этой точке при следующем использовании.
Если вы хотите работать с новыми строками журнала немедленно, а не ждать 59 секунд между вызовами cron, вам придется использовать tail -f
или аналогичный.
Оба ответа Янне и Халед хорошо решают эту проблему.
Если у вас есть syslog-ng
(наверное rsyslogd
тоже подойдет) в качестве syslog-daemon, вы можете использовать это.
Просто настройте его, чтобы следить за файлом журнала Apache, или, в качестве альтернативы, настройте Apache для отправки журналов в средство syslog с помощью CustomLog
директива и logger
.
Затем Syslog-daemon будет использовать сопоставление с образцом и выполнит $ foo, если какое-либо совпадение будет найдено. Например, в syslog-ng вы можете настроить перехват файла журнала и отфильтровать его следующим образом:
source apache_log { file("/var/log/apache2/access.log"); };
filter apache_match { match("GET /evilscript.php"); };
И затем syslog-ng вызывает внешний скрипт
destination apache_logmatch_script { program("/usr/local/bin/apachematch.pl"); };
Наконец, соберите все это вместе:
log { source(apache_log); filter(apache_match); destination apache_logmatch_script); };
Если вы используете эту технику, syslog-ng создаст фон вашего скрипта, ожидая появления нового материала. Из-за этого вам необходимо изменить свои сценарии, чтобы они ожидали ввода от STDIN; вот небольшой пример Perl:
#!/usr/bin/perl -w
$|=1;
while (<>) {
printf "Stuff happened, I got this entry: %s!\n", $_;
}
Я не буду углубляться в свой ответ, пока не узнаю, что вы хотите попробовать эту технику.
Вы можете записывать последнюю прочитанную строку. При каждом новом запуске читать от последней + 1 строки до конца файла и обновлять запись.
Но имейте в виду, что файл журнала может быть повернут. Таким образом, вы должны вести запись, например, номера inode.
fail2ban осуществляет мониторинг файлов журналов так, как вам кажется. Может взглянуть на это? Вы можете либо позаимствовать некоторые идеи, либо использовать их.
Вы можете использовать diff. Скопируйте файл журнала во временный файл.
Возьмите разницу между живым файлом журнала и временным файлом.
Запустите сопоставление с образцом для полученного файла diff.
Идея взята из плагина nagios check_log. Видеть http://www.kilala.nl/Sysadmin/index.php?id=715 Больше подробностей.
Если fail2ban не подходит для ваших нужд, вы можете попробовать изменить flog.c который написал Маркус Дж. Ранум:
«Эта небольшая утилита выполняет аналог« tail -f », но достаточно умен, чтобы обрабатывать изменение файлов, если ротатор журналов перемещает файл из-под пользователя во время работы. Кроме того, в отличие от« tail -f »эта программа достаточно умен, чтобы выйти, когда пользователь выходит из системы (!), и не будет извергать журналы на pty навсегда. Не прилагается никаких усилий для элегантности или производительности ".
Вы можете изменить, чтобы проверить, соответствует ли какая-либо новая строка желаемому шаблону, и действовать соответствующим образом.
Если вам нужно решение на Python, попробуйте Pygtail: https://github.com/bgreenlee/pygtail
Это основано на logcheck
с logtail2
инструмент
#!/bin/bash
while read line;
do
echo $line > /tmp/output.log
mail -s 'Event Msg.' 'email@gmail.com' < /tmp/output.log
done < <(tail -n0 -F /var/adm/messages)