Search code examples
phplaravelslack

Laravel Logging to Slack via a Proxy


I have configured my Laravel app running the Laravel 5.7.5 PHP Framework to send error notifications to a Slack channel. A snippet of my config/logging.php file looks as follows:

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => (env('APP_ENV') == 'production') ? ['single', 'slack'] : ['single'],
    ],

    'single' => [
        'driver' => 'single',
        'path' => storage_path('logs/laravel.log'),
        'level' => 'debug',
    ],

    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => 'debug',
        'days' => 7,
    ],

    'slack' => [
        'driver' => 'slack',
        'url' => env('LOG_SLACK_WEBHOOK_URL'),
        'username' => 'Laravel Log',
        'emoji' => ':boom:',
        'level' => 'error',
    ],

This works fine when I'm connected to the public internet (not via a proxy server), but my production servers need to send the requests via a Squid proxy server, and the requests are timing out.

How do I go about specifying a proxy server for the Slack Webhook to ensure that my requests are routed through the proxy server and get sent to the Slack API?


Solution

  • I understand that quite a lot of time has passed, but I ran into a similar problem, perhaps the material found may be useful to someone.

    Judging by the source code of the library https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/SlackWebhookHandler.php

    Currently, the current implementation cannot specify a proxy.

    But you can define a custom-type logger. Here in this article is written in detail how to do it. https://medium.com/binarcode/laravel-5-6-custom-monolog-channel-to-store-logs-in-mariadb-23da52f537e7

    I did it like this:

    //config/logging.php
    'default' => env('LOG_CHANNEL', 'custom'),
    ....
    'custom' => [
            'driver' => 'custom',
            'via' => App\Extensions\SlackCustomLogger::class,
            'level' => 'debug',
            'url' => env('SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
        ],
    ...
    
    <?php
    
    namespace App\Extensions;
    
    use Monolog\Logger;
    
    class SlackCustomLogger
    {
        /**
         * Create a custom Monolog instance.
         *
         * @param  array  $config
         * @return \Monolog\Logger
         */
        public function __invoke(array $config)
        {
            $logger = new Logger('custom');
            $logger->pushHandler(new CustomSlackLogHandler(
                $config['url'],
                $config['channel'] ?? null,
                $config['username'] ?? 'Laravel',
                $config['attachment'] ?? true,
                $config['emoji'] ?? ':boom:',
                $config['short'] ?? false,
                $config['context'] ?? true,
                $config['level'] ?? 'debug'
            ));
            return $logger;
        }
    }
    
    <?php
    
    namespace App\Extensions;
    
    
    use Monolog\Handler\Curl\Util;
    use Monolog\Handler\SlackWebhookHandler;
    
    class CustomSlackLogHandler extends SlackWebhookHandler
    {
        protected function write(array $record)
        {
            $postData = $this->getSlackRecord()->getSlackData($record);
            $postString = json_encode($postData);
    
            $ch = curl_init();
            $options = array(
                CURLOPT_URL => $this->getWebhookUrl(),
                CURLOPT_POST => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_HTTPHEADER => array('Content-type: application/json'),
                CURLOPT_POSTFIELDS => $postString
            );
    
            if(getenv('PROXY', false)) {
                $options[CURLOPT_PROXY] = getenv('PROXY');
                curl_setopt($ch, CURLOPT_PROXYPORT, getenv('PROXY_PORT'));
                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
                curl_setopt($ch, CURLOPT_PROXYUSERPWD, getenv('PROXY_USERPWD'));
            }
    
            if (defined('CURLOPT_SAFE_UPLOAD')) {
                $options[CURLOPT_SAFE_UPLOAD] = true;
            }
    
            curl_setopt_array($ch, $options);
    
            Util::execute($ch);
        }
    }