From eecc43e4d578723735051761616641494fbefac2 Mon Sep 17 00:00:00 2001 From: Justin Fossey Date: Mon, 4 Dec 2017 18:10:36 +0200 Subject: [PATCH] Basic routing from config using Automatic App::makeWith() method --- README.md | 5 +- src/Config.php | 50 ++++++++++ src/Listeners/LogRouter.php | 143 +++++++++++++++++++++++++++ src/Listeners/LogRouterAsync.php | 13 +++ src/LogRouterServiceProvider.php | 159 +++++++++++++++++++++++++++++++ 5 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 src/Config.php create mode 100644 src/Listeners/LogRouter.php create mode 100644 src/Listeners/LogRouterAsync.php create mode 100644 src/LogRouterServiceProvider.php diff --git a/README.md b/README.md index c1b834a..3afad00 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# LogDispatcher -Dispatch logs of any level to different handlers: database or third party services +# LogRouter + +Route and filter Laravel Monolog entries to different handlers through a simple config. diff --git a/src/Config.php b/src/Config.php new file mode 100644 index 0000000..3a01cb6 --- /dev/null +++ b/src/Config.php @@ -0,0 +1,50 @@ + [ + 'test' => [ + 'aSync' => true, + 'handler' => Monolog\Handler\StreamHandler::class, + 'levels' => [ 'warning' ], + 'params' => [ + 'stream' => storage_path('log/router/test.log'), + ], + ], + ], + +]; \ No newline at end of file diff --git a/src/Listeners/LogRouter.php b/src/Listeners/LogRouter.php new file mode 100644 index 0000000..efc9072 --- /dev/null +++ b/src/Listeners/LogRouter.php @@ -0,0 +1,143 @@ + Monolog::DEBUG, + 'info' => Monolog::INFO, + 'notice' => Monolog::NOTICE, + 'warning' => Monolog::WARNING, + 'error' => Monolog::ERROR, + 'critical' => Monolog::CRITICAL, + 'alert' => Monolog::ALERT, + 'emergency' => Monolog::EMERGENCY, + ]; + + const ASYNC = false; + + protected $monolog; + protected $routes; + + /** + * Setup that builds the logger and sets the handlers based on a config. We + * dont setup in a constructor as monolog is note serializable. + * + * @return void + */ + public function ensureSetup() + { + // Check if we already setup + if (!is_null($this->monolog)) { + return; + } + + $this->makeLogger(); + $this->setHandlers(); + } + + /** + * Handle the event. + * + * @param OrderShipped $event + * @return void + */ + public function handle(MessageLogged $event) + { + $this->ensureSetup(); + $this->routeMessage($event); + } + + protected function routeMessage(MessageLogged $event) + { + $this->monolog->{$event->level}($event->message . ' from =' . get_class($this), $event->context); + } + + /** + * Build the monolog object + * + * @return void + */ + protected function makeLogger() + { + $channel = 'log_router.' . app()->environment(); + $this->monolog = new Monolog($channel); + } + + /** + * Set/push the handlers to the monolog object. A handler is only set to + * active if it has at least one handler. + * + * @return void + */ + protected function setHandlers() + { + $routes = collect(Config::get('log_router.routes')) + ->transform(function($item) { return collect($item); }) + ->filter(function($item) { + return $item->get('aSync', false) === static::ASYNC; + }); + + $this->routes = $routes->map(function ($route, $name) { + $class = $route->get('handler'); + $filterLevels = $route->get('levels', array_keys(static::LEVELS)); + $params = $route->get('params', []); + + $handler = $this->makeHandler($class, $filterLevels, $params); + $this->monolog->pushHandler($handler); + return $handler; + }); + + // $handler = new StreamHandler(storage_path('log/router/test.log')); + // $handler = $this->handlerDefaults($handler); + // $this->monolog->pushHandler($handler); + } + + protected function makeHandler($handler, $levels, $params) + { + $handler = app()->makeWith($handler, $params); + $handler = $this->handlerDefaults($handler); + + $levels = $this->makeLevels($levels); + return new FilterHandler($handler, $levels); + } + + protected function makeLevels($levels) + { + return collect($levels)->transform(function($level) { + return Arr::get(self::LEVELS, $level); + })->all(); + } + + /** + * By default set all handlers to the lowest log level as the dispatcher + * will handle the level allocations. + * + * @param HandlerInterface $handler + * + * @return HandlerInterface + */ + protected function handlerDefaults(HandlerInterface $handler) + { + $handler->setLevel(Monolog::DEBUG); + $handler->setBubble(true); + return $handler; + } + +} \ No newline at end of file diff --git a/src/Listeners/LogRouterAsync.php b/src/Listeners/LogRouterAsync.php new file mode 100644 index 0000000..154b571 --- /dev/null +++ b/src/Listeners/LogRouterAsync.php @@ -0,0 +1,13 @@ + [ + 'WebChefs\LogRouter\Listeners\LogRouter', + 'WebChefs\LogRouter\Listeners\LogRouterAsync', + ], + ]; + + /** + * List of Commands defined by this package. + * + * @var array + */ + protected $commands = [ + TestLog::class, + ]; + + /** + * Register the service provider. Register is called before Boot. + * + * @return void + */ + public function register() + { + // Register our commands with Artisan + $this->commands($this->commands); + + // Log Dispatcher singleton + // $this->app->singleton('Core\LogDispatcher\LogDispatcherContract', 'Core\LogDispatcher\LogDispatcher'); + + // Make available our config data. + $this->mergeConfigFrom(__DIR__ . '/Config.php', 'log_router'); + } + + /** + * All services provides have been registered. Publish the plug-in + * configuration and pass data to views. + */ + public function boot() + { + parent::boot(); + + // $events->listen('artisan.firing: migrate:*', function ($artisan, $input, $output) use ($events) { + // LogDispatcher::disable(); + // $events->forget('illuminate.log'); + // }); + + // $events->listen('artisan.firing: seed:*', function ($artisan, $input, $output) use ($events) { + // LogDispatcher::disable(); + // $events->forget('illuminate.log'); + // }); + + $this->publishes([ + __DIR__ . '/Config.php' => config_path('log_router.php') + ]); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + // public function provides() + // { + // return ['Core\LogDispatcher\LogDispatcherContract', 'LogDispatcherContract']; + // } + + /* + |-------------------------------------------------------------------------- + | Events List + |-------------------------------------------------------------------------- + | + | For reference purposes we list all Laravel Events based on some of the + | following references. + | + | Ref: + | - http://stackoverflow.com/questions/13059744/where-can-i-get-a-complete-list-of-laravel-events-fired-by-the-core-libaries + | - https://laracasts.com/discuss/channels/general-discussion/where-can-i-get-a-complete-list-of-laravel-5-events?page=1 + | + |-------------------------------------------------------------------------- + | + | laravel.log + | laravel.query + | laravel.resolving + | laravel.composing: {viewname} + | laravel.started: {bundlename} + | laravel.controller.factory + | laravel.config.loader + | laravel.language.loader + | laravel.view.loader + | laravel.view.engine + | laravel.done + | + | view.filter + | + | eloquent.saving + | eloquent.updated + | eloquent.created + | eloquent.saved + | eloquent.deleting + | eloquent.deleted + | + | $this->events->fire('auth.attempt', $payload); + | $this->events->fire('auth.login', [$user, $remember]); + | $this->events->fire('auth.logout', [$user]); + | $this->events->fire('cache.'.$event, $payload); + | $this->laravel['events']->fire('cache:clearing', [$storeName]); + | $this->laravel['events']->fire('cache:cleared', [$storeName]); + | $events->fire('artisan.start', [$this]); + | $this->events->fire('illuminate.query', array($query, $bindings, $time, $this->getName())); + | $this->events->fire('connection.'.$this->getName().'.'.$event, $this); + | $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]); + | $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); + | $this['events']->fire('locale.changed', array($locale)); + | $this['events']->fire($class = get_class($provider), array($provider)); //after provider registered. + | $this->app['events']->fire('kernel.handled', [$request, $response]); + | $this->dispatcher->fire('illuminate.log', compact('level', 'message', 'context')); + | $this->events->fire('mailer.sending', array($message)); + | $this->events->fire('illuminate.queue.failed', array($connection, $job, $data)); + | $this->events->fire('illuminate.queue.stopping'); + | $this->events->fire('router.matched', [$route, $request]); + | $this->events->fire('composing: '.$view->getName(), array($view)); + | $this->events->fire('creating: '.$view->getName(), array($view)); + */ +} \ No newline at end of file