功能实现是参考了这个帖子:https://www.workerman.net/q/9487
使用的是手册中的monolog包:https://www.workerman.net/doc/webman/log.html
实现方式如下:
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'default' => [
'handlers' => [
[
'class' => \support\log\MonologExtendHandler::class,
'constructor' => [
null,
config('common.single_log_size'),
Monolog\Logger::DEBUG,
true,
0755
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [null, 'Y-m-d H:i:s', true,true],
],
]
],
],
'api' => [
'handlers' => [
[
'class' => \support\log\MonologExtendHandler::class,
'constructor' => [
'api',
config('common.single_log_size'),
Monolog\Logger::DEBUG,
true,
0755
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [null, 'Y-m-d H:i:s', true,true],
],
]
],
],
'task' => [
'handlers' => [
[
'class' => \support\log\MonologExtendHandler::class,
'constructor' => [
'task',
config('common.single_log_size'),
Monolog\Logger::DEBUG,
true,
0755
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [null, 'Y-m-d H:i:s', true,true],
],
]
],
],
];
在support文件夹中创建log/MonologExtendHandler.php文件,代码如下:
<?php
/**
* Created by PhpStorm.
* User: hjl
* Date: 2023/6/21
* Time: 07:25
*/
namespace support\log;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
class MonologExtendHandler extends StreamHandler
{
protected int $maxFileSize;
protected bool $mustRotate;
protected string $runtimeLogPath;
protected string|null $channelDirName;
/**
* @param string $channelDirName 日志通道路径
* @param int $maxFileSize The maximal file size (default 10MB)
* @param int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @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
*
* @throws \Exception
*/
public function __construct($channelDirName = null, $maxFileSize = 10485760, $level = Logger::DEBUG, bool $bubble = true, int $filePermission = null, bool $useLocking = false)
{
$this->runtimeLogPath = runtime_path() . '/logs/';
$this->channelDirName = $channelDirName;
$dateDir = date('Ym').'/';
$filename = date('d') .'.log';
$fullFilePath = empty($channelDirName) ? $this->runtimeLogPath . $dateDir .$filename : $this->runtimeLogPath . $this->channelDirName . '/' . $dateDir . $filename;
$this->maxFileSize = (int)$maxFileSize;
if ($maxFileSize <= 0) {
throw new \Exception('Max file size must be higher than 0');
}
parent::__construct($fullFilePath, $level, $bubble, $filePermission, $useLocking);
}
/**
* {@inheritdoc}
*/
public function close(): void
{
parent::close();
if ($this->mustRotate) {
$this->rotate();
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
parent::reset();
if ($this->mustRotate) {
$this->rotate();
}
}
/**
* {@inheritdoc}
*/
protected function write(array $record): void
{
$dateDir = date('Ym') . '/';
$logBasePath = empty($this->channelDirName) ? $this->runtimeLogPath . $dateDir : $this->runtimeLogPath . $this->channelDirName . '/' . $dateDir;
$fullLogFilename = $logBasePath . date('d').'.log';
clearstatcache(true, $fullLogFilename);
if (file_exists($fullLogFilename)) {
$fileSize = filesize($fullLogFilename);
if ($fileSize >= $this->maxFileSize) {
$this->mustRotate = true;
$this->close();
}else{
$this->stream = null;
$this->url = $fullLogFilename;
}
}else{
// 解决WebMan启动后删除日志文件无法写入的问题
$this->mustRotate = true;
$this->close();
}
parent::write($record);
}
/**
* Rotates the files.
*/
protected function rotate()
{
// skip GC of old logs if file size is unlimited
if ($this->maxFileSize === 0) {
return;
}
$dateDir = date('Ym') . '/';
$logBasePath = empty($this->channelDirName) ? $this->runtimeLogPath . $dateDir : $this->runtimeLogPath . $this->channelDirName . '/' . $dateDir;
$filename = date('d').'.log';
$fullLogFilename = $logBasePath . $filename;
// archive latest file
clearstatcache(true, $fullLogFilename);
if (file_exists($fullLogFilename)) {
$target = $logBasePath. time() . '_' . $filename;
rename($fullLogFilename, $target);
}else{
if (!is_dir($logBasePath))
{
mkdir($logBasePath,0755,true);
}
$this->url = $fullLogFilename;
}
$this->mustRotate = false;
}
}
/**
* 写日志
*/
if (!function_exists('write_log')) {
function write_log($msg, $extend = [], $level = 'error', $channel = 'api')
{
$requestParams = [];
$line = "\n---------------------------------------------------------------\n";
if (empty(request()))
{
$logInfo = $line;
}else{
$method = request()->method();
$requestInfo = [
'ip' => request()->getRealIp(),
'method' => $method,
'uri' => ltrim(request()->fullUrl(),'/')
];
$logInfo = implode(' ',$requestInfo) . $line;
$method = strtolower($method);
$requestParams = in_array($method,['get','post']) ? request()->{$method}() : request()->all();
}
$logInfo .= var_export([
'msg' => $msg,
'extend' => $extend,
'params' => $requestParams
], true);
\support\Log::channel($channel)->addRecord(CommonConst::LOG_LEVEL_STATUS[$level],$logInfo);
}
}
// LOG_LEVEL_STATUS如下:
const LOG_LEVEL_STATUS = [
'debug' => 100,
'info' => 200,
'warning' => 300,
'error' => 400,
'critical' => 500,
'alert' => 550,
'emergency' => 600
];
当单个文件超出指定大小(如:2M),则会创建新的日志文件,如1702018075_08.log。以上代码可以参考参考。
赞
感谢分享。按照你的教程,我这边已经实现了。给你点赞。
歪瑞古德
6
我通过楼主的设置后,出现以下报错:
版本:Webman-framework v1.5.16
php版本:PHP 8.3.2
这个该如何解决呢?
我错了,我配置错
感谢大佬 你最帅
感谢,mark 下,回头忙完手头的事再试试