Apache httpdでリクエストURI毎にログの出力先を分ける

記事タイトルとURLをコピーする

最近ではNginx等のWEBサーバを利用するケースも増えていますがまだまだApache httpdを利用しているケースもあると思います。

今回はApache httpdを利用した環境で画像へのリクエストはログに残したくないや、 特定のディレクトリへのアクセスはログファイルを分けたいなどと行った要件が出てきた場合の設定方法についてご紹介します。

アクセスログの設定はCustomLogディレクティブ

ご存じかと思いますがアクセスログを出力させる場合CustomLogディレクティブについて振り返ります。 CustomLogディレクティブはログの出力先やフォーマットを指定します。

デフォルトの設定ではhttpd.confに以下のような設定が入っています。

CustomLog "logs/access_log" combined

CustomLogディレクティブはVirtualHostディレクティブの中でも設定でき、 以下のようなバーチャルホスト毎にアクセスログを分けるということは おそらくほとんどの人がやったことがあるのではないでしょうか。

<VirtualHost>
ServerAdmin webmaster@host.example.com
DocumentRoot /var/www/vhosts/host.example.com
ServerName host.example.com
ErrorLog logs/host.example.com-error_log
CustomLog logs/host.example.com-access_log combined
</VirtualHost>

そして今回のテーマである、リクエスト毎にログの出力先を変更する場合、 VirtualHostディレクティブ内にCustomLogディレクティブを複数書くことで実現します。

また、CustomLogは環境変数を引数に渡し出力させるログをコントロールすることができます。

リクエストの属性に基づいて環境変数を設定するSetEnvIfディレクティブ

画像や、特定のディレクトリへのアクセスがあった場合はログを記録しないやログファイルを 分けるといった条件分岐する場合にSetEnvIfディレクティブを利用することが可能です。

例えばfaviconへのアクセスがあった場合no_logという環境変数をセットしたい場合は以下のように書きます。

SetEnvIf Request_URI "favicon.ico$" no_log

また、testのディレクトリにアクセスがあった場合にtest_log環境変数をセットしたい場合は以下のように書きます。

SetEnvIf Request_URI "/test" test_log

CustomLog、SetEnvIfを利用してログの出力先を分ける

これまで説明してきたCustomLog、SetEnvIfの2つのディレクティブを利用して本題であるログの出力停止や リクエストURI毎にファイルを分ける設定を行います。

今回の例ではhost.example.comのドメインを利用したバーチャルホストに test01ディレクトリ、test02ディレクトリ、test03ディレクトリがあり、 このディレクトリへのアクセスはそれぞれ分けたいという要件があるとします。

また、favicon.icoへのアクセスはログに出力させない、ファイルを分けたログファイルは 分ける前のログファイルには出力させないという要件があったとします。

これらの要件を満たす設定は以下の通りになります。

<VirtualHost>
ServerAdmin webmaster@host.example.com
DocumentRoot /var/www/vhosts/host.example.com
ServerName host.example.com
ErrorLog logs/host.example.com-error_log
SetEnvIf Request_URI "favicon.ico$" no_log
SetEnvIf Request_URI "/test01" test01_log no_log
SetEnvIf Request_URI "/test02" test02_log no_log
SetEnvIf Request_URI "/test03" test03_log no_log
CustomLog logs/host.example.com-test01-access_log combined env=test01_log
CustomLog logs/host.example.com-test02-access_log combined env=test02_log
CustomLog logs/host.example.com-test03-access_log combined env=test03_log
CustomLog logs/host.example.com-access_log combined env=!no_log
</VirtualHost> 

SetEnvIfディレクティブの解説

SetEnvIfディレクティブの四行については前項の設定とほぼ変わりません。 環境変数については空白区切りで複数設定することが可能です。

今回なぜ2つの環境変数を設定しているのかは後ほど解説します。

SetEnvIf Request_URI "favicon.ico$" no_log
SetEnvIf Request_URI "/test01" test01_log no_log
SetEnvIf Request_URI "/test02" test02_log no_log
SetEnvIf Request_URI "/test03" test03_log no_log

また、以下のような書き方をすることも可能です。 この場合後勝ちでの上書きとならず複数の環境変数がセットされます。

SetEnvIf Request_URI "favicon.ico$" no_log
SetEnvIf Request_URI "/test01" test01_log 
SetEnvIf Request_URI "/test01" no_log
SetEnvIf Request_URI "/test02" test02_log
SetEnvIf Request_URI "/test02" no_log
SetEnvIf Request_URI "/test03" test03_log
SetEnvIf Request_URI "/test03" no_log

CustomLogディレクティブの解説

次のログの出力設定です。 環境変数を引数に設定できるCustomLogディレクティブを使います。 そこにログファイルのパス、ログフォーマットの名前、環境変数を指定し以下のようになっています。

CustomLog logs/host.example.com-test01-access_log combined env=test01_log
CustomLog logs/host.example.com-test02-access_log combined env=test02_log
CustomLog logs/host.example.com-test03-access_log combined env=test03_log
CustomLog logs/host.example.com-access_log combined env=!no_log

env={環境変数}だとその環境変数にマッチしたリクエストのログが出力されます。 最後のアクセスログの出力設定は特定のディレクトリ以外へのアクセスログを出力させる設定です。

no_logを全てのSetEnvIfで設定した意味

CustomLogは原則全てのアクセスログを指定したファイルに出力します。 そのため以下の設定だとどうなるでしょうか。

SetEnvIf Request_URI "favicon.ico$" no_log
SetEnvIf Request_URI "/test01" test01_log
SetEnvIf Request_URI "/test02" test02_log
SetEnvIf Request_URI "/test03" test03_log
CustomLog logs/host.example.com-test01-access_log combined env=test01_log
CustomLog logs/host.example.com-test02-access_log combined env=test02_log
CustomLog logs/host.example.com-test03-access_log combined env=test03_log
CustomLog logs/host.example.com-access_log combined env=!no_log

答えはtest01ディレクトリにアクセスがあった場合はhost.example.com-test01-access_log のファイルと host.example.com-access_log の両方に同じログが出力されてしまいます。

これでは分けた意味が無いので今回はno_logの環境変数をつけてログが重複して出力されないよう設定してます。

まとめ

SenenvIfを利用して環境変数をセットし、その環境変数に合わせてログの出力先を変えることが可能です。 多すぎるログファイルは分析する際大変なこともあるので必要に応じてうまく分割してログを有効活用したいですね。