perl で複数のプロセスからログを吐くときは :unix layer で開いてもいい

File::RotateLogs が大変便利でよく使っているのだが、これはファイルへ書き込むときに print を呼んでいる。

一方

によると長いログを吐くときは syswrite にしないと混ざるとある。

よって File::RotateLogs も実は混ざることがあるのかなと思い、複数プロセスから長いログを吐きまくってみたが一向に混ざらなかった。

いろいろ調べた結果、open layer に最も低級な layer である :unix を指定すれば print 時も 1 つの write(2) になるようだった。

> cat test.pl
open my $fh, ">:unix", "test.txt";
print $fh "a" x (1024 * 100);

> strace perl test.pl 2>&1 | grep write
write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 102400) = 102400

そして、File::RotateLogs はしっかりと :utf8:unix で open していた。流石である。

まとめ

perl複数のプロセスからログを吐くときは syswrite, もしくは open layer を :unix にすべき。

余談

標準 open layer は大抵の場合 :unix:perlio のため、:perlio を外すという意味で

open my $fh, ">:pop", "file";

としてもよさそうではある。