31.16.4.127 - - [15/Jul/2015:12:27:34 +0200] "GET /path/script.cgi?a=b HTTP/1.1" 302 583 "http://host.domain/page" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.1.0"
Der Aufbau der access.log-Datei, die ein Apache HTTP-Server per
Default schreibt, ist in mehrfacher Hinsicht suboptimal:
-
Information ist unpraktisch formatiert: Der
Request-Zeitpunkt wird als [15/Jul/2015:12:27:34 +0200] (Formatelement
%t) aufgezeichnet. Ein ISO-8601-ähnlicher Aufbau à la
2015-07-15 12:27:34 wäre besser lesbar und verarbeitbar. Zudem
wird die Zeitzone im Normalfall nicht benötigt (da der Server ja
nur in einer Zeitzone läuft, die bekannt sein sollte).
-
Information ist zusammengesetzt, die besser getrennt sein sollte:
Der Request wird als eine Zeichenkette "GET
/path/script.cgi?a=b HTTP/1.1" (Formatelement %r)
aufgezeichnet. Darin sind vier Teilinformationen enthalten:
-
die Request-Methode (GET),
-
der URL-Pfad (/path/script.cgi),
-
der (optionale) Query-String (?a=b),
-
das Request-Protokoll (HTTP/1.1).
Eine Zerlegung ist nicht ganz einfach, da der Query-String optional ist.
Besser wäre es, die Information in getrennten Feldern abzulegen
(URL-Pfad und Query-String können zusammengelegt werden).
-
Interessante Information fehlt: Z.B. fehlt die Ausführungsdauer
des Requests, die insbesondere bei der Performance-Optimierung
von dynmisch generierten Inhalten hilfreich ist, sowie Hostname und
Port, an die der Request gegangen ist, was bei einem
VirtualHost-Setup von Nutzen sein kann. Auch der Content-Type der
Response kann interessant sein, um Logeinträge danach
filtern zu können.
-
Zeilen lassen sich schlecht in ihre Teilinformationen
zerlegen: Eine einfache Trennung auf Whitespace geht nicht, da
manche Felder Whitespace enthalten. Solche Felder sind in doppelte
Anführungsstriche eingefasst. Aber nicht alle. Der Aufruf-Zeitpunkt
ist in eckige Klammern eingefasst (s.o.). Fehlende Werte werden
durch einen Bindstrich (-) dargestellt. Aber auch nicht immer.
Für den Query-String (Formatelement %q) gilt dies nicht.
Aufgrund dieser Ungereimtheiten definiert man sich am besten ein
eigenes Logfile-Format. Zum Glück ist dies mit der Apache-Direktive
LogFormat leicht möglich. Ich verwende folgende Definition, mit
einem senkrechten Strich als eindeutigem Feldtrenner:
LogFormat "%{%Y-%m-%d %H:%M:%S}t|%h|%>s|%L|%D|%I|%O|%{Content-Type}o|
%m|%v|%p|%U%q|%H|%{Referer}i|%{User-Agent}i" NAME
Verwendete Formatelemente (die mit + gekennzeichneten Informationen
kommen im ursprünglichen Format nicht vor):
%{%Y-%m-%d %H:%M:%S}t Request-Zeitpunkt
%h .................. Client-IP oder -Name
%>s ................. finaler HTTP Status (200, ...)
%L .................. + error.log wurde geschrieben
%D .................. + Ausführungsdauer in Mikrosekunden
%I .................. + Bytes empfangen
%O .................. Bytes gesendet
%{Content-Type}o .... + Content-Type Header der Response
%m .................. Request-Methode (GET, POST, ...)
%v .................. + Hostname
%p .................. + Port
%U .................. URL-Pfad
%q .................. Query-String
%H .................. Request-Protokoll (HTTP/1.0, ...)
%{Referer}i ......... Referer Header des Requests
%{User-Agent}i ...... User-Agent Header des Requests
NAME ................ Name es Log-Formats
Ein weiteres interessantes Formatelement ist
%{COOKIE}C .......... + Wert des Cookie COOKIE
das in Anwendungen, die Cookies nutzen, nützlich sein kann. Ich füge
es bei Bedarf am Ende hinzu.
Links:
2015-07-15 12:27:34|31.16.4.127|302|-|7273|400|583|text/html|GET|myhost.mydomain|80|/path/script.cgi?a=b|HTTP/1.1|http://host.domain/page|Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.1.0