Принудительно провисать, входя в очередь - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть небольшая дилемма, так как мне нужно придумать хороший регистратор, который одновременно регистрирует, что происходит в приложении, если есть вызванный Log::error, он также должен уведомить администратора Devs и Sys через слабину. В настоящее время он работает , но добавляет время к ответу на запрос.

Ниже приведены мои настройки:

//config/logging.php
    'default' => env('LOG_CHANNEL', 'stack'),
    //truncated
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily', 'slack'],
        ],

        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 0,
        ],

        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'App',
            'emoji' => ':boom:',
            'level' => 'error',
        ]
    ]
    //truncated

//UserController
public function show(User $user)
{
    //just a sample code, the important part is where the Log facade is called
    try {
        //business logic
    } catch (Exception $e) {
        Log::error(get_class(), [
            'user_id' => $user->id,
            'message' => $e->getMessage()
        ]);
    }  

    return view('user.show', compact($user));
}

Это уже работает, но для Конечно, мы все еще можем улучшить это, чтобы уменьшить накладные расходы, хотя добавленное время для кода выше незначительно, но реальный код более сложен и имеет довольно много итераций

Как я могу изменить, изменить поведение 'слабый' логгер, чтобы положить sh в очередь, когда он срабатывает? Я предпочитаю кодировать его один раз и забыть, а не вспоминать, что мне нужно отправить sh в регистратор по требованию, например

Log::chanel(['daily', 'slack'])->...

ИЛИ

//this is good for more on particular event notification but not not error notification which can happen anywhere
Notification::route('slack', env('LOG_SLACK_WEBHOOK_URL'))->notify(new AlertDevInSlackNotification)`

Примечание:

  • Я пытался добавить какой-то код в bootstrap/app.php, но он не работает
//bootstrap/app.php
$app->configureMonologUsing(function($monolog) use ($app) {
    //some code here. does not work, just getting page not working
});
  • Это как когда я звоню этот уровень журнала и этот канал, я хочу его поставить в очередь

Ответы [ 2 ]

0 голосов
/ 11 февраля 2020

Спасибо @ZeroOne за то, что он дал идею о том, как ее решить. Я хотел его автоматизировать c, и любой существующий код, имеющий Log::error(), будет автоматически запрашивать разработчиков.

Ниже мое решение.

//CustomSlackServiceProvider.php
try {
    //listen to all events
    Event::listen('*', function($event, $details) {
        //check if the event message logged event which is triggered when we call Log::<level>
        if($event == "Illuminate\Log\Events\MessageLogged") {
            //$details contain all the information we need and it comes in array of object
            foreach($details as $detail) {
                //check if the log level is from error to emergency
                if(in_array($detail->level, ['emergency', 'critical', 'alert', 'error'])) {
                    //trigger the notification
                    Notification::route('slack', env('LOG_SLACK_WEBHOOK_URL'))->notify(new AlertDevInSlackNotification($detail->message, $detail->level, $detail->context));
                }
            }
        }
    });
} catch (Exception $e) {

}

//AlertDevInSlackNotification.php
class AlertDevInSlackNotification extends Notification implements ShouldQueue
{
    use Queueable;

    private $class;
    private $level;
    private $context;

    public function __construct($class, $level, $context)
    {
        $this->class = $class;
        $this->level = strtoupper($level);
        $this->context = $context;

        //prevent congestion in primary queue - make sure this queue exists
        $this->queue = 'alert';
    }

    public function via($notifiable)
    {
        return ['slack'];
    }

    public function toSlack($notifiable)
    {
        return (new SlackMessage)
            ->content($this->level.': '.$this->class)
            ->attachment(function($attachment) {
                $attachment->fields($this->context);
            });
    }

ОБНОВЛЕНИЕ:

приведенный выше код будет работать, когда вы запустите Log::error().

Но для прослушивания события, которое вызывается ошибкой, такой как синтаксическая ошибка, которая вызовет «Сериализация« Закрытие »не разрешена». Вместо этого вы можете сделать это для улучшения покрытия:

    public function boot()
    {
        try {
            //listen to all events
            Event::listen('*', function($event, $details) {
                //check if the event message logged event which is triggered when we call Log::<level>
                if($event == "Illuminate\Log\Events\MessageLogged") {
                    // dump($event);
                    //$details contain all the information we need and it comes in array of object
                    foreach($details as $detail) {
                        $this->path = '';
                        $this->level = '';
                        $this->context = [];
                        $this->message = '';

                        //check if the log level is from error to emergency
                        if(in_array($detail->level, ['emergency', 'critical', 'alert', 'error'])) {
                            //@todo - exclude: Error while reading line from the server. [tcp://cache:6379] = restart

                            //check if the context has exception and is an instance of exception
                            //This is to prevent: "Serialization of 'Closure' is not allowed" which prevents jobs from being pushed to the queue
                            if(isset($detail->context['exception'])) {
                                if($detail->context['exception'] instanceof Exception) {

                                    $this->level = $detail->level;
                                    //to keep consistency on all the log message, putting the filename as the header
                                    $this->message = $detail->context['exception']->getFile();
                                    $this->context['user'] = auth()->check() ? auth()->user()->id.' - '. auth()->user()->first_name.' '.auth()->user()->last_name : null;
                                    $this->context['message'] = $detail->context['exception']->getMessage();
                                    $this->context['line'] = $detail->context['exception']->getLine();
                                    $this->context['path'] = request()->path();

                                    $this->runNotification();
                                    continue;
                                }
                            }

                            $this->level = $detail->level;
                            $this->context = $detail->context;
                            $this->message = $detail->message;

                            $this->runNotification();
                            continue;
                        }
                    }
                }
            });
        } catch (Exception $e) {

        }
    }

    public function runNotification()
    {
        Notification::route('slack', env('LOG_SLACK_WEBHOOK_URL'))->notify(new AlertDevInSlackNotification($this->message, $this->level, $this->context));
    }
0 голосов
/ 11 февраля 2020

Вы можете сделать это следующим образом.

1. Создать задание ex: имя как LogSlackQueue.php

public class LogSlackQueue implements ShouldQueue {
     ...
     ...
     public function handle() {
          Log::channel(['daily', 'slack'])->info($your_input);
     }
}

2. Затем использовать как

LogSlackQueue::dispatch($your_input)

Если Вы не хотите делать, как указано выше, вам нужно разобраться, чтобы сделать пользовательский провайдер

...