it-swarm-pt.tech

Você tem algum script awk e grep útil para analisar os logs do Apache?

Posso usar analisadores de log, mas geralmente preciso analisar logs da web recentes para ver o que está acontecendo no momento.

Às vezes, faço coisas como descobrir os 10 ips principais que solicitam um determinado arquivo

cat foo.log | grep request_to_file_foo | awk '{print $1}' |  sort -n | uniq -c | sort -rn | head

O que você tem na sua caixa de ferramentas?

70
deadprogrammer

Você pode fazer praticamente qualquer coisa com os arquivos de log do Apache apenas com o awk. Os arquivos de log do Apache são basicamente separados por espaços em branco, e você pode fingir que as aspas não existem e acessar as informações de seu interesse pelo número da coluna. O único momento em que isso ocorre é se você possui o formato de log combinado e está interessado nos agentes do usuário; nesse momento, você deve usar aspas (") como separador e executar um comando awk separado. A seguir, serão mostrados os IPs de todo usuário que solicita a página de índice classificada pelo número de hits:

awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
    END { for (i in ipcount) {
        printf "%15s - %d\n", i, ipcount[i] } }' logfile.log

$ 7 é o URL solicitado. Você pode adicionar as condições que desejar no início. Substitua '$ 7 == "/" pelas informações que desejar.

Se você substituir $ 1 em (ipcount [$ 1] ++), poderá agrupar os resultados por outros critérios. Usar US $ 7 mostraria quais páginas foram acessadas e com que frequência. Obviamente, você deseja alterar a condição no início. A seguir, mostramos quais páginas foram acessadas por um usuário a partir de um IP específico:

awk -F'[ "]+' '$1 == "1.2.3.4" { pagecount[$7]++ }
    END { for (i in pagecount) {
        printf "%15s - %d\n", i, pagecount[i] } }' logfile.log

Você também pode canalizar a saída através da classificação para obter os resultados em ordem, como parte do comando Shell ou também no próprio script awk:

awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
    END { for (i in ipcount) {
        printf "%15s - %d\n", i, ipcount[i] | sort } }' logfile.log

O último seria útil se você decidisse expandir o script awk para imprimir outras informações. É tudo uma questão do que você deseja descobrir. Estes devem servir como ponto de partida para o que você está interessado.

54
Mark

Uma coisa que eu nunca vi mais alguém fazer, por razões que não consigo imaginar, é alterar o formato do arquivo de log do Apache para uma versão mais facilmente analisável com as informações que realmente são importantes para você.

Por exemplo, nunca usamos autenticação básica HTTP, portanto, não precisamos registrar esses campos. Estou am interessado em quanto tempo cada solicitação leva para atender, portanto, incluiremos isso. Para um projeto, também queremos saber (em nosso balanceador de carga) se algum servidor está atendendo solicitações mais lentamente que outros, então registramos o nome do servidor para o qual estamos fazendo proxy.

Aqui está um trecho da configuração do Apache de um servidor:

# We don't want to log bots, they're our friends
BrowserMatch Pingdom.com robot

# Custom log format, for testing
#
#         date          proto   ipaddr  status  time    req     referer         user-agent
LogFormat "%{%F %T}t    %p      %a      %>s     %D      %r      %{Referer}i     %{User-agent}i" standard
CustomLog /var/log/Apache2/access.log standard env=!robot

O que você realmente não pode dizer disso é que entre cada campo existe um caractere de tabulação literal (\ t). Isso significa que, se eu quiser fazer alguma análise em Python, talvez mostre status que não seja 200, por exemplo, eu posso fazer isso:

for line in file("access.log"):
  line = line.split("\t")
  if line[3] != "200":
    print line

Ou se eu quisesse fazer 'quem está ligando as imagens?' seria

if line[6] in ("","-") and "/images" in line[5]:

Para contagens de IP em um log de acesso, o exemplo anterior:

grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" logfile | sort -n | uniq -c | sort -n

torna-se algo como isto:

cut -f 3 log | uniq -c | sort -n

Mais fácil de ler e entender e muito menos caro computacionalmente (sem regex) que, em logs de 9 GB, faz uma enorme diferença no tempo que leva. Quando isso fica MUITO bom, é se você deseja fazer o mesmo pelos agentes do usuário. Se seus logs forem delimitados por espaço, você precisará fazer alguma correspondência de expressão regular ou pesquisa de string manualmente. Com este formato, é simples:

cut -f 8 log | uniq -c | sort -n

Exatamente o mesmo que o acima. De fato, qualquer resumo que você queira fazer é essencialmente exatamente o mesmo.

Por que diabos eu gastaria a CPU do meu sistema em awk e grep quando o cut fará exatamente o que eu quero ordens de magnitude mais rapidamente?

24
Dan Udey

Esqueça o awk e o grep. Confira asql . Por que escrever scripts ilegíveis quando você pode usar o sql como sintaxe para consultar o arquivo de log. Por exemplo.

asql v0.6 - type 'help' for help.
asql> load /home/skx/hg/engaging/logs/access.log
Loading: /home/skx/hg/engaging/logs/access.log
sasql> select COUNT(id) FROM logs
46
asql> alias hits SELECT COUNT(id) FROM logs
ALIAS hits SELECT COUNT(id) FROM logs
asql> alias ips SELECT DISTINCT(source) FROM logs;
ALIAS ips SELECT DISTINCT(source) FROM logs;
asql> hits
46
asql> alias
ALIAS hits SELECT COUNT(id) FROM logs
ALIAS ips SELECT DISTINCT(source) FROM logs;
16
Vihang D

Aqui está um script para encontrar os principais URLs, principais referenciadores e principais useragents das recentes entradas de log N

#!/bin/bash
# Usage
# ls-httpd type count
# Eg: 
# ls-httpd url 1000
# will find top URLs in the last 1000 access log entries
# ls-httpd ip 1000
# will find top IPs in the last 1000 access log entries
# ls-httpd agent 1000
# will find top user agents in the last 1000 access log entries

type=$1
length=$2

if [ "$3" == "" ]; then
  log_file="/var/log/httpd/example.com-access_log"
else
  log_file="$3"
fi

if [ "$type" = "ip" ]; then
  tail -n $length $log_file | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
Elif [ "$type" = "agent" ]; then
  tail -n $length $log_file | awk -F\" '{print $6}'| sort -n | uniq -c | sort -n
Elif [ "$type" = "url" ]; then
  tail -n $length $log_file | awk -F\" '{print $2}'| sort -n | uniq -c | sort -n
fi

Origem

6
anoopjohn

para contagens de IP em um log de acesso:

cat log | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n

É um pouco feio, mas funciona. Eu também uso o seguinte com o netstat (para ver as conexões ativas):

netstat -an | awk '{print $5}' | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | egrep -v "(`for i in \`ip addr | grep inet |grep eth0 | cut -d/ -f1 | awk '{print $2}'\`;do echo -n "$i|"| sed 's/\./\\\./g;';done`127\.|0\.0\.0)" | sort -n | uniq -c | sort -n

Eles são alguns dos meus favoritos "one liners" :)

