logindex

Copyright (C) 1999 Jun Takahashi <junt@aihara.co.jp>

[戻る]

はじめに

logindexはhttpd等のログファイルの検索用インデックスを定期的に作成しておき、そのインデックスを参照することによって、必要とする行の取り出しを行うツールです。インデックスデータベースには、ログファイル中の該当行のファイルの先頭からのオフセットという形で登録されます。このような方法を採用することによって、高速に必要とするログを取り出すことができるようになります。
logindexは、インデックスを作成するlogindexと、問い合わせルーチンlogquery.c、検索プログラムlogrequestで構成されます。これらは、すべてCで記述されています。通常はログの取り出しにはlogrequestを用いればよいと思いますが、logquery.cを用いれば自分で作ったCのプログラムでインデックスを取り出すこともできます。


logindexの使い方

logindexの使い方は以下の通りです。

logindex -l logfile -p pattern [-g group] [-e pattern] -d indexfile [-i interval] [-r times]
-l logfileで、監視したいログファイルをフルパスで指定します。これは省略できません。また、これは複数指定することができます。複数指定した場合、指定されたファイルすべてを監視します。
-p patternで、監視したいログファイルから取り出すキーのパターンを正規表現で指定します。これは省略できません。
-g groupで、監視したいログファイルから取り出したキーパターンの正規表現の中のグループの番号を指定します。グループとは、正規表現の中で、( )で囲われた部分のことで、出現順に1〜番号が振られます。ここで指定されたグループ番号で取り出された文字列がインデックスデータベースにキーとして登録されます。省略した場合0が指定されたものと見なします。グループ番号が0というのは、-p patternで指定された正規表現でマッチした文字列全体になります。
-e patternで、インデックスデータベースへの登録を除外する行のパターンを正規表現で指定します。省略した場合すべての行が処理対象となります。
-d indexfileで、インデックスデータベースのファイル名を指定します。これは省略できません。
-i intervalで、ログファイルの監視間隔を秒単位で指定します。省略した場合0が指定されたと見なします。0の場合、定期的な監視は行わないので、最初にインデックスデータベースを構築した後、プログラムは終了します。
-r timesで、インデックスデータベースの再構築間隔を指定します。単位は、インデックスデータベースの更新回数です。省略した場合1000回になります。

httpdのログファイルを具体的な例として説明します。
多くのhttpdのログは以下のようにログを記録します。
foo.bar.com - - [01/Jan/1999:01:23:45 +0900] "GET / HTTP/1.0" 200 1024 "-" "Mozilla/4.6 [ja] (Win98; I)"
これを日付でインデックス化したい場合、-p patternで指定する正規表現を
\[.* \+0900\]
とします。この場合パターンにマッチしてキーとして取り出される部分は
[01/Jan/1999:01:23:45 +0900]
となります。
さて、このままだと検索は日付までで時間まで必要がないというような場合、無駄な文字まで登録されてしまい、検索にも時間がかかってしまいます。そこで、キーパターンを
\[(.*):[0-9][0-9]:[0-9][0-9]:[0-9][0-9] \+0900\]
とし、-g 1として、グループ番号を1とします。そうすると、キーとして取り出される部分は、キーパターンの1番目のグループ、つまりこの場合、(.*)にマッチする部分
01/Jan/1999
となり、必要十分なキーを登録することができます。


logrequestの使い方

logrequestの使い方は以下の通りです。

logrequest -p pattern -d index [-o output]
-p patternで、検索パターンを正規表現で指定します。インデックスデータベースに登録されているキーパターンが、ここで指定する検索パターンに合致する行が取り出されます。これは省略できません。
-d indexで、インデックスデータベースファイルを指定します。これは省略できません。
-o outputで、出力ファイルを指定します。省略した場合、標準出力に出力されます。

具体例として、上記のlogindexでhttpdの日付でインデックス化してあるインデックスデータベースから1999年1月のログを取り出す場合は以下のようにします。
logrequest -p 'Jan/1999' -d access_log.idx


logquery.cの使い方

logquery.cの使い方は以下の通りです。

#include <logquery.h>

query_t logquery(char *query_pattern, char *index_name);
query_patternで、検索文字列を指定します。logrequestの-p patternにあたります。
index_nameで、インデックスデータベースのファイル名を指定します。logrequestの-d indexにあたります。

