初めに
perlにはstart_serverというデーモン管理プログラムがあるのですが、
これがlogrotate時にログファイルを再オープンするような機能を、
どうも持ってなさそうだったので、別の方法として表題の手法を取りました。
(環境はCentOS7です)
準備
例えば下記のようなwebアプリがあったとして
(例はperlですが、別にrubyでもpythonでもnodeでも何でも構いません)
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のファイルを作成します。
[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で受けるために、設定ファイルを作ります。
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の制限解除
単位時間に一定量以上のログを流すとフィルタリングされてしまいます。
必要に応じて、その制限を解除しておきます。
[Journal]
...
#RateLimitInterval=30s
#無制限にする
RateLimitInterval=0
...
この後に、journaldの再起動をします。
sudo systemctl restart systemd-journald
デーモン側のプロセスも再起動しないと、ログが全く出てこなくなったので、
そちらも再起動しておきます。
sudo systemctl restart test
※もしかするとjournaldを再起動したら、システムまるごと再起動したほうがいいのかな・・・?
logrotateの設定
/etc/logrotate.d/
配下に設定ファイルを作成します。
/var/log/test.log
{
missingok
notifempty
compress
compresscmd /usr/bin/xz
compressoptions -6
rotate 90
daily
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
dry-run(実際にローテートせずに実験)してみます。
$ logrotate -dv /etc/logrotate.d/test
reading config file /etc/logrotate.d/test
compress_prog is now /usr/bin/xz
compress_options is now -6
Allocating hash table for state file, size 15360 B
Handling 1 logs
rotating pattern: /var/log/test.log
after 1 days (90 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/test.log
log does not need rotating (log has been already rotated)not running postrotate script, since no logs were rotated
ちゃんとローテートできそうですね。