Logo faq-o-matic.net
Logo faq-o-matic.net

Webserver-Logs mit Log Parser auswerten

von veröffentlicht am31. Januar 2011, 07:15 Uhr Kurzlink und Zitatlink einblenden
Kategorie Kategorie: Batch, Log Parser, Webserver   Translate with Google Translate Translate EN   Die angezeigte Seite drucken

Microsofts kostenloses Werkzeug Log Parser eignet sich hervorragend, um Protokolldateien (nahezu) jeder Art auszuwerten. Vor einiger Zeit haben wir hier eine Lösung vorgestellt, die Log Parser einsetzt, um Berichte über Windows-Eventlogs für Server zu erzeugen. Ursprünglich allerdings handelte es sich um ein Tool zur Auswertung von Webserver-Zugriffslogs – daher nutzen wir es seit einiger Zeit auch, um Statistiken über die Nutzung unseres Blogs zu erzeugen. Das ist sicher auch für andere interessant, daher hier ein paar Beispiele.

Bei uns läuft WordPress auf einem LAMP-System, also erhalten wir die Logs vom Apache-Server, die im NCSA-Logformat vorliegen. So kommen sie bei uns allerdings nicht an, sondern wir erhalten sie komprimiert im gz-Format. Zum Entpacken nutzen wir daher ein Batch-Kommando dieser Art (hier mit dem freien Dekomprimierer IZArc2Go, aber man kann auch 7zip oder sowas nehmen):

FOR %%I IN (C:\Statistik\Logs\*.gz) DO (
	echo Dekomprimiere: %%~nI
	C:\Tools\IZArc2Go.exe -eh C:\Statistik\Logs-Raw\ %%~fI
)

Diese Schleife nimmt sich alle gz-Dateien aus dem Ausgangsordner und entpackt sie in den Zielordner. Dort angekommen, sieht eine Logdatei in etwa so aus (hier natürlich anonymisiert):

123.45.67.89 - - [26/Dec/2010:00:00:29 +0100] "GET /2004/10/26/wieviel-ram-ist-sinnvoll-bei-terminal-servern/ HTTP/1.1" 200 10206 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
23.45.6.78 - - [26/Dec/2010:00:00:34 +0100] "GET /2007/06/08/welcher-name-ist-der-beste-fuer-eine-ad-domaene/ HTTP/1.1" 200 10194 "http://www.administrator.de/index.php?content=100062" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
123.98.76.54 - - [26/Dec/2010:00:00:35 +0100] "GET /wp-content/themes/faqomatic/style.css HTTP/1.1" 200 9943 "http://www.faq-o-matic.net/2007/06/08/welcher-name-ist-der-beste-fuer-eine-ad-domaene/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"

Artikel-Aufrufe filtern

Aufgrund des URL-Schemas unserer Seite haben die Aufrufe von Artikeln immer ein ganz spezielles Format: Zuerst kommt das Datum, mit Schrägstrichen getrennt, dann der Titel des Artikels und am Ende des URLs steht wieder ein Schrägstrich. Da wir unter anderem wissen wollen, welche Artikel wie oft aufgerufen werden, lassen wir Log Parser die folgende Abfrage ausführen:

/*

Log Parser: Aus Apache-Serverlogs die erfolgreichen Aufrufe

   von WordPress-Artikeln ausfiltern

   Voraussetzung: WordPress-Permalinks im Format /yyyy/mm/dd/titel/

*/

SELECT   DateTime

       — URI aus Request-Feld isolieren

       , EXTRACT_TOKEN(Request, 1, ‚ ‚) AS URI

INTO %OutputFile%

FROM %InputLog%

WHERE StatusCode=200 — nur erfolgreiche Aufrufe

AND SUBSTR(URI, SUB(STRLEN(URI),1), 1) = ‚/‘ — nur Pseudo-Verzeichnisse (in Permalinks gegeben)

AND SUBSTR(URI, 0, 12) LIKE ‚/____/__/__/‘ — nur Post-Permalinks (Datum am Anfang)

 

Das Feld DateTime findet Log Parser selbst. Um aus dem Request-String den URI herauszufiltern, nutzen wir die Funktion EXTRACT_TOKEN, die den Abschnitt bis zum ersten Leerzeichen extrahiert. Wir wollen aber nur Artikel-Abrufe, also filtern wir in der WHERE-Klausel auf den HTTP-Statuscode 200 und lassen uns nur solche URIs heben, bei denen am Ende ein Leerzeichen steht und die mit dem Muster Schrägstrich – vier Zeichen – Schrägstrich – zwei Zeichen – Schrägstrich – zwei Zeichen – Schrägstrich beginnen.

Zur INTO- und zur FROM-Klausel folgt weiter unten mehr.

