Visitantes que visitaram / page1 e também / page2

1

No meu arquivo de log do Apache, other_vhosts_access.log , tem esta aparência:

www.example.com:80 12.34.56.78 - - [01/Aug/2017:00:42:18 +0200] "GET /page1.html HTTP/1.1" 200 1542 " "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
www.example.com:80 99.99.99.99 - - [02/Aug/2017:06:19:44 +0200] "GET /test.jpg HTTP/1.1" 200 90749 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
www.anotherwebsite.com:80 11.11.11.11 - - [04/Aug/2017:09:39:01 +0200] "GET /test.jpg HTTP/1.1" 200 90749 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"

...
www.example.com:80 12.34.56.78 - - [23/Aug/2017:01:12:11 +0200] "GET /somethingelse2.html HTTP/1.1" 200 21161 "http://www.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"

Gostaria de encontrar visitantes que visitaram /page1.html e /somethingelse2.html , aqui no exemplo: 12.34.56.78.

Se eu usar:

grep page1.html other_vhosts_access.log

Não consigo mais filtrar a saída, porque as linhas restantes não incluem somethingelse2.html .

Como encontrar visitantes que visitaram uma página específica + outra?

    
por Basj 04.09.2017 / 21:59

3 respostas

1

Usando bash , grep e awk :

Assim você obtém todos os números IP correlacionados com o arquivo page1.html :

awk '/page1\.html/ { print $2 }' log

Para os dados de exemplo, isso gerará 12.34.56.78 .

Isso pode ser usado para obter todas as entradas de log que contêm esse endereço IP:

grep -wF -f <( awk '/page1\.html/ { print $2 }' log ) log

Isso usa o resultado do comando awk como um padrão e examina o arquivo de registro uma segunda vez para gerar todas as linhas que contêm esse IP. Isso retorna a primeira e a última linha do exemplo.

O sinal -w e -F para grep é usado para informar grep para interpretar o padrão (endereço IP) como uma string fixa ( -F ) e somente retornar linhas que contenham essa cadeia como uma palavra inteira ( -w ). Isso significa que 12.34.56.789 não será correspondido pelo padrão de string fixo 12.34.56.78 .

A partir desse resultado, podemos remover as linhas que representam page1.html com

grep -wF -f <( awk '/page1\.html/ { print $2 }' log ) log | grep -vF 'page1.html'

Agora você tem todas as entradas de log produzidas pelos visitantes na página page1.html (mas não incluindo a própria página page1.html ).

Se você deseja obter as entradas para uma outra página particular , altere a última grep -vF 'page1.html' para grep -F 'otherpage.html' .

Tenho certeza de que existe uma ferramenta de análise e análise de logs mais robusta, mas, se houver, não sei sobre eles (não faço a análise de logs com muita frequência).

    
por 04.09.2017 / 22:27
1

Normalmente, isso é feito no awk usando matrizes associativas para lembrar o que já foi visto na entrada. Usando o separador de campos whitespace default do awk, notamos que o campo 2 é o endereço IP e o campo 8 é o URL, por exemplo,

awk '$8=="/page1.html"          { ipaddr[$2] = 1; next }
     $8=="/somethingelse2.html" { if(ipaddr[$2]==1)print $2 }'

Isto irá comparar o campo url e quando ele corresponder ao primeiro url, ele cria uma entrada no array ipaddr para o endereço IP, para manter o valor 1. Quando ele corresponde ao segundo url, ele verifica se definimos a entrada para o mesmo endereço IP, e se assim for imprime. Para evitar a reimpressão do mesmo endereço IP, podemos anotar em outro array:

awk '$8=="/page1.html"          { ipaddr[$2] = 1; next }
     $8=="/somethingelse2.html" { if(ipaddr[$2]==1 && !done[$2]){print $2; done[$2]=1 } }'

Se o URL puder ter uma parte de consulta (por exemplo, "/page1.html?id=77" ), você poderá usar correspondências em vez de comparações, ou seja, $8~/^\/page1.html/ .

Se os URLs podem ser visitados em ordem inversa, você pode usar um valor de máscara de bits para lembrar qual deles já viu, por exemplo, 1 para página1 e 2 para algoelse2 e, em seguida, aguarde até ter o valor 3. Bitmasks estão disponíveis no awk apenas através de funções como or e and . Então podemos ter

awk '
BEGIN { v["/page1.html"] = 1
        v["/somethingelse2.html"] = 2
}
$8=="/page1.html" || $8=="/somethingelse2.html"  {
  ipaddr[$2] = or(ipaddr[$2], v[$8])
  if(ipaddr[$2]==3){ print $2; ipaddr[$2] = 4 }
}'

Isso configura, no bloco BEGIN feito uma vez no início, um mapeamento no array associativo v para converter o url em nosso valor de bitmask (apenas um inteiro). Quando um url é correspondido, o valor lembrado tem o valor de máscara de bits apropriado. Se ele for agora 3, imprimiremos o endereço e o definiremos para que não seja impresso novamente.

    
por 05.09.2017 / 09:33
0

Você pode achar que o formato de other_vhosts_access.log é mais rico do que você gosta, nesta tarefa. Eu recomendo que você escolha algumas de suas colunas favoritas, por exemplo awk '{print $2, $8}' other_vhosts_access.log > small.log e, em seguida, manipule small.log, que você pode ver mais convenientemente.

O problema é explicado no link :

... commonly used format string is called the Combined Log Format. It can be used as follows. LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined

Isso parece ser o que você está usando. Você citou example.com em seu log (higienizado), indicando que um site como example.com tinha um HREF em seu site e um navegador incluiu um cabeçalho "Referer: www.example.com" em sua solicitação GET.

Parece muito provável que / page1 tenha HREFs para / page2. Alguns navegadores enviarão um cabeçalho de referência page1 em solicitações page2. Você pode escolher contar com isso e grep para 'page2. * Page1'. Ou você pode escolher confiar no IP de origem como na resposta aceita. Nesse caso, você provavelmente vai querer remover outras colunas que causam falsas correspondências e usar um small.log simplificado para suas análises.

    
por 05.09.2017 / 04:35