phplumenrollbar

Using Rollbar with Lumen 5.7


So, currently the two most popular (IMHO) rollbar packages for Lumen (not Laravel) are:

Given that https://github.com/jenssegers/laravel-rollbar explicitly states attempts to add Lumen support for 5.x and given that there is this wonderful tutorial by James Elliot on adding Rollbar to Lumen 5.2, I attempted to update the code for his tutorial and use it for Lumen 5.7.

The bulk of his work is in his RollbarLumenServiceProvider which looks like this:

namespace App\Providers;

use Jenssegers\Rollbar\RollbarLogHandler;
use Illuminate\Support\ServiceProvider;
use InvalidArgumentException;
use Monolog\Handler\RollbarHandler;
use Rollbar;
use RollbarNotifier;

class RollbarLumenServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;

    /**
     * Register the service provider.
     */
    public function register()
    {
        $this->app->configure('rollbar');

        // Don't register rollbar if it is not configured.
        if (! getenv('ROLLBAR_TOKEN') and ! $this->app['config']->get('rollbar')) {
            return;
        }

        $app = $this->app;

        $app[RollbarNotifier::class] = $app->share(function ($app) {

            // Default configuration.
            $defaults = [
                'environment'  => $app->environment(),
                'root'         => base_path(),
            ];

            $config = array_merge($defaults, $app['config']->get('services.rollbar', []));

            $config['access_token'] = getenv('ROLLBAR_TOKEN') ?: $app['config']->get('services.rollbar.access_token');

            if (empty($config['access_token'])) {
                throw new InvalidArgumentException('Rollbar access token not configured');
            }

            Rollbar::$instance = $rollbar = new RollbarNotifier($config);

            return $rollbar;
        });

        $app[RollbarLogHandler::class] = $app->share(function ($app) {
            $level = getenv('ROLLBAR_LEVEL') ?: $app['config']->get('services.rollbar.level', 'debug');

            $handler = app(RollbarHandler::class, [$this->app[RollbarNotifier::class], $level]);

            return $handler;
        });

        // Register the fatal error handler.
        register_shutdown_function(function () use ($app) {
            if (isset($app[Rollbar::class])) {
                $app->make(Rollbar::class);
                Rollbar::report_fatal_error();
            }
        });

        // If the Rollbar client was resolved, then there is a possibility that there
        // are unsent error messages in the internal queue, so let's flush them.
        register_shutdown_function(function () use ($app) {
            if (isset($app[Rollbar::class])) {
                $app[Rollbar::class]->flush();
            }
        });
    }

    public function boot()
    {
        $app = $this->app;

        // Listen to log messages.
        $app['log']->pushHandler(
            app(RollbarLogHandler::class, [
                $this->app[Rollbar::class]
            ])
        );
    }

    public function provides()
    {
        return [
            RollbarLogHandler::class
        ];
    }
}

My attempt at updating this for Lumen 5.7 accounting for deprecation and breaking changes looks like this:

<?php
namespace App\Providers;

use Jenssegers\Rollbar\RollbarLogHandler;
use Illuminate\Support\ServiceProvider;
use InvalidArgumentException;
use Monolog\Handler\RollbarHandler;
use Rollbar;
use RollbarNotifier;

class RollbarLumenServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;

    private function getApp($app): \Laravel\Lumen\Application
    {
        return $app;
    }

    /**
     * Register the service provider.
     */
    public function register()
    {
        $app = $this->getApp($this->app);

        $app->configure('rollbar');

        // Don't register rollbar if it is not configured.
        if (!getenv('ROLLBAR_TOKEN') and !$app['config']->get('rollbar')) {
            return;
        }


        $app->singleton(RollbarNotifier::class, function (\Laravel\Lumen\Application $app)
        {
            // Default configuration.
            $defaults = [
                'environment'   =>  $app->environment(),
                'root'          =>  base_path(),
            ];

            $config = array_merge($defaults, $app['config']->get('services.rollbar', []));

            $config['access_token'] = getenv('ROLLBAR_TOKEN') ?: $app['config']->get('services.rollbar.access_token');

            if (empty($config['access_token'])) {
                throw new InvalidArgumentException('Rollbar access token not configured');
            }

            Rollbar::$instance = $rollbar = new RollbarNotifier($config);

            return $rollbar;
        });

        $app->singleton(RollbarHandler::class, function (\Laravel\Lumen\Application $app)
        {
            $level = getenv('ROLLBAR_LEVEL') ?: $app['config']->get('services.rollbar.level', 'debug');

            //$handler = app(RollbarHandler::class, [$app[RollbarNotifier::class], $level]);
            $handler = $app->makeWith(RollbarHandler::class, [$app[RollbarNotifier::class], $level]);

            return $handler;
        });

        // Register the fatal error handler.
        register_shutdown_function(function () use ($app)
        {
            if (isset($app[Rollbar::class]))
            {
                $app->make(Rollbar::class);
                Rollbar::report_fatal_error();
            }
        });

        // If the Rollbar client was resolved, then there is a possibility that there
        // are unsent error messages in the internal queue, so let's flush them.
        register_shutdown_function(function () use ($app)
        {
            if (isset($app[Rollbar::class])) {
                $app[Rollbar::class]->flush();
            }
        });
    }

    public function boot()
    {
        $app = $this->app;

        // Listen to log messages.
        $app['log']->pushHandler(
            $app->makeWith(RollbarLogHandler::class, [$app[Rollbar::class]])
        );
    }

    public function provides()
    {
        return [
            RollbarLogHandler::class
        ];
    }
}