Wo kommen die Leser her?

Jeder Webserver-Aufruf eines Browsers (naja, fast jeder) gibt an, welche Seite der Anwender vorher besucht hat. Das ist gar nicht uninteressant, denn so entsteht ein Bild, wie unser Blog in die Community eingebunden ist. Daher werten wir auch den so genannten “Referer” aus (natürlich anonym).

/*

Log Parser: Aus Apache-Serverlogs die Referer-Hosts für

   erfolgreiche Aufrufe ausfiltern

*/

SELECT    DateTime

        , EXTRACT_TOKEN(Referer, 2, ‚/‘) AS Host — Host extrahieren

INTO %OutputFile%

FROM %InputLog%

WHERE StatusCode=200 — nur erfolgreiche Aufrufe

AND Host IS NOT NULL — nur gültige Referer

AND INDEX_OF(Host, ‚faq-o-matic.net‘) IS NULL — keine Eigenverweise

 

Das Feld Referer ist Log Parser wieder bekannt, aber daraus benötigen wir nur den Host, nicht den ganzen URI, also kommt wieder EXTRACT_TOKEN zum Einsatz. Dabei interessieren uns interne Verweise nicht, also filtern wir unseren eigenen Servernamen wieder aus.

Externe Suchausdrücke

Die meisten Suchmaschinen lassen die Suchausdrücke, die Anwender verwendet haben, in ihrem Referer-URL erkennen. Das machen wir uns zunutze und werten die Ausdrücke aus, mit denen Leser zu uns kommen. Das Prinzip ist einfach: Wir identifizieren in den Aufrufen die Suchmaschinen über die Referer und schneiden aus der Angabe die Suchstrings heraus. Das folgende Beispiel findet die Suchbegriffe für Google und Bing. Praktischerweise verwenden beide ein sehr ähnliches Parameter-Format.

/*

Log Parser: Aus Apache-Serverlogs die Suchausdrücke

   von Google und Bing ausfiltern

*/

SELECT    DateTime

        , EXTRACT_TOKEN(Referer, 2, ‚/‘) AS Host — Host extrahieren

        — Suchausdruck extrahieren und lesbar machen

        , REPLACE_STR(URLUNESCAPE(EXTRACT_TOKEN(EXTRACT_TOKEN(Referer, 1, ‚?q=‘), 0, ‚&‘)), ‚+‘, ‚ ‚) AS Suchausdruck

INTO %OutputFile%

FROM %InputLog%

WHERE

(Host LIKE ‚%.google.%‘

OR Host LIKE ‚%.bing.%‘)

AND INDEX_OF(Referer, ‚?q=‘) IS NOT NULL — nur Referer von externen Suchabfragen

 

Die gesuchten Ausdrücke finden sich nämlich bei Google und Bing im URI nach der Angabe ?q=. Die obige SELECT-Klausel ist zwar ganz schön unübersichtlich, weil sie gleich vier Log-Parser-Funktionen ineinander verschachtelt, aber vom Prinzip her einfach: Erst schneidet sie mit EXTRACT_TOKEN den Teil nach dem ?q= aus, dann wirft sie alles nach dem folgenden & weg (da kommen nämlich Angaben, die nicht mehr zu den Suchbegriffen gehören). Danach konvertiert sie die HTTP-Codes für Umlaute mit URLUNESCAPE in lesbare Zeichen und ersetzt am Ende mit REPLACE_STR alle + durch Leerzeichen.

Fehler finden

Schließlich interessieren uns auch die Fehler, die Leser auf unserer Seite erzeugen. Die meisten davon sind nicht richtig spannend, aber einige lassen Rückschlüsse auf Angriffe zu. So ist es manchmal beeindruckend zu sehen, wie Clients (wahrscheinlich durch Botnetze ferngesteuert) bekannte angreifbare Dateien auf unserem Server suchen oder wild irgendwelche SQL-Injection-Angriffe ausprobieren. Bislang glücklicherweise erfolglos.

Daneben dienen uns die Fehler aber auch zum Optimieren unserer Seite. So haben wir ja bereits mehrfach die Technik gewechselt, und dadurch haben sich viele Links geändert. Durch die Fehler-Auswertung haben wir Hinweise, für welche veralteten Links sich Umleitungs-Maßnahmen besonders lohnen würden.

/*

Log Parser: Aus Apache-Serverlogs die fehlerhaften Aufrufe

   mit Errorcode ab 400 ausfiltern

*/

SELECT   DateTime

       , Request

       , StatusCode

INTO %OutputFile%

FROM %InputLog%

WHERE StatusCode>=400 — nur fehlgeschlagene Aufrufe

AND INDEX_OF(Request, ‚/favicon.ico‘) IS NULL — ohne Favicon-Suchen

