diff --git a/README.md b/README.md index 0978880..d877b94 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Laravel Exception Notifications -An easy way to send emails with stack trace whenever an exception occurs on the server for Laravel applications. +An easy way to send Notifications via email and slack channels along with full stack trace whenever an exception occurs on the server for Laravel applications.  @@ -15,96 +15,114 @@ $ composer require squareboat/sneaker ``` ### Configure Laravel - -Once installation operation is complete, simply add the service provider to your project's `config/app.php` file: +Once installation operation is complete, simply add both the service provider and facade classes to your project's `config/app.php` file: #### Service Provider -``` + +```php SquareBoat\Sneaker\SneakerServiceProvider::class, ``` -### Add Sneaker's Exception Capturing +#### Facade +```php +'Sneaker' => SquareBoat\Sneaker\Facades\Sneaker::class, +``` + +### Add Sneaker's Exception Capturing Add exception capturing to `app/Exceptions/Handler.php`: ```php public function report(Exception $exception) { - app('sneaker')->captureException($exception); + if ($this->shouldReport($exception)) { + Sneaker::captureException($exception); + } parent::report($exception); } ``` -### Configuration File +### Configuration -Create the Sneaker configuration file with this command: +Create the Sneaker configuration file using this command: ```bash $ php artisan vendor:publish --provider="SquareBoat\Sneaker\SneakerServiceProvider" ``` -The config file will be published in `config/sneaker.php` +The config file will be published in `config/sneaker.php` Following are the configuration attributes used for the Sneaker. #### silent -The package comes with `'silent' => true,` configuration by default, since you probably don't want error emailing enabled on your development environment. Especially if you've set `'debug' => true,`. +The package comes with `'silent' => false,` configuration by default. It means that Sneaker is configured to send notifications when an exception occurs. ```php -'silent' => env('SNEAKER_SILENT', true), +'silent' => env('SNEAKER_SILENT', false), ``` - -For sending emails when an exception occurs set `SNEAKER_SILENT=false` in your `.env` file. - +To avoid sending notifications on your development environment set `SNEAKER_SILENT=true` in your `.env` file. #### capture -It contains the list of the exception types that should be captured. You can add your exceptions here for which you want to send error emails. +It contains the list of the exception types that should be captured. You can add your exceptions types here for which you want to send notifiactions. -By default, the package has included `Symfony\Component\Debug\Exception\FatalErrorException::class`. +By defautl we have `'*'` in the array, which means that we will capture all the exceptions that occurs in the application. ```php 'capture' => [ - Symfony\Component\Debug\Exception\FatalErrorException::class, + '*' ], ``` -You can also use `'*'` in the `$capture` array which will in turn captures every exception. +To explicitly list the exception types, remove `'*'` and define them as: ```php 'capture' => [ - '*' + Symfony\Component\Debug\Exception\FatalErrorException::class, + ... ], ``` -To use this feature you should add the following code in `app/Exceptions/Handler.php`: +#### notifications -```php -public function report(Exception $exception) -{ - if ($this->shouldReport($exception)) { - app('sneaker')->captureException($exception); - } +It lists the channels on which the notification will be delivered. Out of the box, Senaker supports `'mail'` and `'slack'` channels, and plan is to add more in future. - parent::report($exception); -} +```bash +'notifications' => [ + 'mail', + 'slack', +], +``` + +#### mail + +### to +The email address used to deliver the mail notification. + +```php +'mail' => [ + 'to' => [ + // 'your@email.com', + ], +], ``` -#### to +#### slack -This is the list of recipients of error emails. +### webhook_url +The webhook URL to which the slack notification should be delivered. Webhook URLs may be generated by adding an "Incoming Webhook" service to your Slack team. ```php -'to' => [ - // 'hello@example.com', +'slack' => [ + 'webhook_url' => env('SNEAKER_SLACK_WEBHOOK_URL'), ], ``` #### ignored_bots -This is the list of bots for which we should NOT send error emails. +This is the list of bots for which we should NOT send error notifications. ```php 'ignored_bots' => [ @@ -115,29 +133,67 @@ This is the list of bots for which we should NOT send error emails. ], ``` -## Customize +## Adding Context +Sometimes you may need more information for debugging when an exception occurs like which user got the excpetion, app version, etc... -If you need to customize the subject and body of email, run following command: +For that we can add some context as: -```bash -$ php artisan vendor:publish --provider="SquareBoat\Sneaker\SneakerServiceProvider" +### User Context +You can add user context to be send in each notification. + +```php +Sneaker::userContext(function() { + return [ + 'ID' => 10, + 'Name' => 'John Doe' + ]; +}); ``` -> Note - Don't run this command again if you have run it already. +### Extra Context +You can add extra context to be send in each notification. -Now the email's subject and body view are located in the `resources/views/vendor/sneaker` directory. +```php +Sneaker::extraContext(function() { + return [ + 'App' => 'Project X', + 'Version' => 'v3.0.0' + ]; +}); +``` -We have passed the thrown exception object `$exception` in the view which you can use to customize the view to fit your needs. +The best place to add them is in `report()` method of `app/Exceptions/Handler.php`: + +```php +public function report(Exception $exception) +{ + Sneaker::userContext(function() { + // return user context array + }); + + Sneaker::extraContext(function() { + // return extra context array + }); + + if ($this->shouldReport($exception)) { + Sneaker::captureException($exception); + } + + parent::report($exception); +} +``` ## Sneak ### Test your integration -To verify that Sneaker is configured correctly and our integration is working, use `sneaker:sneak` Artisan command: +To verify that Sneaker is configured correctly and your integration is working, use `sneaker:sneak` Artisan command: ```bash $ php artisan sneaker:sneak ``` -A `SquareBoat\Sneaker\Exceptions\DummyException` class will be thrown and captured by Sneaker. The captured exception will appear in your configured email immediately. +A `SquareBoat\Sneaker\Exceptions\DummyException` class will be thrown and captured by Sneaker. The captured exception will appear in your configured notifiaction channel immediately. + +You can also add the verbosity flags `-v/-vv/-vvv`. ## Security diff --git a/composer.json b/composer.json index 4266c78..4dc908c 100644 --- a/composer.json +++ b/composer.json @@ -12,17 +12,23 @@ ], "require": { "php": ">=5.4.0", + "guzzlehttp/guzzle": "^6.2", "illuminate/support": "5.3.*|5.4.*", - "illuminate/view": "5.3.*|5.4.*", "illuminate/config": "5.3.*|5.4.*", - "illuminate/mail": "5.3.*|5.4.*", + "illuminate/notifications": "5.3.*|5.4.*", "illuminate/log": "5.3.*|5.4.*", - "symfony/debug": "~3.1|~3.2" + "illuminate/console": "5.3.*|5.4.*", + "symfony/debug": "~3.1|~3.2", + "symfony/console": "~3.1|~3.2", + "nesbot/carbon": "~1.20" }, "autoload": { "psr-4": { "SquareBoat\\Sneaker\\": "src/" - } + }, + "files": [ + "src/helpers.php" + ] }, "minimum-stability": "dev" } diff --git a/config/sneaker.php b/config/sneaker.php index a8d3803..a5c8cf6 100644 --- a/config/sneaker.php +++ b/config/sneaker.php @@ -4,27 +4,46 @@ /* |-------------------------------------------------------------------------- - | Sends an email on Exception or be silent + | Sends a notification on Exception or be silent. |-------------------------------------------------------------------------- | | Should we email error traces? | */ - 'silent' => env('SNEAKER_SILENT', true), + 'silent' => env('SNEAKER_SILENT', false), /* |-------------------------------------------------------------------------- - | A list of the exception types that should be captured. + | A list of exception types that should be captured. |-------------------------------------------------------------------------- | - | For which exception class emails should be sent? + | For which exception type notification should be sent? | - | You can also use '*' in the array which will in turn captures every - | exception. + | By defautl we have set the array to '*', which means that we will capture + | all the exceptions that occurs in the application. To explicitly list + | the class define them below as: + | + | 'capture' => [ + | Symfony\Component\Debug\Exception\FatalErrorException::class, + | ], | */ 'capture' => [ - Symfony\Component\Debug\Exception\FatalErrorException::class, + '*' + ], + + /* + |-------------------------------------------------------------------------- + | Notification Delivery Channels + |-------------------------------------------------------------------------- + | + | The channels on which the notification will be delivered. + | + */ + + 'notifications' => [ + 'mail', + 'slack', ], /* @@ -32,12 +51,27 @@ | Error email recipients |-------------------------------------------------------------------------- | - | Email stack traces to these addresses. + | The email address used to deliver the notification. + | + */ + + 'mail' => [ + 'to' => [ + // 'your@email.com', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Slack Webhook Url + |-------------------------------------------------------------------------- + | + | The webhook URL to which the notification should be delivered. | */ - 'to' => [ - // 'hello@example.com', + 'slack' => [ + 'webhook_url' => env('SNEAKER_SLACK_WEBHOOK_URL'), ], /* @@ -45,7 +79,7 @@ | Ignore Crawler Bots |-------------------------------------------------------------------------- | - | For which bots should we NOT send error emails? + | For which bots should we NOT send error notifications? | */ 'ignored_bots' => [ diff --git a/resources/views/email/body.blade.php b/resources/views/email/body.blade.php index 944cd8c..4ae658b 100644 --- a/resources/views/email/body.blade.php +++ b/resources/views/email/body.blade.php @@ -12,22 +12,129 @@ .extra-info { background-color: #FFFFFF; padding: 15px 28px; + margin: 0 auto; margin-bottom: 20px; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; border: 1px solid #ccc; + width: 970px; } - {!! $css !!} + + .padding { + padding: 15px 28px; + } + + .extra-info .title { + color: #4674ca; + font-size: large; + font-family: Monaco,monospace; + border-bottom: 1px solid #ccc; + } + + .tags.no-margin { + margin-bottom: -10px; + } + .tags { + padding-left: 0; + list-style: none; + display: flex; + flex-wrap: wrap; + font-size: 13px; + } + .tags li { + white-space: nowrap; + margin: 0 10px 10px 0; + border-radius: 1px; + display: flex; + border: 1px solid #d0c9d7; + border-radius: 3px; + box-shadow: 0 1px 2px rgba(0,0,0,.04); + line-height: 1.2; + max-width: 100%; + } + .tags .key, .tags .value { + padding: 4px 8px; + min-width: 0; + white-space: nowrap; + } + .tags .value, .tags .value>a { + max-width: 100%; + text-overflow: ellipsis; + white-space: nowrap; + } + .tags .key { + font-family:inherit; + } + .tags .value { + color: #4674ca; + background: #fbfbfc; + border-left: 1px solid #d8d2de; + border-radius: 0 3px 3px 0; + font-family: Monaco,monospace; + } + .tags .key, .tags .value { + padding: 4px 8px; + min-width: 0; + white-space: nowrap; + } + + {!! $report->getHtmlStylesheet() !!}
- {!! $content !!} -