IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    分享一组比 laravel 调度事件中 AppendOutputTo 方法更为便捷的宏方法

    guanguans发表于 2024-01-17 10:08:45
    love 0

    分享一组比 laravel 调度事件中 AppendOutputTo 方法更为便捷的宏方法

    特性

    • 默认根据命令名称自动生成输出日志文件路径
    • 默认输出日志文件路径格式为 storage/logs/schedules/命令名称/命令名称.log
    • 由 single 渠道日志自动记录命令运行的开始运行时间,这样就会形成 laravel 标准的日志文件,可以更好的由第三方扩展去解析查看,例如 opcodesio/log-viewer
    • 更为便捷的一组按年、季、月、周、日切割输出日志的方法

    源码 - app/Support/Macros/SchedulingEventMacro.php

    <?php
    
    declare(strict_types=1);
    
    namespace App\Support\Macros;
    
    use Illuminate\Console\Scheduling\Event;
    use Illuminate\Support\Facades\Log;
    use Illuminate\Support\Stringable;
    
    /**
     * @mixin Event
     *
     * @property $channels
     */
    class SchedulingEventMacro
    {
        public function userAppendOutputToDaily(): callable
        {
            return fn (
                ?string $filename = null,
                ?string $dirname = null
            ): Event => $this->userAppendOutputTo($filename, sprintf('daily-%s', date('Y-m-d')), $dirname);
        }
    
        public function userAppendOutputToWeekly(): callable
        {
            return fn (
                ?string $filename = null,
                ?string $dirname = null
            ): Event => $this->userAppendOutputTo($filename, sprintf('weekly-%s', date('Y-W')), $dirname);
        }
    
        public function userAppendOutputToMonthly(): callable
        {
            return fn (
                ?string $filename = null,
                ?string $dirname = null
            ): Event => $this->userAppendOutputTo($filename, sprintf('monthly-%s', date('Y-m')), $dirname);
        }
    
        public function userAppendOutputToQuarterly(): callable
        {
            return fn (
                ?string $filename = null,
                ?string $dirname = null
            ): Event => $this->userAppendOutputTo(
                $filename,
                sprintf('quarterly-%s-%s', date('Y'), now()->quarter),
                $dirname
            );
        }
    
        public function userAppendOutputToYearly(): callable
        {
            return fn (
                ?string $filename = null,
                ?string $dirname = null
            ): Event => $this->userAppendOutputTo($filename, sprintf('yearly-%s', date('Y')), $dirname);
        }
    
        public function userAppendOutputTo(): callable
        {
            return function (?string $filename = null, ?string $suffix = null, ?string $dirname = null): Event {
                $outputPath = value(
                    function (?string $filename, ?string $suffix, ?string $dirname): string {
                        $filename = value(
                            function (?string $filename): string {
                                if ($filename) {
                                    return $filename;
                                }
    
                                // artisan
                                if (str($this->command)->contains("'artisan'")) {
                                    $commands = (array) explode(' ', $this->command);
    
                                    return $commands[array_search("'artisan'", $commands, true) + 1];
                                }
    
                                /** @see \Illuminate\Console\Scheduling\CallbackEvent::withoutOverlapping */
                                if (empty($this->description)) {
                                    throw new \LogicException(
                                        "Please incoming the \$filename parameter, Or use the 'name' method before 'userAppendOutputTo'."
                                    );
                                }
    
                                // exec|call|job
                                return $this->description;
                            },
                            $filename
                        );
    
                        $normalizedFilename = str($filename)->replace([\DIRECTORY_SEPARATOR, '\\', ' '], ['-', '-', '-']);
    
                        return (
                            $dirname
                                ? str($dirname)
                                : str(storage_path('logs'))
                                    ->finish(\DIRECTORY_SEPARATOR)
                                    ->append('schedules')
                                    ->finish(\DIRECTORY_SEPARATOR)
                                    ->append($normalizedFilename)
                        )
                            ->finish(\DIRECTORY_SEPARATOR)
                            ->append($normalizedFilename)
                            ->when(
                                $suffix,
                                static fn (
                                    Stringable $stringable,
                                    string $suffix
                                ) => $stringable->finish('-')->finish($suffix)
                            )
                            ->append('.log')
                            ->toString();
                    },
                    $filename,
                    $suffix,
                    $dirname,
                );
    
                // dump($outputPath);
    
                return $this
                    ->before(function () use ($outputPath): void {
                        $singleLogPath = config('logging.channels.single.path');
                        $unsetSingleChannelHandler = function (): void {
                            unset($this->channels['single']);
                        };
    
                        config()->set('logging.channels.single.path', $outputPath);
                        $unsetSingleChannelHandler->call(app('log'));
    
                        Log::channel('single')->info('>>>>>>>>');
    
                        config()->set('logging.channels.single.path', $singleLogPath);
                        $unsetSingleChannelHandler->call(app('log'));
                    })
                    ->appendOutputTo($outputPath);
            };
        }
    }

    注册

    <?php
    
    declare(strict_types=1);
    
    namespace App\Providers;
    
    use App\Support\Macros\SchedulingEventMacro;
    use Illuminate\Console\Scheduling\Event;
    use Illuminate\Support\ServiceProvider;
    
    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap any application services.
         */
        public function boot(): void
        {
            Event::mixin($this->app->make(SchedulingEventMacro::class));
        }
    }

    使用

    <?php
    
    declare(strict_types=1);
    
    namespace App\Console;
    
    use App\Console\Commands\CpSyncDataCommand;
    use Illuminate\Console\Scheduling\Schedule;
    use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
    use Spatie\ScheduleMonitor\Models\MonitoredScheduledTaskLogItem;
    
    class Kernel extends ConsoleKernel
    {
        /**
         * Define the application's command schedule.
         */
        protected function schedule(Schedule $schedule): void
        {
            $schedule->command('model:prune', ['--model' => MonitoredScheduledTaskLogItem::class])->daily()->userAppendOutputToMonthly()->withoutOverlapping();
            $schedule->command('telescope:prune')->daily()->skip($this->app->isProduction())->userAppendOutputToMonthly()->withoutOverlapping();
            $schedule->command(CpSyncDataCommand::class)->hourly()->userAppendOutputToDaily()->withoutOverlapping();
        }
    }

    效果 - storage/logs/schedules/cp:sync-data/cp:sync-data-daily-2024-01-16.log

    [2024-01-16 00:00:03] testing.INFO: >>>>>>>> {"php-version":"8.1.26","php-interface":"cli","laravel-version":"10.40.0","running-in-console":true,"X-Request-Id":"68a4470b-d6b4-4bb5-aa8e-feb8c4c43e29","command":"'/usr/bin/php8.1' 'artisan' cp:sync-data"} 
    Your Command output...
    [2024-01-16 01:00:02] testing.INFO: >>>>>>>> {"php-version":"8.1.26","php-interface":"cli","laravel-version":"10.40.0","running-in-console":true,"X-Request-Id":"7e461dac-d11c-4e25-94b5-d6976f009157","command":"'/usr/bin/php8.1' 'artisan' cp:sync-data"} 
    Your Command output...

    原文链接

    • https://github.com/guanguans/guanguans.github.io/issues/55


沪ICP备19023445号-2号
友情链接