项目中内核记录的日志比较重要,但一天生成的内容很多,一天一个文件大多在百兆,怎么设置成X小时1个文件呢
没有
找到在哪设置了,RotatingFileHandler.php里FILE_PER_DAY设置为'Y-m-d H',但这是改了源码了,不知道在config/log.php里是怎么设置的
上面虽然找到了解决方法但是实际操作下来发现还是有问题,表现是虽然按小时生成了日志但不是每个小时的内容都写在相应的文件里。比如现在是17点理应生成一个2023-07-04 17.log的日志,实际却是写到了2023-07-04 11.log里,12点-17点都没有生成相应时间的日志,在网上搜索了很久没有找到合适解决方案,也看了很久源码,猜测是设置写入内存块或文件流大小的影响,奈何水平太低改不动源码。
既然改不了项目源码,那就找外部解决方案吧,搜了下有个liunx自带的logrotate日志转储工具,试了下可以满足我的需求。
配置很简单
1.先把FILE_PER_DAY设置为空,所有日志生成在一个文件里
class MyRotatingFileHandler extends RotatingFileHandler
{
const FILE_PER_DAY = '';
}
2.在/etc/logrotate.d/里创建日志分割配置
/xxx/xxx/xxx.log{ //webman的日志路径
su root root
create
daily
rotate 120
dateext
dateformat %Y-%m-%d %H
missingok
copytruncate //该设置必选,如果不截断已经打开文件,即使已经转存日志,后续的日志还会写到已分割的里面
notifempty
}
以下是全部配置项
compress 通过gzip 压缩转储以后的日志
nocompress 不做gzip压缩处理
copytruncate 用于还在打开中的日志文件,把当前日志备份并截断;是先拷贝再清空的方式,拷贝和清空之间有一个时间差,可能会丢失部分日志数据。
nocopytruncate 备份日志文件不过不截断
create mode owner group 轮转时指定创建新文件的属性,如create 0777 nobody nobody
nocreate 不建立新的日志文件
delaycompress 和compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress 覆盖 delaycompress 选项,转储同时压缩。
missingok 如果日志丢失,不报错继续滚动下一个日志
errors address 转储时的错误信息发送到指定的Email 地址
ifempty 即使日志文件为空文件也做轮转,这个是logrotate的缺省选项。
notifempty 当日志文件为空时,不进行轮转
mail address 把转储的日志文件发送到指定的E-mail 地址
nomail 转储时不发送日志文件
olddir directory 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir 转储后的日志文件和当前日志文件放在同一个目录下
sharedscripts 运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个,那么每个日志轮转后都会执行一次脚本
prerotate 在logrotate转储之前需要执行的指令,例如修改文件的属性等动作;必须独立成行
postrotate 在logrotate转储之后需要执行的指令,例如重新启动 (kill -HUP) 某个服务!必须独立成行
daily 指定转储周期为每天
weekly 指定转储周期为每周
monthly 指定转储周期为每月
rotate count 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
dateext 使用当期日期作为命名格式
dateformat .%s 配合dateext使用,紧跟在下一行出现,定义文件切割后的文件名,必须配合dateext使用,只支持 %Y %m %d %s 这四个参数
size(或minsize) log-size 当日志文件到达指定的大小时才转储,log-size能指定bytes(缺省)及KB (sizek)或MB(sizem).
当日志文件 >= log-size 的时候就转储。 以下为合法格式:(其他格式的单位大小写没有试过)
size = 5 或 size 5 (>= 5 个字节就转储)
size = 100k 或 size 100k
size = 100M 或 size 100M
3.如果有每X小时或每X分分割日志需求的要创建crontab来执行日志分割
//-f 强制模式
0 */1 * * * /usr/sbin/logrotate -f /etc/logrotate.d/webman
4.结果
中间空的时间是因为主日志没有内容所以不分割
只能自己写一个脚本 处理了估计
日志的文件名是可以自定义的,在 config/log.php 中,你可以直接定义一个函数生成日志文件名,什么样的格式都可以,但好像默认都会带有当前日期的后缀。比如定义文件名为 runtime_path() . '/logs/webman' . date('YmdH') . '.log',生成的文件名会是 webman2023062909-2023-06-29.log
别改源码,不好升级。app目录下直接建立一个MyRotatingFileHandler类
config/log.php配置里
'class' => Monolog\Handler\RotatingFileHandler::class,
改成
'class' => app\MyRotatingFileHandler::class,
reload搞定
正解
这个是按照小时 打印的嘛???
厉害了
厉害
按小时分割是解决了,但是发现不是准确的按小时生成日志,比如现在是16点,他会把日志写在2023-07-04 11.log里,过一会再刷新就会生成2023-07-04 16.log,中间12点-15点的日志都写在11点的日志里
你得研究下monolog源码,看它什么时候生成日志,在你的类里重写那块的逻辑
改不动源码,绕路解决
试了一下这个方法,发现还是有问题,不能每个小时都生成日志文件,或者有的日志又记录到前面小时的日志文件去了,经研究和实践,MyRotatingFileHandler 类复制自RotatingFileHandler类全部重写了方法,修改命名空间和引入缺失的父类StreamHandler, 修改常量 'public const FILE_PER_DAY = 'Y-m-d-H';',然后找到类中两处
$this->nextRotation = new \DateTimeImmutable('tomorrow');
并改成$this->nextRotation = new \DateTimeImmutable('now');
同时修改log.php配文件的constructor的第二个参数,把7改成168,意思是:24 * 7 即一天24个文件,保留7天的文件
这个参数 根本就不起作用呀,我之前测试写2 但是 还是全部保留了
我的是生效的,不修改前,系统一直保留最近7天的日志,后来改为小时了,只保留7小时的日志,改168就生效了。我的MyRotatingFileHandler类是重写了RotatingFileHandler类,而楼主却是继承了RotatingFileHandler类,不知道你是怎样写
一样的写法 感觉不生效
啥叫感觉啊,你可以把
public const FILE_PER_DAY = 'Y-m-d-H';
改成public const FILE_PER_DAY = 'Y-m-d-H-i';
每分钟生成一个文件,还有这个$this->nextRotation = new \DateTimeImmutable('now');
很关键,再找到getGlobPattern()
方法把H,i
补上,试一试为了更好地兼容,可以加个条件
我试试 他是否会自动删除日志文件
我刚才测试了 安分钟的 'constructor' => [
runtime_path() . '/logs/api/api.log',
2,
Monolog\Logger::DEBUG,
], 但是还是会留很多的日志文件
是按照分钟写的日志 public const FILE_PER_DAY = 'Y-m-d H-i'; 正常就应该留两个文件 但是现在好几个
他只会删除相同格式的文件,也就是分钟格式的。我的是生效的,你的不生效自己找找原因
你不应该留空格,文件名留空格是大忌
日志肯定是相同格式的呀,按照分钟的 你留两个 是不是两分钟之前的日志就被删除了吧,但是我的不生效
把public const FILE_PER_DAY = 'Y-m-d H-i';的空格去掉