5
f4nt

Aqui, meu exemplo 'sed', lê o formato padrão dos logs do Apache e o converte em algo mais conveniente para o processamento automático. A linha inteira é definida como expressão regular, as variáveis ​​são salvas e gravadas na saída com '#' como separador.

A notação simplificada da entrada é:% s% s% s [% s] "% s"% s% s "% s" "% s"

Exemplo de linha de entrada: xx.xx.xx.xx - - [29/Mar/2011: 12: 33: 02 +0200] "GET /index.html HTTP/1.0" 200 9443 "-" "Mozilla/4.0"

Exemplo de linha de saída: xx.xx.xx.xx # - # - # 29/Mar/2011: 12: 33: 02 + 0200 # GET /index.html HTTP/1.0 # 200 # 9443 # - # Mozilla/4.0

cat access.log | \ 
  sed 's/^\(.*\) \(.*\) \(.*\) \[\(.*\)\] \"\(.*\)\" \(.*\) \(.*\) \"\(.*\)\" \"\(.*\)\"$/\1#\2#\3#\4#\5#\6#\7#\8#\9/g'

Sinta o poder das expressões regulares :-)

3
Kris

Criar uma lista de perguntas comuns seria um ótimo índice para essas respostas a essa pergunta. Minhas perguntas comuns são:

  • por que o hitrate mudou?
  • por que o tempo de resposta geral está aumentando? '.

