Webman日志按日期分割

Jonlinc

功能实现是参考了这个帖子:https://www.workerman.net/q/9487
使用的是手册中的monolog包:https://www.workerman.net/doc/webman/log.html
实现方式如下:

1、在config/log.php中添加以下配置


<?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],
                ],
            ]
        ],
    ],
];

2、重写monolog StreamHandler类:

在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;
    }
}

3、 使用

/**
 * 写日志
 */
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
    ];

4、说明

当单个文件超出指定大小(如:2M),则会创建新的日志文件,如1702018075_08.log。以上代码可以参考参考。

2762 7 23
7个评论

yoyo_admin

  • 暂无评论
luhuan

感谢分享。按照你的教程,我这边已经实现了。给你点赞。

  • 暂无评论
964562398

歪瑞古德

  • 暂无评论
咸鱼.php

6

  • 暂无评论
bang

我通过楼主的设置后,出现以下报错:

TypeError: support\Log::handler(): Return value must be of type Monolog\Handler\HandlerInterface, Monolog\Formatter\LineFormatter returned in ----------------/vendor/workerman/webman-framework/src/support/Log.php:105

版本:Webman-framework v1.5.16
php版本:PHP 8.3.2

这个该如何解决呢?

  • bang 2024-02-27

    我错了,我配置错

ikun

感谢大佬 你最帅

  • 暂无评论
zjfazc

感谢,mark 下,回头忙完手头的事再试试

  • 暂无评论

Jonlinc

290
积分
0
获赞数
0
粉丝数
2023-05-30 加入
×
🔝