我们有 Monolog/RotatingFileHandler 和 cron 表达式。有人创建了一个理解 crontabs 表达式的 Monolog Filehandler 吗?我很想能够做到
$log = new Monolog\Logger( 'default' );
$log->pushHandler( new Monolog\Handler\CronRotateHandler( ROOT . 'log/default.log', "0 0 * * 6", Monolog\Logger::DEBUG ) );
创建每周六 00:00 轮换。这是已经创建的还是我应该自己编写一个?
基于dragonmantank/cron-expression 和 cesargb/php-log-rotation
<?php declare(strict_types=1);
namespace Monolog\Handler;
/*
* This file is part of the Monolog package.
*
* (c) TheKing2 <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Monolog\Level;
use Monolog\Utils;
/**
* Stores logs rotated by cron expression
*
* This rotation is only intended to be used as a workaround. Using logrotate to
* handle the rotation is strongly encouraged when you can use it.
*
*/
class CronRotatingFileHandler extends StreamHandler implements HandlerInterface
{
private $filename;
private $stateFilename;
/**
* @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
* @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
* @param bool $useLocking Try to lock log file before doing any writes
*/
public function __construct(
string $filename,
array $rotateSettings,
int|string|Level $level = Level::Debug,
bool $bubble = false,
?int $filePermission = null,
bool $useLocking = false
) {
$this->filename = Utils::canonicalizePath( $filename );
$this->checkRotate( $rotateSettings );
parent::__construct( $this->filename, $level, $bubble, $filePermission, $useLocking );
}
/**
* checkRotate
*
* @return void
*/
protected function checkRotate( array $rotateSettings ): void
{
$cronExpression = $rotateSettings['cronExpression'] ?? '* * */1 * *';
$maxFiles = $rotateSettings['maxFiles'] ?? 366;
$minSize = $rotateSettings['minSize'] ?? 0;
$compress = $rotateSettings['compress'] ?? false;
$stateFilename = Utils::canonicalizePath( $this->filename . '.state' );
$fileInfo = new \SplFileInfo( $stateFilename );
if( !$fileInfo->isFile() ) {
touch( $stateFilename );
}
// create state file if not exist
$rotation = ( new \Cesargb\Log\Rotation() )
->files( $maxFiles )
->minSize( $minSize );
if( $compress ) {
$rotation->compress();
}
$cron = new \Cron\CronExpression( $cronExpression );
// check if log file is due based on state file modified time
$dateTime = new \DateTimeImmutable(); // current datetime
$filedateTime = $dateTime->setTimeStamp( $fileInfo->getMTime() ); // state-file datetime
$nextRun = $cron->getNextRunDate( $filedateTime ); // next-run datetime
// if log file is due, rotate it
if( $nextRun < $dateTime ) {
// rotate log file
touch( $fileInfo->getRealPath() );
$rotation->rotate( $this->filename );
}
}
}