Percebo essas mudanças monitorando as páginas de status do servidor (via mod_status) quanto à taxa de bits e tempo de resposta aproximado para solicitações ativas e concluídas recentemente (sabendo muito bem que sinto falta de uma pilha enorme de dados, mas as amostras são boas o suficiente).

Eu uso a seguinte diretiva LogFormat (o% T é realmente útil)

LogFormat "%h %l %u %t \"%r\" %>s %b 
    \"%{Referer}i\" \"%{User-Agent}i\" %T" custom

Estou procurando causa-efeito e o que aconteceu primeiro ... geralmente sobre subconjuntos específicos de padrões nos meus logs, portanto, preciso saber o seguinte para qualquer padrão/expressão regular:

  • hitcounts por intervalo (minuto ou hora) para um determinado padrão (endereço IP ou sequência ou parâmetros cgi, etc)
  • histogramas de tempo aproximado de resposta (usando o parâmetro% T)

Eu geralmente uso Perl, porque eventualmente fica complexo o suficiente para valer a pena.


Um exemplo que não seja Perl seria uma taxa rápida por minuto para códigos de status que não sejam 200:

tail -9000 access_log | grep -v '" 200 ' | cut -d: -f2,3 | uniq -c

Sim, estou trapaceando com esse grep, presumindo que um espaço entre aspas-200-espaço corresponda apenas aos códigos de status http ... poderia usar awk ou Perl para isolar o campo, mas lembre-se de que pode ser impreciso.


Um exemplo mais complexo no Perl pode ser visualizar uma alteração na taxa de bits de um padrão.

Há muito o que mastigar no script abaixo, especialmente se você não é familiar com o Perl.

  • lê stdin para que você possa usar partes de seus logs, usar tail (especialmente com tail -f), com ou sem greps e outros filtros ...
  • engana a extração de timestamp da Epoch com hack de um regex e uso de Date :: Manip
  • você poderia modificá-lo apenas um pouco para extrair o tempo de resposta ou outros dados arbitrários

código a seguir:

#!/usr/bin/Perl
# script to show changes in hitrates for any regex pattern
# results displayed with arbitrary intervals
# and ascii indication of frequency
# gaps are also displayed properly
use Date::Manip;
use POSIX qw(strftime);
$pattern=shift || ".";
$ival=shift || 60;
$tick=shift || 10;
$minb=undef;
while (<>){
    next unless /$pattern/;
    $stamp="$1 $2" if m[(../.../....):(..:..:..)];
    $Epoch = UnixDate(ParseDate($stamp),"%s");
    $bucket= int($Epoch/$ival)*$ival;
    $minb=$bucket if $bucket<$minb || !defined($minb);
    $maxb=$bucket if $bucket>$maxb;
    $count{$bucket}++;
}
# loop thru the min/max range to expose any gaps
for($t=$minb;$t<=$maxb;$t+=$ival){
    printf "%s %s %4d %s\n",
            $t,
            strftime("%m/%d/%Y %H:%M:%S",localtime($t)),
            $count{$t}+0,
            substr("x"x100,0,$count{$t}/$tick
    );
}

Se você deseja apenas processar métricas padrão, finalize a compra

  • 'mergelog' para reunir todos os seus logs (se você tiver vários apaches atrás de um balanceador de carga) e
  • webalizer (ou awstats ou outro analisador comum).
3
ericslaw

Quem está vinculando suas imagens a quente:

awk -F\" '($2 ~ /\.(jpg|gif)/ && $4 !~ /^http:\/\/www\.mydomain\.com/){print $4}' access_log | sort | uniq -c | sort
2
rkthkr

Eu uso muito o awk tailing ou cat'ing o arquivo. Toda noite eu entrego um relatório da web para cada servidor. Dependendo do seu arquivo de log e do seu LogFormat, você precisará editar alguns dos liners para trabalhar para você.

Aqui está um exemplo simples:

Se eu quiser alterar os logs no meu servidor apenas para códigos de status 404/500, eu faria o seguinte:

# $6 is the status code in my log file

tail -f ${Apache_LOG} |  awk  '$8 ~ /(404|500)/ {print $6}'

<snip>

echo ""
#echo  "Hits by source IP:"
echo "======================================================================"

awk '{print $2}' "$1" | grep -ivE "(127.0.0.1|192.168.100.)" | sort | uniq -c | sort -rn | head -25

echo ""
echo ""
#echo "The 25 most popular pages:"
echo "======================================================================"

