diff --git a/CHANGELOG.md b/CHANGELOG.md index c8cd9df..ce878a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,25 @@ # Changelog -All notable changes to `laravel-log-mailer` will be documented in this file +All notable changes to `laravel-mail-log-channel` will be documented in this file. + +## 2.0.1 - 2020-02-21 + +- support multiple `to` configuration formats + +## 2.0.0 - 2020-01-29 + +- add support for Laravel 6 and 7 (thanks to @jbeales https://github.com/designmynight/laravel-log-mailer/pull/7) +- remove extra configuration and view files +- improve exception layout in mails ## 1.0.2 - 2018-09-09 + - fix logging levels ## 1.0.1 - 2018-09-05 + - fix dependancy ## 1.0.0 - 2018-09-04 -- initial release \ No newline at end of file + +- initial release diff --git a/README.md b/README.md index 7b14a7c..b2c6690 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,123 @@ -Laravel Mail Logger -=============== +# Laravel Mail Log Channel -[![Latest Stable Version](http://img.shields.io/github/release/designmynight/laravel-log-mailer.svg)](https://packagist.org/packages/designmynight/laravel-log-mailer) [![Total Downloads](http://img.shields.io/packagist/dm/designmynight/laravel-log-mailer.svg)](https://packagist.org/packages/designmynight/laravel-log-mailer) -[![StyleCI](https://github.styleci.io/repos/147424037/shield?branch=master)](https://github.styleci.io/repos/147424037) + +[![Latest Stable Version](https://img.shields.io/github/v/release/shaffe-fr/laravel-mail-log-channel.svg)](https://packagist.org/packages/shaffe/laravel-mail-log-channel) [![Total Downloads](https://img.shields.io/packagist/dt/shaffe/laravel-mail-log-channel.svg)](https://packagist.org/packages/shaffe/laravel-mail-log-channel) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -A service provider to add support for logging via email using Laravels built-in mail provider +A service provider to add support for logging via email using Laravels built-in mail provider. + +This package is a fork of [laravel-log-mailer](https://packagist.org/packages/designmynight/laravel-log-mailer) by Steve Porter. ![image](https://user-images.githubusercontent.com/12199424/45576336-a93c1300-b86e-11e8-9575-d1e4c5ed5dec.png) +## Table of contents -Table of contents ------------------ * [Installation](#installation) * [Configuration](#configuration) -Installation ------------- +## Installation -Installation using composer: +You can install this package via composer using this commande: ```sh -composer require designmynight/laravel-log-mailer +composer require shaffe/laravel-mail-log-channel ``` -### Laravel version Compatibility +### Laravel version compatibility Laravel | Package | :---------|:--------| - 5.6.x | 1.0.x | - -And add the service provider in `config/app.php`: + 7.x | ^2.0 | + 6.x | ^2.0 | + 5.6.x | ^1.0 | -```php -DesignMyNight\Laravel\Logging\MailableLogServiceProvider::class, -``` +The package will automatically register itself if you use Laravel. For usage with [Lumen](http://lumen.laravel.com), add the service provider in `bootstrap/app.php`. ```php -$app->register(DesignMyNight\Laravel\Logging\MailableLogServiceProvider::class); +$app->register(Shaffe\MailLogChannel\MailLogChannelServiceProvider::class); ``` -Configuration ------------- +## Configuration -Most configuration options can be automatically populated by environment variables or in config/mailablelog.php, to generate it run php artisan vendor:publish. +To ensure all unhandled exceptions are mailed: -To ensure all unhandled exceptions are mailed, set up a mail logging channel and add it to your logging stack in config/logging.php: +1. create a `mail` logging channel in `config/logging.php`, +2. add this `mail` channel to your current logging stack, +3. add a `LOG_MAIL_ADDRESS` to your `.env` file to define the recipient. + +You can specify multiple channels and individually change the recipients, the subject and the email template. ```php 'channels' => [ 'stack' => [ 'driver' => 'stack', - // Add mail to the stack: + // 2. Add mail to the stack: 'channels' => ['single', 'mail'], ], // ... - // Create a mail logging channel: + // 1. Create a mail logging channel: 'mail' => [ 'driver' => 'mail', - // Specify who to mail the log to + 'level' => env('LOG_MAIL_LEVEL', 'notice'), + + // Specify mail recipient 'to' => [ [ - 'address' => 'errors@designmynight.com', - 'name' => 'Error' - ] + 'address' => env('LOG_MAIL_ADDRESS'), + 'name' => 'Error', + ], ], - // Optionally specify who the log mail was sent by - // This is overidable in config/mailablelog.php and - // falls back to your global from in config/mail.php + 'from' => [ - 'address' => 'errors@designmynight.com', + // Defaults to config('mail.from.address') + 'address' => env('LOG_MAIL_ADDRESS'), + // Defaults to config('mail.from.name') 'name' => 'Errors' ], + + // Optionally overwrite the subject format pattern + // 'subject_format' => env('LOG_MAIL_SUBJECT_FORMAT', '[%datetime%] %level_name%: %message%'), + // Optionally overwrite the mailable template + // Two variables are sent to the view: `string $content` and `array $records` // 'mailable' => NewLogMailable::class ], ], ``` -You can specify multiple channels and change the recipients and customise the email template per channel. +### Recipients configuration format + +The following `to` config formats are supported: + +* single email address: + + ```php + 'to' => env('LOG_MAIL_ADDRESS', ''), + ``` + +* array of email addresses: + + ```php + 'to' => explode(',', env('LOG_MAIL_ADDRESS', '')), + ``` + +* associative array of email => name addresses: + + ```php + 'to' => [env('LOG_MAIL_ADDRESS', '') => 'Error'],` + ``` + +* array of email and name: + ```php + 'to' => [ + [ + 'address' => env('LOG_MAIL_ADDRESS', ''), + 'name' => 'Error', + ], + ], + ``` diff --git a/composer.json b/composer.json index e0cc2fb..60fd1e2 100644 --- a/composer.json +++ b/composer.json @@ -1,24 +1,36 @@ { - "name": "designmynight/laravel-log-mailer", + "name": "shaffe/laravel-mail-log-channel", "description": "A package to support logging via email in Laravel", - "homepage": "https://github.com/designmynight/laravel-log-mailer", + "homepage": "https://github.com/shaffe-fr/laravel-mail-log-channel", "license": "MIT", "keywords": [ "laravel", - "laravel-logging", + "logging", + "mail channel", "laravel-log-mailer", "monolog", - "designmynight" + "laravel-mail-log-channel", + "shaffe" ], "require": { - "illuminate/support": "^5.6" + "illuminate/bus": "^5.6|^6.0|^7.0", + "illuminate/contracts": "^5.6|^6.0|^7.0", + "illuminate/log": "^5.6|^6.0|^7.0", + "illuminate/mail": "^5.6|^6.0|^7.0", + "illuminate/queue": "^5.6|^6.0|^7.0", + "illuminate/support": "^5.6|^6.0|^7.0" }, "autoload": { "psr-4": { - "DesignMyNight\\Laravel\\": "src" + "Shaffe\\MailLogChannel\\": "src" } }, "authors": [ + { + "name": "Karel FAILLE", + "email": "shaffe.fr@gmail.com", + "role": "Developer" + }, { "name": "Steve Porter", "email": "steve@designmynight.com", @@ -28,7 +40,7 @@ "extra": { "laravel": { "providers": [ - "DesignMyNight\\Laravel\\Logging\\MailableLogServiceProvider" + "Shaffe\\MailLogChannel\\MailLogChannelServiceProvider" ] } } diff --git a/config/mailablelog.php b/config/mailablelog.php deleted file mode 100644 index a9c1990..0000000 --- a/config/mailablelog.php +++ /dev/null @@ -1,28 +0,0 @@ - env('MAILABLE_LOG_SUBJECT_FORMAT', '[%datetime%] %level_name%: %message%'), - - /* - |-------------------------------------------------------------------------- - | From information - |-------------------------------------------------------------------------- - | - | Set default from information of your mailables. The from information - | falls back to your mail config. - | - */ - 'from' => [ - 'address' => env('MAILABLE_LOG_FROM_ADDRESS'), - 'name' => env('MAILABLE_LOG_FROM_NAME'), - ], -]; diff --git a/resources/views/log.blade.php b/resources/views/log.blade.php deleted file mode 100644 index 2702b2f..0000000 --- a/resources/views/log.blade.php +++ /dev/null @@ -1,5 +0,0 @@ -@component('mail::message') - -{!!$content!!} - -@endcomponent diff --git a/src/Logging/Driver/MailableLogger.php b/src/Logging/Driver/MailableLogger.php index a31008e..c69ae2e 100644 --- a/src/Logging/Driver/MailableLogger.php +++ b/src/Logging/Driver/MailableLogger.php @@ -20,7 +20,10 @@ class MailableLogger */ public function __invoke(array $config) { - $this->config = $config; + $this->config = array_merge([ + 'level' => Logger::DEBUG, + 'bubble' => true + ], $config ); $mailHandler = new MailableHandler( $this->buildMailable(), diff --git a/src/Logging/MailableLogServiceProvider.php b/src/Logging/MailableLogServiceProvider.php index d4a1a7b..64d93b7 100644 --- a/src/Logging/MailableLogServiceProvider.php +++ b/src/Logging/MailableLogServiceProvider.php @@ -66,7 +66,6 @@ protected function setupViews(Container $app) public function register() { if ($this->app['log'] instanceof LogManager) { - $this->loadViewsFrom(base_path('designmynight/resources/views'), 'mailablelog'); $this->app['log']->extend('mail', function (Container $app, array $config) { $logger = new MailableLogger(); diff --git a/src/Logging/Monolog/Handlers/MailableHandler.php b/src/Logging/Monolog/Handlers/MailableHandler.php index d6c1de1..c239b96 100644 --- a/src/Logging/Monolog/Handlers/MailableHandler.php +++ b/src/Logging/Monolog/Handlers/MailableHandler.php @@ -19,7 +19,7 @@ class MailableHandler extends MailHandler * * @return void */ - public function __construct(Mailable $mailable, LineFormatter $subjectFormatter, $level = Logger::DEBUG, $bubble = true) + public function __construct(Mailable $mailable, LineFormatter $subjectFormatter, int $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); $this->mailer = app()->make('mailer'); @@ -42,7 +42,7 @@ protected function setSubject(array $records) /** * {@inheritdoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records): void { $this->mailable->with([ 'content' => $content, diff --git a/src/Logging/Mail/Log.php b/src/Mail/Log.php similarity index 60% rename from src/Logging/Mail/Log.php rename to src/Mail/Log.php index a32cf79..387ad6a 100644 --- a/src/Logging/Mail/Log.php +++ b/src/Mail/Log.php @@ -1,10 +1,11 @@ markdown('mailablelog::log'); + return $this->markdown('mail::message', ['slot' => new HtmlString($this->viewData['content'] ?? '')]); } } diff --git a/src/MailLogChannelServiceProvider.php b/src/MailLogChannelServiceProvider.php new file mode 100644 index 0000000..9789373 --- /dev/null +++ b/src/MailLogChannelServiceProvider.php @@ -0,0 +1,25 @@ +app['log'] instanceof LogManager) { + $this->app['log']->extend('mail', function ($app, array $config) { + $logger = new MailLogger(); + + return $logger($config); + }); + } + } +} diff --git a/src/MailLogger.php b/src/MailLogger.php new file mode 100644 index 0000000..769ac92 --- /dev/null +++ b/src/MailLogger.php @@ -0,0 +1,152 @@ +config = array_merge( + ['level' => Logger::DEBUG, 'bubble' => true], + $config + ); + + $mailHandler = new MailableHandler( + $this->buildMailable(), + $this->subjectFormatter(), + $this->config('level'), + $this->config('bubble') + ); + + $mailHandler->setFormatter(new HtmlFormatter()); + + return new Logger('mailable', [$mailHandler]); + } + + /** + * Create the mailable log. + * + * @return \Illuminate\Contracts\Mail\Mailable + */ + protected function buildMailable(): Mailable + { + $mailableClass = $this->config('mailable') ?? MailableLog::class; + /** @var \Illuminate\Contracts\Mail\Mailable $mailable */ + $mailable = new $mailableClass(); + + if (! ($recipients = $this->buildRecipients())) { + throw new InvalidArgumentException('"To" address is required. Please check the `to` driver\'s logging config.'); + } + + $mailable->to($recipients); + + if (! $this->defaultFromAddress() && ! isset($this->config('from')['address'])) { + throw new InvalidArgumentException('"From" address is required. Please check the `from.address` driver\'s config and the `mail.from.address` config.'); + } + + $mailable->from( + $this->config('from')['address'] ?? $this->defaultFromAddress(), + $this->config('from')['name'] ?? $this->defaultFromName() + ); + + return $mailable; + } + + protected function buildRecipients(): array + { + if (! ($to = $this->config('to'))) { + return []; + } + + $recipients = []; + foreach ((array)$to as $emailOrIndex => $nameOrEmail) { + if (is_array($nameOrEmail)) { + $email = $nameOrEmail['email'] ?? $nameOrEmail['address'] ?? null; + if ($email) { + $recipients[] = [ + 'email' => $email, + 'name' => $nameOrEmail['name'] ?? null, + ]; + } + } elseif (is_string($emailOrIndex)) { + $recipients[] = [ + 'email' => $emailOrIndex, + 'name' => $nameOrEmail, + ]; + } elseif (is_string($nameOrEmail)) { + $recipients[] = [ + 'email' => $nameOrEmail, + 'name' => null, + ]; + } + } + + return $recipients; + } + + /** + * Get the default from address. + * + * @return string + */ + protected function defaultFromAddress(): ?string + { + return config('mail.from.address'); + } + + /** + * Get the default from name. + * + * @return string + */ + protected function defaultFromName(): ?string + { + return config('mail.from.name'); + } + + /** + * Get the subject formatter. + * + * @return \Monolog\Formatter\LineFormatter + */ + protected function subjectFormatter(): LineFormatter + { + $format = $this->config('subject_format') ?? '[%datetime%] %level_name%: %message%'; + + return new LineFormatter($format); + } + + /** + * Get the value from the passed in config. + * + * @param string $field + * + * @return mixed + */ + private function config(string $field) + { + return $this->config[$field] ?? null; + } +} diff --git a/src/Monolog/Formatters/HtmlFormatter.php b/src/Monolog/Formatters/HtmlFormatter.php new file mode 100644 index 0000000..63cc40f --- /dev/null +++ b/src/Monolog/Formatters/HtmlFormatter.php @@ -0,0 +1,17 @@ + ' '