I think it ALMOST works. I get an exception in this method:

    public function boot()
    {
        $app = $this->app;

        // Listen to log messages.
        $app['log']->pushHandler(
            $app->makeWith(RollbarLogHandler::class, [$app[Rollbar::class]])
        );
    }

Here is the Exception trace:

(1/1) ReflectionException Class Illuminate\Foundation\Application does not exist in Container.php line 838

at ReflectionParameter->getClass() in Container.php line 838

at Container->resolveDependencies(array(object(ReflectionParameter), object(ReflectionParameter), object(ReflectionParameter))) in Container.php line 807

at Container->build('Jenssegers\Rollbar\RollbarLogHandler') in Container.php line 658

at Container->resolve('Jenssegers\Rollbar\RollbarLogHandler', array(object(Rollbar))) in Container.php line 609

at Container->make('Jenssegers\Rollbar\RollbarLogHandler', array(object(Rollbar))) in Application.php line 260

at Application->make('Jenssegers\Rollbar\RollbarLogHandler', array(object(Rollbar))) in Container.php line 597

at Container->makeWith('Jenssegers\Rollbar\RollbarLogHandler', array(object(Rollbar))) in RollbarLumenServiceProvider.php line 104

at RollbarLumenServiceProvider->boot() at call_user_func_array(array(object(RollbarLumenServiceProvider), 'boot'), array()) in BoundMethod.php line 29

at BoundMethod::Illuminate\Container{closure}() in BoundMethod.php line 87

at BoundMethod::callBoundMethod(object(Application), array(object(RollbarLumenServiceProvider), 'boot'), object(Closure)) in BoundMethod.php line 31

at BoundMethod::call(object(Application), array(object(RollbarLumenServiceProvider), 'boot'), array(), null) in Container.php line 572

at Container->call(array(object(RollbarLumenServiceProvider), 'boot')) in Application.php line 237

at Application->bootProvider(object(RollbarLumenServiceProvider)) in Application.php line 222

at Application->Laravel\Lumen{closure}(object(RollbarLumenServiceProvider), 'App\Providers\RollbarLumenServiceProvider')

It's at this point that I get stuck. Does anyone know how to fix this error? I am not a service container or rollbar wiz and will appreciate any help. Hopefully, this will serve as a nice community way to get Rollbar working with Lumen 5.7!


Solution

  • I came across this question when facing the same problem. Since there were no answer I decided to give it a go myself.

    I wrote an article about it with my solution.

    http://troccoli.it/rollbar-in-lumen/

    In short, get rollbar

    composer require rollbar/rollbar
    

    Add the rollbar channel to your config/logging.php

    <?php
    
    return [
        'default' => env('LOG_CHANNEL', 'stack'),
    
        'channels' => [
            'stack' => [
                'driver' => 'stack',
                'channels' => ['rollbar'],
            ],
            'rollbar' => [
                'driver' => 'monolog',
                'handler' => Rollbar\Monolog\Handler\RollbarHandler::class,
                'access_token' => env('ROLLBAR_ACCESS_TOKEN'),
                'level' => 'debug',
            ],
        ],
    ];
    

    Write a service provider RollbarServiceProvider.php

    <?php
    
    namespace App\Providers;
    
    use Illuminate\Contracts\Config\Repository;
    use Illuminate\Support\ServiceProvider;
    use Rollbar\RollbarLogger;
    use Rollbar\Rollbar;
    
    class RollbarServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton(RollbarLogger::class, function () {
                $config = $this->app->make(Repository::class);
    
                $defaults = [
                    'environment' => app()->environment(),
                    'root' => base_path(),
                    'handle_exception' => true,
                    'handle_error' => true,
                    'handle_fatal' => true,
                ];
    
                $rollbarConfig = array_merge($defaults, $config->get('logging.channels.rollbar', []));
    
                $handleException = (bool)array_pull($rollbarConfig, 'handle_exception');
                $handleError = (bool)array_pull($rollbarConfig, 'handle_error');
                $handleFatal = (bool)array_pull($rollbarConfig, 'handle_fatal');
    
                Rollbar::init($rollbarConfig, $handleException, $handleError, $handleFatal);
    
                return Rollbar::logger();
            });
        }
    }
    

    Add the post_server_item- token (you can get this from your rollbar account) into the.env` file

    ROLLBAR_ACCESS_TOKEN=ROLLBAR_POST_SERVER_ITEM_TOKEN
    

    and finally link all this together in bootstrap/app.php

    $app->register(\App\Providers\RollbarServiceProvider::class);
    $app->configure('logging');