Perl
Linux
systemd
rsyslog
centos7

systemd環境でアプリのログをsyslogに流す

初めに

perlにはstart_serverというデーモン管理プログラムがあるのですが、
これがlogrotate時にログファイルを再オープンするような機能を、
どうも持ってなさそうだったので、別の方法として表題の手法を取りました。
(環境はCentOS7です)

準備

例えば下記のようなwebアプリがあったとして
(例はperlですが、別にrubyでもpythonでもnodeでも何でも構いません)

app.psgi
use strict;
use warnings;
use 5.010;

use Plack::Request;

my $i   = 0;
my $app = sub {
        my ($env)       = @_;
        my $req         = Plack::Request->new($env);

        say "STDOUT : request $i";
        warn "STDERR : request $i";
        $i++;

        my $res = $req->new_response(200);
        $res->body("$i\n");
        return $res->finalize;
};

$app;

こいつをデーモンとして起動するとします。

systemd設定

perlのstart_serverを利用するとしたら、
例えば下記のようなsystemdのファイルを作成します。

/etc/systemd/system/test.service
[Unit]
Description = test Daemon

[Service]
Environment = "PATH=/bin:/usr/bin:/home/vagrant/.anyenv/envs/plenv/shims/"
ExecStart = /home/vagrant/.anyenv/envs/plenv/shims/start_server --backlog 1024 --port 5000 --pid /tmp/test.pid --status-file /tmp/test.status  --signal-on-hup=USR1 -- plackup -s Gazelle --workers=1 /home/vagrant/mysrc/perl/log-test/app.psgi
Restart = always
Type = simple
User = vagrant
Group = vagrant
LimitNOFILE = 60000

StandardOutput=syslog # キモ
StandardError=syslog  # キモ

SyslogIdentifier=test-daemon

[Install]
WantedBy = multi-user.target

キモと記載している部分が重要で、
標準出力、標準エラー出力をsyslogに流してくれます。

rsyslogd設定

先のデーモンログをrsyslogdで受けるために、設定ファイルを作ります。

/etc/rsyslog.d/test-daemon.conf
if $programname == 'test-daemon' then /var/log/test.log
# messagesに出るのを抑止する
if $programname == 'test-daemon' then ~

"test-daemon"の部分は、serviceファイルの SyslogIdentifier で記載した名前にします。

rsyslogdを再起動します。

sudo systemctl restart rsyslog

これで、/var/log/test.logにアプリケーションのログが出力されます。

while [ 1 ] ; do curl http://localhost:5000/; done

とかでアクセスをしてみて、

tail -f /var/log/test.log

でログがでていればOKです。

journaldの制限解除

単位時間に一定量以上のログを流すとフィルタリングされてしまいます。

必要に応じて、その制限を解除しておきます。

/etc/systemd/journald.conf
[Journal]
...
#RateLimitInterval=30s
#無制限にする
RateLimitInterval=0
...

この後に、journaldの再起動をします。

sudo systemctl restart systemd-journald

デーモン側のプロセスも再起動しないと、ログが全く出てこなくなったので、
そちらも再起動しておきます。

sudo systemctl restart test

※もしかするとjournaldを再起動したら、システムまるごと再起動したほうがいいのかな・・・?