antonioribeiro / health

Laravel Health Panel
BSD 3-Clause "New" or "Revised" License
1.94k stars 198 forks source link

Does this work with SMS/Nexmo? #147

Open elliotlings opened 5 years ago

elliotlings commented 5 years ago

Can this send SMS message notifications? I'm struggling to get it working.

antonioribeiro commented 5 years ago

Never tested it with SMS, but it uses Laravel's notification system, so it should be at least compatible with Nexmo. How are you configuring it?

'channels' => ['mail', 'slack'],

'notifier' => 'PragmaRX\Health\Notifications',
elliotlings commented 5 years ago

I'm getting this error, L5.5.

[2019-03-19 16:19:28] local.ERROR: call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\Foundation\Application' does not have a method 'send' {"exception":"[object] (ErrorException(code: 0): call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\\Foundation\\Application' does not have a method 'send' at /var/www/html/vendor/pragmarx/health/src/Notifications/HealthStatus.php:87)
[stacktrace]
#0 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError(2, 'call_user_func_...', '/var/www/html/v...', 87, Array)
#1 /var/www/html/vendor/pragmarx/health/src/Notifications/HealthStatus.php(87): call_user_func_array(Array, Array)
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/Channels/NexmoSmsChannel.php(51): PragmaRX\\Health\\Notifications\\HealthStatus->__call('toNexmo', Array)
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php(113): Illuminate\\Notifications\\Channels\\NexmoSmsChannel->send(Object(App\\User), Object(PragmaRX\\Health\\Notifications\\HealthStatus))
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php(89): Illuminate\\Notifications\\NotificationSender->sendToNotifiable(Object(App\\User), '9c049c6f-1a22-4...', Object(PragmaRX\\Health\\Notifications\\HealthStatus), 'nexmo')
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php(64): Illuminate\\Notifications\\NotificationSender->sendNow(Object(Illuminate\\Support\\Collection), Object(PragmaRX\\Health\\Notifications\\HealthStatus))
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/ChannelManager.php(35): Illuminate\\Notifications\\NotificationSender->send(Object(Illuminate\\Support\\Collection), Object(PragmaRX\\Health\\Notifications\\HealthStatus))
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(221): Illuminate\\Notifications\\ChannelManager->send(Object(Illuminate\\Support\\Collection), Object(PragmaRX\\Health\\Notifications\\HealthStatus))
#8 /var/www/html/vendor/pragmarx/health/src/Listeners/NotifyHealthIssue.php(42): Illuminate\\Support\\Facades\\Facade::__callStatic('send', Array)
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Collection.php(339): PragmaRX\\Health\\Listeners\\NotifyHealthIssue->PragmaRX\\Health\\Listeners\\{closure}(Object(PragmaRX\\Health\\Support\\Target), 0)
#10 /var/www/html/vendor/pragmarx/health/src/Listeners/NotifyHealthIssue.php(45): Illuminate\\Support\\Collection->each(Object(Closure))
#11 [internal function]: PragmaRX\\Health\\Listeners\\NotifyHealthIssue->handle(Object(PragmaRX\\Health\\Events\\RaiseHealthIssue))
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(369): call_user_func_array(Array, Array)
#13 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(200): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}('PragmaRX\\\\Health...', Array)
#14 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php(465): Illuminate\\Events\\Dispatcher->dispatch('PragmaRX\\\\Health...')
#15 /var/www/html/vendor/pragmarx/health/src/Support/Resource.php(245): event(Object(PragmaRX\\Health\\Events\\RaiseHealthIssue))
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Collection.php(339): PragmaRX\\Health\\Support\\Resource->PragmaRX\\Health\\Support\\{closure}('nexmo', 1)
#17 /var/www/html/vendor/pragmarx/health/src/Support/Resource.php(249): Illuminate\\Support\\Collection->each(Object(Closure))
#18 /var/www/html/vendor/pragmarx/health/src/Support/Resource.php(230): PragmaRX\\Health\\Support\\Resource->sendNotifications()
#19 /var/www/html/vendor/pragmarx/health/src/Support/Resource.php(189): PragmaRX\\Health\\Support\\Resource->notify()
#20 /var/www/html/vendor/pragmarx/health/src/Support/ResourceChecker.php(124): PragmaRX\\Health\\Support\\Resource->check('check')
#21 /var/www/html/vendor/pragmarx/health/src/Support/Cache.php(127): PragmaRX\\Health\\Support\\ResourceChecker->PragmaRX\\Health\\Support\\{closure}()
#22 /var/www/html/vendor/pragmarx/health/src/Support/ResourceChecker.php(125): PragmaRX\\Health\\Support\\Cache->remember('elasticsearch-c...', Object(Closure))
#23 /var/www/html/vendor/pragmarx/health/src/Support/ResourceChecker.php(93): PragmaRX\\Health\\Support\\ResourceChecker->checkResource(Object(PragmaRX\\Health\\Support\\Resource))
#24 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Collection.php(339): PragmaRX\\Health\\Support\\ResourceChecker->PragmaRX\\Health\\Support\\{closure}(Object(PragmaRX\\Health\\Support\\Resource), 'ElasticsearchCo...')
#25 /var/www/html/vendor/pragmarx/health/src/Support/ResourceChecker.php(94): Illuminate\\Support\\Collection->each(Object(Closure))
#26 /var/www/html/vendor/pragmarx/health/src/Service.php(42): PragmaRX\\Health\\Support\\ResourceChecker->checkResources(false)
#27 /var/www/html/vendor/pragmarx/health/src/Service.php(87): PragmaRX\\Health\\Service->checkResources()
#28 /var/www/html/vendor/pragmarx/health/src/Commands.php(79): PragmaRX\\Health\\Service->PragmaRX\\Health\\{closure}()
#29 /var/www/html/vendor/pragmarx/health/src/Console/Commands/HealthCheckCommand.php(29): PragmaRX\\Health\\Commands->check(Object(PragmaRX\\Health\\Console\\Commands\\HealthCheckCommand))
#30 [internal function]: PragmaRX\\Health\\Console\\Commands\\HealthCheckCommand->handle(Object(PragmaRX\\Health\\Commands))
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(29): call_user_func_array(Array, Array)
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Illuminate\\Foundation\\Application), Array, Object(Closure))
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(549): Illuminate\\Container\\BoundMethod::call(Object(Illuminate\\Foundation\\Application), Array, Array, NULL)
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(183): Illuminate\\Container\\Container->call(Array)
#36 /var/www/html/vendor/symfony/console/Command/Command.php(255): Illuminate\\Console\\Command->execute(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle))
#37 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(170): Symfony\\Component\\Console\\Command\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle))
#38 /var/www/html/vendor/symfony/console/Application.php(948): Illuminate\\Console\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#39 /var/www/html/vendor/symfony/console/Application.php(250): Symfony\\Component\\Console\\Application->doRunCommand(Object(PragmaRX\\Health\\Console\\Commands\\HealthCheckCommand), Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#40 /var/www/html/vendor/symfony/console/Application.php(148): Symfony\\Component\\Console\\Application->doRun(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#41 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(88): Symfony\\Component\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#42 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(121): Illuminate\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#43 /var/www/html/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#44 {main}
"} 
elliotlings commented 5 years ago