AND INDEX_OF(Request, ‚/blogs/MainFeed.aspx ‚) IS NULL — ohne veraltete Feed-Abonnements

AND INDEX_OF(Request, ‚/index2.php?option=com_rss&feed=RSS2.0&no_html=1 ‚) IS NULL — ohne veraltete Feed-Abonnements

 

Automatisch auswerten

Wie die meisten Webserver erzeugt auch unser Apache für jeden Tag eine Logdatei. Damit Log Parser all diese Dateien automatisch auswertet, lassen wir alle 14 Tage einen Batch über die angesammelten Dateien laufen, der für jede Datei einige Abfragen ausführt. Wir schreiben die Ergebnisse dann in eine kleine SQL-Datenbank (das macht Log Parser selbst) und löschen die Ausgangsdaten datenschutzkonform.

So sieht unser Batch prinzipiell aus:

@echo off
REM --- Ordner
SET LogsRawFolder="C:\Statistik\logs-raw"
SET LogParserSQLFolder="C:\Statistik"
REM --- SQL-Klausel für Log Parser
SET LogParserOutputClause=-o:SQL -server:.\SQLEXPRESS -database:fomStats -createTable:ON
REM --- Pfade zu den Programmen
SET LogParserCmd="C:\Program Files\Log Parser 2.2\LogParser.exe"

REM Logdateien auswerten
FOR %%I IN (%LogsRawFolder%\*.*) DO (
	ECHO Werte aus: %%~nI
	REM Artikelaufrufe
	%LogParserCmd% file:%LogParserSQLFolder%\acclog-Artikel.sql?InputLog="%%~fI"+OutputFile="Artikel" -i:NCSA %LogParserOutputClause% -q
	REM Referer-Domains
	%LogParserCmd% file:%LogParserSQLFolder%\acclog-RefererDomains.sql?InputLog="%%~fI"+OutputFile="RefererDomains" -i:NCSA %LogParserOutputClause% -q
	REM Externe Suche
	%LogParserCmd% file:%LogParserSQLFolder%\acclog-ExterneSuche.sql?InputLog="%%~fI"+OutputFile="ExterneSuche" -i:NCSA %LogParserOutputClause% -q
	REM Angriffe und Fehler
	%LogParserCmd% file:%LogParserSQLFolder%\acclog-Errors.sql?InputLog="%%~fI"+OutputFile="Errors" -i:NCSA %LogParserOutputClause% -q
)

ECHO Log-Verarbeitung beendet.

Der eigentliche Witz liegt in den Log-Parser-Aufrufen. Jede der oben gezeigten SQL-Abfragen liegt als Datei vor. Diese übergeben wir an Log Parser (mit dem Parameter -file). Da in jeder der SQL-Dateien Platzhalter für die FROM– und INTO-Klauseln stehen (schließlich ändern sich ja die Dateinamen der Logdateien bei jedem Aufruf), übergeben wir in jedem Durchlauf der Batch-Schleife den Namen der aktuellen Logdatei sowie den Namen der SQL-Tabelle, in der die erhaltenen Daten landen sollen. Dafür zuständig ist die Angabe ?InputLog="%%~fI"+OutputFile="Artikel" in dem Aufruf: Das Fragezeichen leitet die Parameter-Übergabe ein, die dem Parameter InputLog den Namen der gerade bearbeiteten Datei (aus der FOR-Schleife im Batch) sowie dem Parameter OutputFile den Namen der SQL-Tabelle Artikel übergibt.

Hinter dieser Angabe folgen dann noch die Identifikation des Eingabe-Logformats (-i:NCSA), damit Log Parser auch weiß, was für Daten er denn da bekommt, sowie die nötigen Angaben zur SQL-Datenbankverbindung, die wir der Einfachheit halber am Anfang der Batchdatei in der Variablen %LogParserOutputClause% hinterlegt haben.

Log Parser kann’s auch einfacher

Die hier gezeigten Beispiele sind schon starker Tobak und wenden sich eher an Fortgeschrittene. Es ist aber wohl sichtbar, wie flexibel Log Parser ist. Natürlich kann er auch einige einfachere Fragen beantworten – aber auch noch viel komplexere.

© 2005-2019 bei faq-o-matic.net. Alle Rechte an den Texten liegen bei deren Autorinnen und Autoren.

Jede Wiederveröffentlichung der Texte oder von Auszügen daraus - egal ob kommerziell oder nicht - bedarf der ausdrücklichen Genehmigung durch die jeweiligen Urheberinnen oder Urheber.

Das Impressum findet sich unter: http://www.faq-o-matic.net/impressum/

Danke, dass du faq-o-matic.net nutzt. Du hast ein einfaches Blog sehr glücklich gemacht!