awk '{print $6}' "$1" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png)' | \
 sed 's/\/$//g' | sort | \
 uniq -c | sort -rn | head -25

echo ""    
echo ""
echo "The 25 most popular pages (no js or css):"
echo "======================================================================"

awk '{print $6}' "$1" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png|.js|.css)' | \
 sed 's/\/$//g' | sort | \
   uniq -c | sort -rn | head -25

   echo ""


#echo "The 25 most common referrer URLs:"
echo "======================================================================"

awk '{print $11}' "$1" | \
 grep -vE "(^"-"$|/www.$Host|/$Host)" | \
 sort | uniq -c | sort -rn | head -25

echo ""

#echo "Longest running requests"
echo "======================================================================"

awk  '{print $10,$6}' "$1" | grep -ivE '(.gif|.jpg|.png|.css|.js)'  | awk '{secs=0.000001*$1;req=$2;printf("%.2f minutes req time for %s\n", secs / 60,req )}' | sort -rn | head -50

exit 0

</ snip>

2
Michael Steinfeld

Embora não seja sed ou awk, há duas coisas que achei úteis para manipular arquivos de log do Apache e do icecast.

AWStats possui um script muito útil chamado logresolvemerge.pl que combina vários arquivos de log compactados ou não compactados, tira dupes e classifica por carimbo de data/hora. Ele também pode fazer pesquisas de DNS e ser configurado para executar multithread. É particularmente útil quando usado com o awstats, porque o awstats não pode adicionar linhas de registro com registros de data e hora mais antigos que o banco de dados atual; portanto, tudo deve ser adicionado em ordem, mas isso é muito fácil, basta você chuck tudo em logresolvemerge.pl e tudo sai bem.

sed e awk são muito ruins em lidar com datas, porque geralmente os tratam como strings. O awk possui algumas funções de hora e data, mas elas não são suficientes. Por exemplo, extrair um intervalo de linhas entre dois registros de data e hora é difícil se esses registros de data e hora exatos não ocorrerem no arquivo (mesmo que os valores entre eles ocorram) - o exemplo de Chris tem exatamente esse problema. Para lidar com isso, escrevi a PHP que relata os intervalos de data e hora do arquivo de log e também pode extrair um pedaço por faixa de data e hora, usando qualquer formato de data ou hora que você desejar (ele não precisa corresponder ao formato do registro de data e hora do arquivo de log).

Para manter esse tópico, aqui estão alguns awkisms úteis: Obtenha o número total de bytes exibidos no Apache ou no log do icecast:

cat access.log | awk '{ sum += $10 } END { print sum }'

Obtenha o número total de segundos conectados a partir de um log do icecast:

cat access.log | awk '{ sum += $13 } END { print sum }'
1
Synchro

O que costumo fazer na maioria das vezes é ler seções de um log com base no tempo, então escrevi o seguinte script usando sed para obter o período em que estou interessado, ele funciona em todos os arquivos de log que vim e também pode lidar com os logs arquivados.

 #!/bin/bash 
 # Este script deve retornar um conjunto de linhas entre 2 valores, o objetivo principal é pesquisar um arquivo de log entre 2 vezes 
 # Uso do script: logship.sh "start" "stop" file 
 
 # Se o arquivo contiver algum "/" no período, as 2 linhas a seguir adicionam o caractere de escape para que a pesquisa possa ser realizada por aqueles caracteres 
 start = $ (eco "$ 1" | sed 's/\ // \\\ // g') 
 stop = $ (eco "$ 2" | sed 's/\//\\\//g')[.____.}[.____.{zipped=$(echo "$ 3" | grep -c "gz $") #figura se o arquivo estiver zipado ou não 
 
 se ["$ compactado" == "1"]; # # Se o arquivo estiver compactado, passe-o pelo zcat antes de sed 
 zcat $ 3 | sed -n "/$start/,/$stop/p";[.____.{se
 sed -n"/$ start /,/$ stop/p "$ 3; #se não estiver compactado, basta executar sed 
 fi 
1
Chris

Recuperando esse thread antigo, depois de desistir do asql para grandes arquivos de log, procurei uma solução novamente, também em serverfault, descobri sobre o wtop aqui é uma ferramenta de código aberto, capaz de fazer monitoramento ao vivo ou processar logs e obter estatísticas (parte superior N), muito flexível e poderoso, o local oficial é aqui

0
aseques