У меня около 30 000 журналов доступа Apache, в некоторых из которых перечислены IP-адреса нескольких клиентов. Это происходит из-за того, что Apache регистрирует заголовок X-Forwarded-For вместо IP-адреса клиента. Причина этого в том, что мы недавно добавили haproxy перед веб-серверами.
В дальнейшем мы будем использовать rpaf чтобы Apache регистрировал только 1 IP-адрес, то есть входящего подключения к haproxy, поэтому это не будет постоянной проблемой.
Это подводит меня к собственному вопросу:
Как мне обработать существующие журналы с несколькими IP-адресами, чтобы извлечь только тот, который мне нужен. Я предполагаю, что мне понадобится sed или что-то подобное, но я больше люблю Windows, поэтому не уверен на 100%.
Правила следующие:
Пример 1, 1 IP
Ввод: 10.1.1.1 - - [29 января 2010 г .: 11: 00: 00] .... (остальная часть строки журнала)
Результат: 10.1.1.1 - - [29 / Янв / 2010: 11: 00: 00] .... (остальная часть строки журнала)
Пример 2, 2 IP
Вход: 10.1.1.1, 10.2.2.2 - - [29 / Янв / 2010: 11: 00: 00] .... (остальная часть строки журнала)
Вывод: 10.1.1.1 - - [29 января 2010: 11: 00: 00] .... (остальная часть строки журнала)
Пример 3, 3 IP
Ввод: 10.1.1.1, 10.2.2.2, 10.3.3.3 - - [29 / Янв / 2010: 11: 00: 00] .... (остальная часть строки журнала)
Вывод: 10.2.2.2 - - [29 января 2010: 11: 00: 00] .... (остальная часть строки журнала)
Этого можно добиться, выполнив эту команду sed в своих журналах:
sed -i "s/^\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+, \)*\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\), [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+ - -/\2 - -/"
Некоторые пояснения:
s/MATCH PATTERN/REPLACE PATTERN/
\2
который относится ко второй части матча в скобках.(
и )
, плюс: +
(что означает «хотя бы один раз») и буквальную точку: .
(иначе считается подстановочным знаком)-i
опция sed означает изменение файлов на месте. Убедитесь, что вы работаете с копиями!«Из-за этого мои глаза кровоточат почти так же, как от Perl, но это работает».
use strict;
use warnings;
use Regexp::Common qw /net/;
my $ip;
my $restOfLine;
my @ips;
while (<>) {
if (/- -.*/) {
$restOfLine = $&;
}
unless (@ips = /($RE{net}{IPv4})/g) {
print;
next;
}
if ($ips[1]) {
$ip = splice(@ips,-2,1);
} else {
$ip = $ips[0];
}
print "$ip " . $restOfLine . "\n";
}
Уменьшает кровотечение из глаз, но, может быть, это только я :-)