I have managed to get around this but it has been a bit hacky.

I updated config/health/config.php notifications.channels with these additions:

'notifications' => [

    ...

    'channels' => [
        'mail',
        'nexmo',
        'nexmo' => [
            'sender' => \App\Health\SMSNotification::class,
        ],
    ],

    ...

],

Added a new class:

<?php
namespace App\Health;

use Illuminate\Notifications\Messages\NexmoMessage;

class SMSNotification
{
    public function send($notifiable, $item)
    {
        return (new NexmoMessage())
            ->content($item->getMessage());
    }
}

This provides the ability for the sending of SMS notifications. It will error on one of the channels, but there is no way around this due to the way it works.

I also added my own listener so I can loop through the users in my database:

<?php
namespace App\Health;

use Illuminate\Support\Facades\Notification;
use PragmaRX\Health\Events\RaiseHealthIssue;
use PragmaRX\Health\Notifications\HealthStatus;

class Listener
{
    /**
     * @return static
     */
    private function getNotifiableUsers()
    {
        $users = $model = instantiate(
            config('health.notifications.users.model')
        )->all();

        return $users;
    }

    /**
     * Handle the event.
     *
     * @param  RaiseHealthIssue  $event
     * @return void
     */
    public function handle(RaiseHealthIssue $event)
    {
        try {
            $event->failure->targets->each(function ($target) use ($event) {
                if (! $target->result->healthy) {
                    Notification::send(
                        $this->getNotifiableUsers(),
                        new HealthStatus($target, $event->channel)
                    );
                }
            });
        } catch (\Exception $exception) {
            report($exception);
        } catch (\Throwable $error) {
            report($error);
        }
    }
}

I think it would help a lot if the methods in the service provider were of protected visibility to make it easier to extend.