Посетители, посетившие / стр. 1, а также / стр. 2

В моем файле журнала Apache other_vhosts_access.log выглядит так:

 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" 

Я бы хотел найти посетителей, которые посетили /page1.html и /somethingelse2.html , вот в примере: 12.34.56.78.

Если я использую:

 grep page1.html other_vhosts_access.log 

Я больше не могу фильтровать выход, потому что остальные строки не включают somethingelse2.html .

Как найти посетителей, посетивших одну конкретную страницу + другую?

Использование bash , grep и awk :

Вот как вы получаете все номера IP, сопоставляющиеся с файлом page1.html :

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

Для данных примера это будет выводить 12.34.56.78 .

Это можно использовать для получения всех записей журнала, содержащих этот IP-адрес:

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

Это использует результат awk команды в качестве шаблона и второй раз проверяет файл журнала для вывода всех строк, содержащих этот IP-адрес. Это возвращает первую и последнюю строку из примера.

Флаг -w и -F для grep используется, чтобы сообщить grep интерпретировать шаблон (IP-адрес) как фиксированную строку ( -F ) и только возвращать строки, содержащие эту строку, как целое слово ( -w ). Это означает, что 12.34.56.789 не будет соответствовать шаблону фиксированной строки 12.34.56.78 .

Из этого результата мы можем удалить строки, page1.html к page1.html с помощью

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

Теперь у вас есть все записи журнала, созданные посетителями на странице page1.html (но не включая страницу page1.html ).

Если вы хотите получить записи для определенной другой страницы, измените последний grep -vF 'page1.html' на grep -F 'otherpage.html' .


Я уверен, что там есть более надежный инструмент анализа и анализа журналов, но если есть, я не знаю о них (я не часто разбираюсь с журналом).

Как правило, это делается в awk, используя ассоциативные массивы, чтобы помнить, что уже было видно на входе. Мы используем разделитель полей awk для awk по умолчанию, отметим, что поле 2 является ip-адресом, а поле 8 является URL-адресом, например,

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

Это будет сравнивать поле url и когда оно соответствует первому url, он создает запись в массиве ipaddr для ip-адреса, чтобы сохранить значение 1. Когда он соответствует второму URL-адресу, он проверяет, была ли указана запись для того же ip-адреса, и если это так печатает. Чтобы не перепечатывать один и тот же ip-адрес, мы могли бы отметить его в другом массиве:

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

Если URL-адрес может иметь часть запроса (например, "/page1.html?id=77" ), вы можете использовать совпадения вместо сравнения, то есть $8~/^\/page1.html/ .

Если URL-адреса могут быть просмотрены в обратном порядке, вы можете использовать значение битовой маски, чтобы помнить, какой из них вы уже видели, например 1 для страницы 1 и 2 для somethingelse2, а затем дождаться, когда у вас есть значение 3. Битмаксы доступны только в awk через такие функции, как or и and . Таким образом, мы могли бы

 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 } }' 

Это устанавливает в блоке BEGIN один раз в начале сопоставление в ассоциативном массиве v для преобразования url в наше значение битовой маски (просто целое число). Когда любой URL-адрес сопоставлен, запоминаемое значение имеет соответствующее значение битмаски или-ed. Если оно теперь 3, мы печатаем адрес и устанавливаем его так, чтобы он не печатался снова.

Вы можете обнаружить, что формат other_vhosts_access.log более богачен, чем вам нужно, в этой задаче. Я рекомендую вам выделить несколько ваших любимых столбцов, например awk '{print $2, $8}' other_vhosts_access.log > small.log , а затем манипулировать small.log, который вы можете лучше смотреть.

Проблема объясняется на https://httpd.apache.org/docs/2.4/logs.html :

… обычно используемая форматная строка называется Комбинированным форматом журнала. Его можно использовать следующим образом. LogFormat "% h% l% u% t \"% r \ "%> s% b \"% { Referer } i \ "\"% {User-agent} i \ "" вместе

Это похоже на то, что вы используете. Вы цитировали example.com в своем (дезинфицированном) журнале, указав, что сайт, например example.com, имел HREF на вашем сайте, а браузер включал заголовок «Referer: http://www.example.com&#xBB; в их запросе GET.

Очень вероятно, что / page1 имеет HREFs / page2. Некоторые браузеры отправят заголовок refer1 страницы1 на запросы страницы2. Вы можете рассчитывать на это, и grep для 'page2. * Page1'. Или вы можете полагаться на исходный IP-адрес, как в принятом ответе. В этом случае вы, вероятно, захотите вычеркнуть другие отвлекающие столбцы, которые вызовут ложные совпадения, и используйте упрощенные small.log для ваших анализов.