Zpracování log souborů z webového serveru

20. června 2007

O autorovi

Portrét

Jan Aubrecht
.NET vývojář a konzultant IS/IT
honza@intellisoft.cz

Honza se zabývá vývojem webových aplikací od roku 2000. Rád používá ASP.NET 2.0 a je přímo posedlý neustálým zlepšováním svých aplikací.

Ve volném čase je jeho vášní dobré jídlo a pití. Nejraději se baví přípravou středomořských specialit a báječnými víny z Francie.

Soubory ke stažení

Zdrojové kódy použité v článku a další související soubory si můžete stáhnout zde:

Další články

V krátkém článku se dozvíte, jak zpracovat log soubory z webového serveru, které jsou uloženy ve standardním formátu W3C. Předvedeme si, jak programově získat z log souboru všechna požadovaná data nebo jak spočítat jednoduché statistiky.

Jak zpracovat log soubory?

Možná jste někdy potřebovali získat data z log souborů, které vytváří webový nebo FTP server. V takovém případě jste mohli šáhnout třeba po utilitě Log Parser, která umožňuje provádět dotazy do logu pomocí jazyka SQL.

Co když ale potřebujeme zpracovat log soubor uvnitř vlastní .NET aplikace nebo ASP.NET stránky?

Na to už budeme potřebovat vlastní parser, který log soubor zpracuje a poskytne nám rozhraní pro pohodlnou práci s uloženými údaji.

Jeden takový parser jsme pro vás vytvořili a najdete ho včetně zdrojových kódů v příloze článku.

Jaké soubory jsou podporovány?

Náš jednoduchý parser umožňuje pracovat s log soubory, které jsou uloženy ve formátu navrženým organizací W3C. Pokud tedy používáte Microsoft IIS, tak můžete tento parser použít jak pro zpracování logů z web serveru, tak i pro logy z FTP a SMTP serveru.

Načítáme log soubor

Parser obsahuje dvě jednoduché třídy. První z nich je třída LogReader, která slouží pro čtení dat z log souboru. Druhá třída nazvaná LogRecord reprezentuje samostatný záznam v logu.

Použití je opravdu jednoduché. V konstruktoru třídy LogReader zadáme cestu k log souboru, který chceme zpracovat. Pak můžeme začít načítat jednotlivé záznamy pomocí metody ReadRecord.

Metoda ReadRecord nám vrátí instanci třídy LogRecord, která obsahuje aktuálně načtený záznam se všemi jeho údaji. Tyto údaje jsou pak ve třídě LogRecord reprezentovány samostatnými veřejnými vlastnostmi.

Použité vlastnosti jsou silně typové (strongly typed) a hodnoty z logu jsou do nich převedeny tak, aby nedošlo k žádné ztrátě údajů.

Příklad, jak načíst první záznam z log souboru, vypadá takto:

using (LogReader reader = new LogReader("C:\\ex070620.log"))
{
    LogRecord record = reader.ReadRecord();
 
    if (record != null)
        Console.WriteLine(record.ClientIPAddress);
}

Určitě vás bude zajímat, jak zpracovat celý soubor. I to není nic složitého. V případě, že třída LogReader dorazí na konec log souboru, tak metoda ReadRecord vrátí místo nového záznamu (LogRecord) pouze hodnotu null.

Můžeme tak celý soubor zpracovat pomocí jednoduchého cyklu:

using (LogReader reader = new LogReader("C:\\ex070620.log"))
{
    LogRecord record;
 
    while ((record = reader.ReadRecord()) != null)
    {
        Console.WriteLine(record.ClientIPAddress);
    }
}

Další příklady použití

Na závěr si ukážeme několik jednoduchých nápadů, co všechno je možné z log souborů zjistit.

Součet všech odeslaných a přijatých dat:

long received = 0;
long sent = 0;
 
using (LogReader reader = new LogReader("C:\\ex070620.log"))
{
    LogRecord record;
 
    while ((record = reader.ReadRecord()) != null)
    {
        if (record.BytesReceived.HasValue)
            received += record.BytesReceived.Value;
 
        if (record.BytesSent.HasValue)
            sent += record.BytesSent.Value;
    }
}
Console.WriteLine("Total received bytes: {0}", received);
Console.WriteLine("Total sent bytes: {0}", sent);

Přehled všech unikátních IP adres:

Dictionary<string, int> results = new Dictionary<string, int>();
 
using (LogReader reader = new LogReader("C:\\ex070620.log"))
{
    LogRecord record;
 
    while ((record = reader.ReadRecord()) != null)
    {
        string client = record.ClientIPAddress;
 
        if (results.ContainsKey(client))
            results[client] += 1;
        else
            results.Add(client, 1);
    }
}
foreach (KeyValuePair<string, int> item in results)
{
    Console.WriteLine("Client: {0}, Hits: {1}", item.Key, item.Value);
}

URL, ze kterých přichází návštěvníci webu:

Dictionary<string, int> results = new Dictionary<string, int>();
string websiteUrl = "http://www.intellisoft.cz";
 
using (LogReader reader = new LogReader("C:\\ex070620.log"))
{
    LogRecord record;
 
    while ((record = reader.ReadRecord()) != null)
    {
        string url = record.Referrer;
 
        if (url != null && !url.StartsWith(websiteUrl))
        {
            if (results.ContainsKey(url))
                results[url] += 1;
            else
                results.Add(url, 1);
        }
    }
}
foreach (KeyValuePair<string, int> item in results)
{
    Console.WriteLine("Referrer: {0}, Visits: {1}", item.Key, item.Value);
}

Dokumenty, které nebyly nalezeny (chyba 404):

Dictionary<string, int> results = new Dictionary<string, int>();
 
using (LogReader reader = new LogReader("C:\\ex070620.log"))
{
    LogRecord record;
 
    while ((record = reader.ReadRecord()) != null)
    {
        if (record.Status.Value == 404)
        {
            string url = record.UriStem;
 
            if (results.ContainsKey(url))
                results[url] += 1;
            else
                results.Add(url, 1);
        }
    }
}
foreach (KeyValuePair<string, int> item in results)
{
    Console.WriteLine("Document: {0}, Hits: {1}", item.Key, item.Value);
}

Komponentu Intellisoft W3C Log Parser a další příklady si můžete stáhnout zde: