PHP / regex для анализа журнала ошибок NGINX

Запись ошибки выглядит так:

2011/06/10 13:30:10 [error] 23263#0: *1 directory index of "/var/www/ssl/" is forbidden, client: 86.186.86.232, server: hotelpublisher.com, request: "GET / HTTP/1.1", host: "hotelpublisher.com" 

Мне нужно разобрать:

 date/time error type error message client server request host 

Первый бит (дата синтаксического анализа) легко используется с помощью substr . Хотя мой REGEX не слишком хорош, и я надеюсь услышать лучшее решение. Я просто взрываю , не буду работать, я думаю, поскольку ошибка может также содержать запятую.

Каков наиболее эффективный способ сделать это?

Как насчет:

 $str = '2011/06/10 13:30:10 [error] 23263#0: *1 directory index of "/var/www/ssl/" is forbidden, client: 86.186.86.232, server: hotelpublisher.com, request: "GET / HTTP/1.1", host: "hotelpublisher.com"'; preg_match('~^(?P<datetime>[\d+/ :]+) \[(?P<errortype>.+)\] .*?: (?P<errormessage>.+), client: (?P<client>.+), server: (?P<server>.+), request: (?P<request>.+), host: (?P<host>.+)$~', $str, $matches); print_r($matches); 

вывод:

 Array ( [0] => 2011/06/10 13:30:10 [error] 23263#0: *1 directory index of "/var/www/ssl/" is forbidden, client: 86.186.86.232, server: hotelpublisher.com, request: "GET / HTTP/1.1", host: "hotelpublisher.com" [datetime] => 2011/06/10 13:30:10 [1] => 2011/06/10 13:30:10 [errortype] => error [2] => error [errormessage] => *1 directory index of "/var/www/ssl/" is forbidden [3] => *1 directory index of "/var/www/ssl/" is forbidden [client] => 86.186.86.232 [4] => 86.186.86.232 [server] => hotelpublisher.com [5] => hotelpublisher.com [request] => "GET / HTTP/1.1" [6] => "GET / HTTP/1.1" [host] => "hotelpublisher.com" [7] => "hotelpublisher.com" ) 

Вот как я это сделал.

 $error = array(); $error['date'] = strtotime(substr($line, 0, 19)); $line = substr($line, 20); $error_str = explode(': ', strstr($line, ', client:', TRUE), 2); $error['message'] = $error_str[1]; preg_match("|\[([az]+)\] (\d+)#(\d+)|", $error_str[0], $matches); $error['error_type'] = $matches[1]; $args_str = explode(', ', substr(strstr($line, ', client:'), 2)); $args = array(); foreach($args_str as $a) { $name_value = explode(': ', $a, 2); $args[$name_value[0]] = trim($name_value[1], '"'); } $error = array_merge($error, $args); die(var_dump( $error )); 

Что будет производить:

 array(7) { ["date"]=> int(1307709010) ["message"]=> string(50) "*1 directory index of "/var/www/ssl/" is forbidden" ["error_type"]=> string(5) "error" ["client"]=> string(13) "86.186.86.232" ["server"]=> string(18) "hotelpublisher.com" ["request"]=> string(14) "GET / HTTP/1.1" ["host"]=> string(18) "hotelpublisher.com" } 

Просто хочу увидеть несколько голосов, чтобы узнать, какой из них является предпочтительным вариантом производительности / надежности.

Попробуйте этот код:

 $str = '2011/06/10 13:30:10 [error] 23263#0: *1 directory index of "/var/www/ssl/" is forbidden, client: 86.186.86.232, server: hotelpublisher.com, request: "GET / HTTP/1.1", host: "hotelpublisher.com"'; preg_match('~^(\d{4}/\d{2}/\d{2}\s\d{2}:\d{2}:\d{2})\s\[([^]]*)\]\s[^:]*:\s(.*?)\sclient:\s([^,]*),\sserver:\s([^,]*),\srequest:\s"([^"]*)",\shost:\s"([^"]*)"~', $str, $m ); list($line, $dateTime, $type, $msg, $client, $server, $request, $host ) = $m; var_dump($dateTime); var_dump($type); var_dump($msg); var_dump($client); var_dump($server); var_dump($request); var_dump($host); 

ВЫВОД

 string(19) "2011/06/10 13:30:10" string(5) "error" string(60) "*1 directory index of "/var/www/ssl/" is forbidden," string(13) "86.186.86.232" string(18) "hotelpublisher.com" string(14) "GET / HTTP/1.1" string(18) "hotelpublisher.com" 

Если у вас нет доступа к форматированию файла журнала, это будет делать:

 $regex = '~(\d{4}/\d{2}/\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.*?) client: (\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}), server: (.*?), request: "(.*?)", host: "(.*?)"~'; preg_match($regex, $line, $matches); list($all,$date,$time,$type,$message,$client,$server,$request,$host) = $matches; 

Если у вас есть доступ к тому, как форматируется журнал, поместите сообщение в конец, а не в середину, то вы можете сделать:

 $log_arr = explode(', ', $line, 7); list($date,$time,$type,$client,$server,$request,$host,$message) = $matches; 

Секрет в том, что explode принимает необязательный третий аргумент, ограничивая количество разделяемых элементов. Поэтому, установив его в 8 , оставшаяся часть строки будет сохранена как последний элемент в возвращаемом массиве. См. Руководство для получения дополнительной информации об этом.

Проверьте Nginx Error Log Reader ; читатель / парсер php для файла журнала ошибок Nginx. скрипт способен рекурсивно считывать журналы ошибок и отображать их в удобной для пользователя таблице. Конфигурация сценария включает в себя количество байтов для чтения на страницу и позволяет разбивать страницы на журнал ошибок.