PHP写日志
需求:PHP在每次请求结束之前,要向一个文件写入数据。要克服环境因素,尽量保证写操作成功。
于是我第一版的代码是这样的:
<?php
function write_log($message) {
file_put_contents('./logs/2015.log', $message);
}
write_log(123);
?>
这时候,我遇到了第一个问题,如果没有./log目录怎么办?因为不论是代码初次上线,或者是新开发clone完项目准备开发,都有可能遇到没有./logs这个目录的情况。
需求:需要加上路径判断。
于是就有了第二版:
<?php
function write_log($message) {
if (!is_dir('./logs')) {
mkdir('./logs');
}
file_put_contents('./logs/2015.log', $message);
}
write_log(123);
?>
写到这里,我觉得我已经很好的完成了我作为程序员的工作,既实现了功能,又加了保护逻辑,谁知道吃翔的经历刚刚开始。有一天突然之间不停的有warning,是在mkdir()这一行,虽然对于程序员来说,warning == running,但还是上去看了看,最终定位到原因:./logs的目录权限被篡改成了0400。导致文件写入失败。
需求:写日志不能影响正常请求流程,在上述情况下,需要告警出来。
第三版:
<?php
function write_log($message) {
if (!is_dir('./logs')) {
mkdir('./logs');
}
if (!is_writeable('./logs/2015.log')) { // 这样不管哪一级目录、文件被改成了不可写,都不会触发错误,只会告警出来。
// 告警
return false;
}
file_put_contents('./logs/2015.log', $message);
}
write_log(123);
?>
文章写到这里,我就没心情调侃了,直接说第四次遇到的问题。./logs目录权限没问题,但是./logs的父目录的权限被改成了0400,所以没办法mkdir(‘./logs’)。
ps:这里再补充说一下,如果不是!is_dir(‘./logs’)的话,也只会告警出来,不会主流程走不下去。
需求:上述问题,也只能告警出来,不能影响主流程。
第四版a:
<?php
function write_log($message) {
if (!is_dir('./logs')) {
try {
mkdir('./logs');
} catch (Exception $e) {
// 告警
return false;
}
}
if (!is_writeable('./logs/2015.log')) { // 这样不管哪一级目录、文件被改成了不可写,都不会触发错误,只会告警出来。
// 告警
return false;
}
file_put_contents('./logs/2015.log', $message);
}
write_log(123);
?>
可怜的人啊,如果你觉得这个没问题的话,你就被php坑了。
PHP对异常的奇葩处理,请参考这里,下面附上正确姿势:
第四版f:
<?php
function write_log($message) {
if (!is_dir('./logs')) {
$mkdir_res = @mkdir('./logs');
if (!$mkdir_res) {
// 告警
return false;
}
}
if (!is_writeable('./logs/2015.log')) { // 这样不管哪一级目录、文件被改成了不可写,都不会触发错误,只会告警出来。
// 告警
return false;
}
file_put_contents('./logs/2015.log', $message);
}
write_log(123);
?>
写到这里,终于算是把这个问题告一段落了,最后总结一下遇到的问题:
- 没有目录
- 没有权限
- 异常捕获失败