読者です 読者をやめる 読者になる 読者になる

CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: mod_wsgi のログを rsyslog と logrotate でローテーションする

今回は mod_wsgi で動作させた WSGI アプリケーションのログを syslog で飛ばして、それを rsyslog で受信して logrotate でローテーションさせてみる。 尚、Apache httpd 本体のログを syslog で飛ばす方法は以下を参照のこと。

blog.amedama.jp

検証用の環境には CentOS7 を使った。

$ cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)
$ uname -r
3.10.0-229.11.1.el7.x86_64

必要なパッケージをインストールする

mod_wsgi など必要なパッケージをインストールする。 rsyslog と logrotate は最初から入っていると思う。

$ sudo yum -y install mod_wsgi rsyslog logrotate

WSGI アプリケーションを用意する

次に WSGI に対応したアプリケーションを用意する。 mod_wsgi の場合、application という名前のシンボルを自動的に読み込むようになっている。 ログの設定は設定ファイルから読み込むようにした。

$ cat << EOF | sudo tee /var/www/cgi-bin/myapp.wsgi > /dev/null
# -*- coding: utf-8 -*-

import os
import logging
from logging import config


logging.config.fileConfig(
    '/var/www/cgi-bin/logging.conf',
    disable_existing_loggers=False,
)
LOG = logging.getLogger(__name__)

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    LOG.info('Hello, World!')
    return ['Hello, World!\n']

EOF

WSGI アプリケーションを動作させるために mod_wsgi の設定ファイルを用意する。 先ほど作成した WSGI アプリケーションの場所を指定することになる。 また、動作させる場合はデーモンモードにすると良い。

$ cat << EOF | sudo tee /etc/httpd/conf.d/wsgi.conf > /dev/null
WSGISocketPrefix /var/run/wsgi

WSGIDaemonProcess myapp-process
WSGIScriptAlias /myapp /var/www/cgi-bin/myapp.wsgi
<Location /myapp>
WSGIProcessGroup myapp-process
</Location>
EOF

mod_wsgi の動作モードについては以下の記事に書いた。

blog.amedama.jp

WSGI アプリケーションが参照する、ロギングの設定ファイルを用意する。 ここで syslog でログを飛ばすように設定している。 ファシリティには local2 (SysLogHandler.LOG_LOCAL2) を使った。

$ cat << EOF | sudo tee /var/www/cgi-bin/logging.conf > /dev/null
[loggers]
keys=root

[handlers]
keys=syslogHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=syslogHandler

[handler_syslogHandler]
class=logging.handlers.SysLogHandler
level=DEBUG
formatter=simpleFormatter
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_LOCAL2)

[formatter_simpleFormatter]
format=%(asctime)s - %(process)d - %(threadName)s - %(name)s - %(levelname)s - %(message)s @ %(pathname)s:%(lineno)d
EOF

ロギングの設定ファイルの詳細については以下を参照する。

16.6. logging — Python 用ロギング機能 — Python 3.5.2 ドキュメント

rsyslog を設定する

今度は syslog を受ける側の rsyslog を設定する。 まずは、syslog が UDP で転送されてくるので、それを受信できるようにする。

$ sudo sed -i.back -e "
  s:^#\(\$ModLoad imudp\)$:\1:
  s:^#\(\$UDPServerRun 514\)$:\1:
" /etc/rsyslog.conf

ファシリティ local2 のログを保存する先を指定する。

$ cat << EOF | sudo tee /etc/rsyslog.d/mod_wsgi.conf > /dev/null
local2.* /var/log/mod_wsgi/mod_wsgi.log
EOF

logrotate を設定する

rsyslog で保存したログを logrotate でローテーションする設定を用意する。

$ cat << EOF | sudo tee /etc/logrotate.d/mod_wsgi > /dev/null
/var/log/mod_wsgi/mod_wsgi.log {
    dateext
    hourly
    missingok
    rotate 3
    notifempty
    nocompress
    sharedscripts
    delaycompress
    postrotate
        /bin/kill -HUP \`cat /var/run/syslogd.pid 2> /dev/null\` 2> /dev/null || true
        /bin/kill -HUP \`cat /var/run/rsyslogd.pid 2> /dev/null\` 2> /dev/null || true
    endscript
}
EOF

動作を確認する

以上で設定がおわったので rsyslog と httpd と (再) 起動する。

$ sudo systemctl restart rsyslog
$ sudo systemctl start httpd

wget で WSGI アプリケーションにアクセスしてみる。

$ wget -qO - http://localhost/myapp
Hello, World!

すると、ログファイルが作られたことが確認できる。

$ sudo cat /var/log/mod_wsgi/mod_wsgi.log
Sep 12 23:49:16 2015-09-12 23: 49:16,399 - 4227 - MainThread - _mod_wsgi_18cb3436d24acb6e50a4d2521dd7445a - INFO - Hello, World! @ /var/www/cgi-bin/myapp.wsgi:16

動作確認のために、できたログファイルを強制的にローテーションさせてみよう。

$ sudo logrotate -fv /etc/logrotate.d/mod_wsgi
reading config file /etc/logrotate.d/mod_wsgi

Handling 1 logs

rotating pattern: /var/log/mod_wsgi/mod_wsgi.log  forced from command line (3 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/mod_wsgi/mod_wsgi.log
  log needs rotating
rotating log /var/log/mod_wsgi/mod_wsgi.log, log->rotateCount is 3
dateext suffix '-2015091223'
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
renaming /var/log/mod_wsgi/mod_wsgi.log to /var/log/mod_wsgi/mod_wsgi.log-2015091223
running postrotate script

みるとちゃんとログファイルがローテーションされている。

$ sudo ls /var/log/mod_wsgi
mod_wsgi.log-2015091223

もちろん、再度アクセスすると新しいログファイルの方に書き込みが行われる。

$ wget -qO - http://localhost/myapp
Hello, World!
$ sudo ls /var/log/mod_wsgi
mod_wsgi.log  mod_wsgi.log-2015091223

めでたしめでたし。

まとめ

今回は mod_wsgi のログを rsyslog に飛ばして logrotate でローテーションするところを確認してみた。 尚、今回使った Python のロギング設定ファイルは、mod_wsgi に限らず使うことができる。 通常のアプリケーションのログを syslog で転送する場合にも有効なので、覚えておきたい。