3

我在 Laravel 7.3 上构建项目,同时运行多个作业。我需要让每个 Job 将日志写入不同的每日旋转文件。日志文件的名称应基于 Job 正在处理的模型。

问题是我找不到聪明的解决方案。

我试过的:

1) 在config/logging.php.

这按预期工作,但目前大约有 50 个不同的工作,并且数量不断增长。方法很丑陋,很难维护。

2)设置Config(['logging.channels.CUSTOMCHANNEL.path' => storage_path('logs/platform/'.$this->platform->name.'.log')]);

使用 Config 变量是个坏主意,因为许多作业一次运行。结果,来自一个作业的消息通常被写入另一个作业日志。

3)使用Log::useDailyFiles()

自 laravel 5.5 或 5.6 以来,这似乎停止工作。只是得到错误Call to undefined method Monolog\Logger::useDailyFiles()。任何想法如何在 laravel 7 中工作?

4) 使用tap通道参数config/logging.php

laravel 文档中的示例 不知道如何将模型名称传递给 CustomizeFormatter 以设置文件名。

我几乎可以肯定有聪明的解决方案,我只是错过了一些东西。有什么建议吗?谢谢!

4

2 回答 2

1

您可以继承日志管理器以允许动态配置

<?php

namespace App\Log;

use Illuminate\Support\Str;
use Illuminate\Log\LogManager as BaseLogManager;

class LogManager extends BaseLogManager
{
    /**
     * Get the log connection configuration.
     *
     * @param  string  $name
     * @return array
     */
    protected function configurationFor($name)
    {
        if (!Str::contains($name, ':')) {
            return parent::configurationFor($name);
        }
        [$baseName, $model] = explode(':', $name, 2);
        $baseConfig = parent::configurationFor($baseName);
        $baseConfig['path'] = ...; //your logic
        return $baseConfig;
    }
}

同样关于 Laravel 的日志服务提供者,除了这个可以完全替换

<?php

namespace App\Log;

use Illuminate\Support\ServiceProvider;

class LogServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('log', function ($app) {
            return new LogManager($app);
        });
    }
}

编辑:我刚刚看到 Laravel 的日志服务提供者丢失了config/app.php,这是因为它是由应用程序“硬加载”的。您仍然可以通过继承应用程序本身来替换它

<?php

namespace App\Foundation;

use App\Log\LogServiceProvider;
use Illuminate\Events\EventServiceProvider;
use Illuminate\Routing\RoutingServiceProvider;
use Illuminate\Foundation\Application as BaseApplication;

class Application extends BaseApplication
{
    /**
     * Register all of the base service providers.
     *
     * @return void
     */
    protected function registerBaseServiceProviders()
    {
        $this->register(new EventServiceProvider($this));
        $this->register(new LogServiceProvider($this));
        $this->register(new RoutingServiceProvider($this));
    }
}

最后在bootstrap/app.php,替换Illuminate\Foundation\ApplicationApp\Foundation\Application

例如,如果你尝试这个

app('log')->channel('single:users')->debug('test');

Laravel 将使用single通道的配置并写入,users.log如果您的解析逻辑是

$baseConfig['path'] = $model + '.log';
于 2020-04-04T14:05:05.100 回答
0

我得到了一个自 Laravel 4 以来一直在使用的解决方案,尽管它不遵循“Laravel”的做事方式。

class UserTrackLogger
{
    /**
     * @var $full_path string
     */
    protected $full_path;
    /**
     * @var $tenant string
     */
    protected $tenant;
    /**
     * @var $user User
     */
    protected $user;
    /**
     * @var $request Request
     */
    protected $request;

    public static function log(string $message, Request $request, User $user, array $data = []): void
    {
        /** @noinspection PhpVariableNamingConventionInspection */
        $userTrack = new static($request, $user);
        $userTrack->write($message, $data);
    }

    protected function __construct(Request $request, User $user)
    {
        $this->request = $request;
        $this->user = $user;
        $this->tenant = app()->make('tenant')->tenant__name;
        $path = storage_path() . "/logs/{$this->tenant}/users";

        $filename = $this->user->username_with_name;
        $this->full_path = Formatter::formatPath("{$path}/{$filename}.log");
        self::makeFolder($this->full_path);
    }

    protected function write(string $message, array $data = []): void
    {
        $formatter = $this->getFormat();
        $record = [
            'message'    => $message,
            'context'    => $data,
            'extra'      => [],
            'datetime'   => date(Utility::DATETIME_FORMAT_DEFAULT),
            'level_name' => 'TRACK',
            'channel'    => '',
        ];
        file_put_contents($this->full_path, $formatter->format($record), FILE_APPEND);
    }

    protected function getFormat(): FormatterInterface
    {
        $ip = $this->request->getClientIp();
        $method = strtoupper($this->request->method());
        $format = "[%datetime%][{$this->tenant}][{$this->user->username}][{$this->user->name}]: $ip $method %message% %context%\n";
        return new LineFormatter($format, null, true);
    }

    protected static function makeFolder(string $full_path): bool
    {
        $path = dirname($full_path);
        if ( !is_dir($path) ) {
            return mkdir($path, 0755, true);
        }

        return false;
    }
}

当我想记录一些东西时,我会UserTrackLogger::log($request->fullUrl(), $request, $user, $data);

我建议创建一个与此类似但扩展的记录器RotatingFileHandler

于 2020-10-09T16:16:20.317 回答