como escrever um script que só atua em novas entradas de log

7

Eu sinto que isso deve ser uma coisa simples, mas estou tendo dificuldades para descobrir isso.

Estou tentando escrever um script que monitore um dos arquivos de log do apache e execute alguma ação específica. Mas como devo proceder para monitorar o arquivo de log?

Toda vez que uma nova linha é escrita para o log, eu quero que essa entrada seja verificada para ver se ela corresponde ao que estou procurando e, se assim for, x acontece. Quando estou fazendo isso manualmente eu usei cat ou tail -f. Eu não quero executar o script a cada 30 segundos via cron e percorrer todo o log (ou mesmo as últimas 5 linhas), descobrir quais dessas linhas são novas desde a última vez que o script foi executado e, em seguida, algumas coisas. p>

Existe uma maneira de verificar apenas a nova entrada no log?

    
por karmet 31.01.2012 / 08:01

8 respostas

5

Executar o seu script pelo cron, mas usar logtail ou logtail2 para ler o arquivo evitará a leitura o arquivo inteiro a cada minuto. Logtail mantém o controle de onde leu pela última vez e pula para esse ponto na próxima vez que você usá-lo.

Se você quiser atuar em novas linhas de log imediatamente, em vez de esperar até 59 segundos entre as chamadas do cron, você terá que usar tail -f ou algum equivalente.

As respostas de Janne e Khaled parecem resolver bem este problema.

    
por 31.01.2012 / 08:44
6

Você pode usar as ferramentas do Linux já disponíveis, como tail , grep e named pipes . Primeiro, crie um pipe nomeado (fifo) usando:

$ mkfifo /tmp/myfifo

Em segundo lugar, crie um script simples que leia este arquivo fifo. Aqui está um exemplo simples:

#!/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"

Esse script lê o pipe nomeado e imprime a linha para stdout até obter a palavra "quit". Este é apenas um exemplo que pode ser personalizado.

Em terceiro lugar, use tail para ler novas linhas anexadas ao arquivo de log do apache e redirecionar a saída para o canal nomeado.

$ tail -n0 -F /var/log/apache2/access.log | grep some_text > /tmp/myfifo

A opção -F significa seguir o arquivo pelo nome, o que deve torná-lo imune ao logrotate. Então, seguirá sempre o mesmo nome de arquivo. O -n0 significa não obter nenhuma linha antiga. O grep é útil para direcionar apenas as linhas relevantes.

Usando esta solução, você não precisa de nenhuma tarefa cron. Basta executar o script e o comando tail mostrado acima.

    
por 31.01.2012 / 09:18
3

Se você tem syslog-ng (provavelmente rsyslogd também) como syslog-daemon, você pode usar isso.

Basta configurá-lo para ficar de olho no arquivo de log do Apache ou, alternativamente, configurar o Apache para enviar logs para o recurso de syslog com CustomLog directive e logger .

O daemon Syslog então usará correspondência de padrões e executará $ foo se alguma correspondência for encontrada. Por exemplo, no syslog-ng você pode configurar um gancho de arquivo de log e filtrá-lo assim:

source apache_log { file("/var/log/apache2/access.log"); };
filter apache_match { match("GET /evilscript.php"); };

E, em seguida, syslog-ng chama o script externo

destination apache_logmatch_script { program("/usr/local/bin/apachematch.pl"); };

Por fim, coloque todos juntos:

log { source(apache_log); filter(apache_match); destination apache_logmatch_script); };

Se você usar essa técnica, o syslog-ng gerará o plano de fundo do seu script esperando que novas coisas apareçam. Por causa disso, você precisa modificar seus scripts para aguardar a entrada de STDIN; aqui está um pequeno exemplo de Perl:

#!/usr/bin/perl -w

$|=1;
while (<>) {
     printf "Stuff happened, I got this entry: %s!\n", $_;
}

Não vou mais fundo com a minha resposta até saber que você quer tentar essa técnica.

    
por 31.01.2012 / 09:52
1

Você pode manter um registro da última linha que leu. Em cada nova execução, leia da última + 1 linha até o final do arquivo e atualize o registro.

Mas lembre-se de que o arquivo de log pode ser rotacionado. Então você deve manter um registro do número do inode por exemplo.

fail2ban implementa o monitoramento do arquivo de log da maneira que você deseja. Talvez dê uma olhada nisso? Ou você pode pegar algumas ideias ou usá-las.

    
por 31.01.2012 / 08:28
0

Você pode usar o diff. Copie o arquivo de log para um arquivo temporário.

Faça um diff do arquivo de log ao vivo e do arquivo temporário.

Execute o padrão correspondente no diff resultante.

Idéia retirada do plugin nagios check_log. Consulte o link para obter mais detalhes.

    
por 31.01.2012 / 09:31
0

Se o fail2ban não for adequado às suas necessidades, você pode tentar modificar flog.c que foi escrito por Markus J. Ranum:

"Este pequeno utilitário faz o equivalente a" tail -f ", mas é inteligente o suficiente para lidar com a mudança de arquivos se um rotador de log mover o arquivo para fora sob o usuário enquanto estamos correndo. Além disso, ao contrário de "tail -f" isso programa é inteligente o suficiente para sair quando o usuário sair (!) e não vomitar logs para o arquivo para sempre. Nenhum esforço é feito na elegância ou desempenho ".

Você pode modificar para verificar se alguma nova linha corresponde ao padrão desejado e agir de acordo.

    
por 31.01.2012 / 09:49
0

Se você quiser uma solução python, confira o Pygtail: link

É baseado na logcheck ' logtail2 tool

    
por 28.04.2015 / 01:50
0
#!/bin/bash

while read line;
do
      echo $line > /tmp/output.log
      mail -s 'Event Msg.' '[email protected]' < /tmp/output.log
done < <(tail -n0 -F /var/adm/messages)
    
por 19.06.2015 / 05:50