我有一个 PHP 应用程序,它可以生成大量日志信息。我想使用它logrotate
来确保这些日志不会随着时间的推移而失控。
但是,我担心竞争条件。如果 PHP 正在写入日志,然后logrotate
确定需要轮换该日志(如下面的事件序列所示),是否会丢失日志消息?如果不是,为什么?
- PHP 打开日志文件进行写入。
- PHP 写入一行。
logrotate
决定日志文件是否应该轮换。- PHP 写入另一行。
- PHP 关闭文件资源。
file_put_contents
例如,使用 PHP 的会有什么不同吗?更一般地说,通过管道传输到日志文件的输出又会怎样呢?
环境细节:
我在另一台机器上的 nginx 服务器后面使用php5-fpm
( )。Version: 5.5.9+dfsg-1ubuntu4.6
我建议的 logrotate 配置(我还没有设置任何东西)将是这样的(在/etc/logrotate.d/my-app
):
/var/my-app-data/logs/*.log {
missingok
notifempty
weekly
size 20M
rotate 4
}
以下是我的 PHP 日志代码的几个示例:
$res = file_put_contents('/var/my-app-data/logs/general.log', date('[d/m/Y H:i:s]') . ' Something noteworthy has happened!' . "\n", FILE_APPEND);
我们将来可能会使用类似下面的代码:
$fp = fopen('/var/my-app-data/logs/general.log', 'a');
fwrite($fp, date('[d/m/Y H:i:s]') . ' Starting process...' . "\n");
// ...
fwrite($fp, date('[d/m/Y H:i:s]') . ' Something happened!' . "\n");
// ...
fwrite($fp, date('[d/m/Y H:i:s]') . ' Something happened!' . "\n");
// ...
fwrite($fp, date('[d/m/Y H:i:s]') . ' End of process.' . "\n");
fclose($fp);
答案1
当应用程序打开文件时,即使文件被移动,也会继续写入。因此,如果要确保不丢失信息,应该向应用程序发送信号,以便它释放资源。
您可以尝试这样的配置:
/var/my-app-data/logs/general.log {
missingok
notifempty
size 20M
rotate 4
create mode owner group
sharedscripts
postrotate
nginx command to do graceful restart
endscript
}
当文件general.log
大小超过其20M
容量上限时,就会进行轮换,轮换结束后4
,文件会被删除。
这sharedscripts
意味着该postrotate
脚本只会运行一次,而不是对于每个轮换的日志运行一次。
根据日志旋转手动的:
create mode owner group
Immediately after rotation (before the postrotate script is run)
the log file is created (with the same name as the log file just
rotated). mode specifies the mode for the log file in octal
(the same as chmod(2)), owner specifies the user name who will
own the log file, and group specifies the group the log file
will belong to.
因此就你的情况而言:
- 旋转文件
- 如果存在,则删除 general.log.5
- 创建具有适当属性和所有权的 general.log
- 运行 postrotate 脚本
您的应用程序将继续写入 general.log.1,直到关闭文件或postscript
执行并且 nginx 执行优雅重启。
fclose($fp)
如果您的应用程序总是通过或使用关闭日志文件,file_put_contents
您应该省略nginx
平滑重启。