戻り値はquery_t型で、これは以下のような構造体です。
typedef struct {
  int log_count;
  log_t *log;
} query_t;
また、log_t型は以下のような構造体です。
typedef struct {
  char name[256];
  int offset_count;
  z_off_t *offset;
  int offset_size;
} log_t;
戻り値の変数名をqueryとすると、query.log_countは監視しているファイルの数が格納されます。この値が0以下だった場合、検索は失敗です。ここでいう検索失敗とは、インデックスデータベースファイルの異常等による検索失敗を意味します。検索した結果、検索パターンに合致する行がなかった場合は含みません。query.log[]は監視しているファイルの数分確保されます。
query.log[i].nameはi番目の監視ファイルのファイル名が格納されます。
query.log[i].offset_countはi番目の監視ファイルのなかで、検索パターンに合致した行の数が格納されます。
query.log[i].offset[]はi番目の監視ファイルのなかで、検索パターンに合致した行のファイル中のオフセット位置が格納されます。このエリアはquery.log[i].offset_size個確保されていますが、有効なデータはquery.log[i].offset_count個です。

logquery()は戻り値のエリアを確保します。この確保されたエリアを解放するための関数がlogqueryfree()で、使い方は以下の通りです。
void logqueryfree(query_t query);


インデックスを作るときの注意点

インデックスデータベースは一つのキーに対して、それに該当する行のオフセットが複数で構成されますが、キーの取り出しパターンによっては、一つのキーに一つのオフセットというようになったり、逆に、一つのキーで非常に多くのオフセットになることもあります。前者の場合、柔軟な検索ができますが、検索に非常に時間がかかり、logindexを使うメリットがなくなってしまいます。後者の場合、あまり柔軟な検索ができないため、うまい絞り込みができなくなる可能性があります。
そのため、logindexを利用するときは必要にして十分な、ちょうど良いキーの取り出しパターンを選ぶことが重要です。

logindexはgdbmを使ってインデックスデータベースを管理していますが、これはデータのサイズが変わるような更新をしたとき、それまで使っていた領域は残して、新しい領域にデータを追加するという動作をするようです。また、データを削除した場合も、その領域は残されます。そのため、運用を続けていると、どんどんファイルサイズが大きくなっていってしまいます。ただし、当然そういった領域を解放し、データベースを再構築する機能も用意されていますが、自動的にやってくれるわけではありません。logindexでは-r timesオプションで指定される値によって、データベース再構築のタイミングを制御しています。
データベースの再構築には当然それなりの時間がかかりますから、頻繁に再構築を行っていてはデータベースの更新に時間がかかりすぎてしまいます。しかし、まったく再構築を行わないと無駄に巨大なファイルになってしまいます。再構築の適切なタイミングは、キー取り出しパターンと監視対象のログファイルの構成によって変化します。
例えば、前述のhttpdのログを日付でインデックス化する場合、ログは当然日付順に並んでいるので、一つのキーでの登録は連続して行われます。そのため、データベースファイルのサイズが爆発的に大きくなることはないので、あまり頻繁に再構築する必要はありません。ディスクの空き領域次第ですが、目安として、一日分のログの数毎に再構築するくらいが良いと思います。
また、httpdのログファイルのもう一つの例として、参照されたページによってインデックス化することを考えます。この場合、日付でのインデックス化と違って、一つのキーでの登録は連続して行われることはほとんどありません。また、ページによってバラツキはあると思いますが、一つのキーに登録されるオフセットの数は日付でのインデックス化の場合よりも多くなると考えられます。そのため、データベースファイルのサイズは短期間で爆発的に増加することが予想されるので、再構築の間隔も短めにした方がよいでしょう。


配布について

本プログラムはフリーソフトウェアであり、これによって生じたいかなる損害も作者は責任は負いかねます。特に、このソフトウェアはインデックスを作るときの注意点で述べているように、運用の仕方によっては、システムの資源をかなり消費します。よって、このソフトウェアはシステムの状態を把握したシステム管理者にのみ使って頂きたいと思います。そのため、現状では、このパッケージをこのサイトに置いて自由に配布することはぜず、特に要望のあった方のみ配布することにしますので、御了承下さい。
以上を御理解頂いた上で、このソフトウェアのパッケージに興味がある方は、junt@aihara.co.jpまでメールを下されば、追ってメールで配布致します。


logindexの構築

本プログラムはすべてCで記述されています。構築の詳細についてはMakefileを参照してください。
本プログラムはgdbmとregexを用いています。そのため、gdbmを別途インストールする必要があります。regexが標準で利用できないシステムの場合、これも別途インストールする必要があります。
また、zlibを利用してgzipで圧縮されたファイルのインデックスを作成することもできます。この場合、別途zlibをインストールし、Makefileのコンパイルオプション-DNOT_USE_ZLIBを削除してコンパイルしてください。


ウェブアクセスログへの応用

このプログラムをウェブログ解析ツールshow-log-httpdに応用することにより、高速なウェブアクセスログの表示が可能となります。


Copyright (C) 1999 Jun Takahashi