Skip to content

Commit

Permalink
Add package source with tests (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
stasadev committed Jul 2, 2023
1 parent 13de7f8 commit 26f2f6a
Show file tree
Hide file tree
Showing 16 changed files with 1,051 additions and 0 deletions.
178 changes: 178 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,185 @@
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct-single.svg)](https://stand-with-ukraine.pp.ua)

# Laravel Slack Notifier

[![Latest Version on Packagist](https://img.shields.io/packagist/v/stasadev/laravel-slack-notifier.svg?style=flat-square)](https://packagist.org/packages/stasadev/laravel-slack-notifier)
[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/stasadev/laravel-slack-notifier/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/stasadev/laravel-slack-notifier/actions?query=workflow%3Arun-tests+branch%3Amain)
[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/stasadev/laravel-slack-notifier/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/stasadev/laravel-slack-notifier/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/stasadev/laravel-slack-notifier.svg?style=flat-square)](https://packagist.org/packages/stasadev/laravel-slack-notifier)

Send exceptions and dump variables to Slack.

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

SlackNotifier::send(new \RuntimeException('Test exception'));
SlackNotifier::send('Test message');
```

## Installation

Install the package via composer:

```bash
composer require stasadev/laravel-slack-notifier
```

All env variables used by this package (only `LOG_SLACK_WEBHOOK_URL` is required):

```dotenv
APP_NAME=Laravel
LOG_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/ABC
LOG_SLACK_CHANNEL=
LOG_SLACK_EMOJI=:boom:
LOG_SLACK_CACHE_SECONDS=0
CACHE_DRIVER=file
```

How to get a webhook URL [in the Slack API docs](https://api.slack.com/messaging/webhooks).

To temporarily disable all logging, simply comment out `LOG_SLACK_WEBHOOK_URL` or set it to an empty string or `null`.

Optionally publish the [config](./config/slack-notifier.php) file with:

```bash
php artisan vendor:publish --tag="slack-notifier"
```

## Usage

To send a message to Slack, simply call `SlackNotifier::send()`.

## Report Exception

```php
// In Laravel 8.x and later
// app/Exceptions/Handler.php
public function register(): void
{
$this->reportable(function (Throwable $e) {
\Stasadev\SlackNotifier\Facades\SlackNotifier::send($e);
});
}

// In Laravel 5.7.x, 5.8.x, 6.x, 7.x
// app/Exceptions/Handler.php
public function report(Throwable $exception)
{
if ($this->shouldReport($exception) {
\Stasadev\SlackNotifier\Facades\SlackNotifier::send($exception);
}

parent::report($exception);
}
```

## Dump Variable

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

$variable = 'message';
// $variable = ['test' => 'array'];
// $variable = new stdClass();

SlackNotifier::send($variable);
```

## Using multiple webhooks

Use an alternative webhook, by specify extra ones in the config file.

```php
// config/slack-notifier.php

'webhook_urls' => [
'default' => 'https://hooks.slack.com/services/ABC',
'testing' => 'https://hooks.slack.com/services/DEF',
],
```

The webhook to be used can be chosen using the `to` function.

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

SlackNotifier::to('testing')->send('Test message');
```

### Using a custom webhooks

The `to` function also supports custom webhook URLs.

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

SlackNotifier::to('https://custom-url.com')->send('Test message');
```

## Sending message to another channel

You can send a message to a channel (use `LOG_SLACK_CHANNEL`) other than the default one for the webhook, by passing it to the `channel` function.

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

SlackNotifier::channel('reminders')->send('Test message');
```

## Slack bot customizing

Use `username` (use `APP_NAME`) and `emoji` (use `LOG_SLACK_EMOJI`) to make your messages unique, or override them right before sending.

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

SlackNotifier::username('My Laravel Bot')->emoji(':tada:')->send('Test message');
```

### Formatting

Extend the default `Stasadev\SlackNotifier\SlackNotifierFormatter::class` to format the messages however you like. Then simply replace the `formatter` key in the configuration file.

```php
// config/slack-notifier.php

'formatter' => App\Formatters\CustomSlackNotifierFormatter::class,
```

### Additional context in the message

Include additional `context` in a Slack message (use `dont_flash` to exclude sensitive info from `context`). It will be added as an attachment.

### Exception stack trace filtering

Stack traces for exceptions in Laravel usually contain many lines, including framework files. Usually, you are only interested in tracking exception details in the application files.
You can filter it out with the `dont_trace` config option.

### Caching the same exceptions

Sometimes a large group of exceptions is thrown, and you don't want to log each of them because they are the same.

Use `LOG_SLACK_CACHE_SECONDS` (uses Laravel `CACHE_DRIVER` under the hood) to suppress output for X seconds, or pass it to the `cacheSeconds` function.

```php
use Stasadev\SlackNotifier\Facades\SlackNotifier;

SlackNotifier::cacheSeconds(60)->send(new \RuntimeException('Test exception'));
```

## Testing

```bash
composer test
```

## Credits

Inspired by [spatie/laravel-slack-alerts](https://github.com/spatie/laravel-slack-alerts).

- [Stanislav Zhuk](https://github.com/stasadev)
- [All Contributors](../../contributors)

## License

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
62 changes: 62 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"name": "stasadev/laravel-slack-notifier",
"description": "Send exceptions and dump variables to Slack",
"license": "MIT",
"type": "library",
"keywords": [
"laravel",
"notifications",
"slack"
],
"authors": [
{
"name": "Stanislav Zhuk",
"email": "stanislav.zhuk.work@gmail.com",
"role": "Developer"
}
],
"homepage": "https://github.com/stasadev/laravel-slack-notifier",
"require": {
"php": "^7.1.3 || ^8.0",
"ext-json": "*",
"laravel/slack-notification-channel": "^1.0 || ^2.0",
"monolog/monolog": "^1.12 || ^2.0 || ^3.0",
"symfony/polyfill-php80": "^1.20"
},
"require-dev": {
"laravel/pint": "^1.0",
"orchestra/testbench": "^8.0",
"pestphp/pest-plugin-laravel": "^2.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"Stasadev\\SlackNotifier\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Stasadev\\SlackNotifier\\Tests\\": "tests/"
}
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
},
"sort-packages": true
},
"extra": {
"laravel": {
"providers": [
"Stasadev\\SlackNotifier\\SlackNotifierServiceProvider"
]
}
},
"scripts": {
"post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi",
"format": "vendor/bin/pint",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage"
}
}
65 changes: 65 additions & 0 deletions config/slack-notifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

return [
/*
* Slack incoming webhook URLs.
*/
'webhook_urls' => [
'default' => env('LOG_SLACK_WEBHOOK_URL'),
],

/*
* Override the Slack channel to which the message will be sent.
*/
'channel' => env('LOG_SLACK_CHANNEL'),

/*
* The name of the Slack bot.
*/
'username' => env('APP_NAME', 'Laravel Log'),

/*
* The emoji used for the Slack bot.
*/
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),

/*
* An exception can be triggered several times in a row.
* We can use the Laravel cache to suppress the same exception for "x" seconds.
*/
'cache_seconds' => env('LOG_SLACK_CACHE_SECONDS', 0),

/*
* A formatter for Slack message.
*/
'formatter' => Stasadev\SlackNotifier\SlackNotifierFormatter::class,

/*
* Add context for the Slack message. Possible values:
* 'get', 'post', 'request', 'headers', 'files', 'cookie', 'session', 'server'
*/
'context' => [
'get',
'post',
'cookie',
'session',
],

/*
* The list of the values from context that are never flashed to Slack.
*/
'dont_flash' => [
'current_password',
'password',
'password_confirmation',
],

/*
* Lines containing any of these strings will be excluded from exceptions.
*/
'dont_trace' => [
'/vendor/symfony/',
'/vendor/laravel/framework/',
'/vendor/barryvdh/laravel-debugbar/',
],
];
38 changes: 38 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd"
backupGlobals="false"
bootstrap="vendor/autoload.php"
colors="true"
processIsolation="false"
stopOnFailure="false"
executionOrder="random"
failOnWarning="true"
failOnRisky="true"
failOnEmptyTestSuite="true"
beStrictAboutOutputDuringTests="true"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
>
<testsuites>
<testsuite name="Stasadev Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage>
<report>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
<clover outputFile="build/logs/clover.xml"/>
</report>
</coverage>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
<source>
<include>
<directory suffix=".php">./src</directory>
</include>
</source>
</phpunit>
39 changes: 39 additions & 0 deletions src/Config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Stasadev\SlackNotifier;

use Stasadev\SlackNotifier\Exceptions\FormatterClassDoesNotExist;
use Stasadev\SlackNotifier\Exceptions\WebhookUrlNotValid;

class Config
{
public static function getFormatter(array $arguments = []): SlackNotifierFormatter
{
$formatterClass = config('slack-notifier.formatter');

if (is_null($formatterClass) || ! class_exists($formatterClass)) {
throw FormatterClassDoesNotExist::make($formatterClass);
}

return app($formatterClass, $arguments);
}

public static function getWebhookUrl(string $name): ?string
{
if (filter_var($name, FILTER_VALIDATE_URL)) {
return $name;
}

$url = config("slack-notifier.webhook_urls.{$name}");

if (! $url) {
return null;
}

if (filter_var($url, FILTER_VALIDATE_URL) === false) {
throw WebhookUrlNotValid::make($name, $url);
}

return $url;
}
}

0 comments on commit 26f2f6a

Please sign in to comment.