Configuring Laravel and Monolog to send stack traces to Sentry

At Netsells, we've used a self-hosted version of Sentry to keep updated to any errors that sites we've built for quite some time now. This has usually resulted in fixing the issue and emailing the client the good news before they are even aware there was a bug!

Today, we are going to configure Laravel and Monolog to send errors to a Sentry instance (either self-hosted or saas) along with the stack trace you're used to seeing on the Whoops! page.

To get started, we'll pull in raven, the PHP client for Sentry via composer (in our composer.json). At the time of writing, the latest version is 0.8.0.

"require": {
	"laravel/framework": "4.1.*",
	"raven/raven": "0.8.0"
}

Once you've run composer update, we can now move to global.php and change the logging code. As we only like to log events on staging and production, we use the power of environment based configs to make sure we are sending to the correct sentry project.

An example of app/config/production/netsells.php

<?php

return array(
	'raven' => array(
    	'enabled' => 'true',
    	'url' => 'http://d1c31158d0b90ba4e3e9db09e6a89afe:d1c31158d0b90ba4e3e9db09e6a89afe@sentry.yourdomain.com/1',
	),
);

and app/start/global.php

App::error(function(Exception $exception, $code)
{
	if ( Config::get('netsells.raven.enabled') ) {

		// Grab the monolog singleton
		$monolog = Log::getMonolog();
	
		// Create a new raven client with the Sentry project URL
		$client = new \Raven_Client( Config::get('netsells.raven.url') );
	
		// Next we tell the monolog raven handler the client we wish to use and the minimum error level to log
		$handler = new \Monolog\Handler\RavenHandler($client, \Monolog\Logger::ERROR);
	
		// Finally, we re-format the error message to remove the date/time (more on that later)
		$handler->setFormatter(new \Monolog\Formatter\LineFormatter("%message% %context% %extra%\n"));
	
		// Push the new handler onto monolog for when we encounter an error (in a few lines)
		$monolog->pushHandler($handler);
	}

	// Log the error to monolog (With the new handler in place)
	Log::error($exception, [
    	'exception' => $exception
	]);
});

You might notice I'm passing in the $exception variable twice. After some digging into the Monolog RavenHandler source, I discovered that this is the only way to force the exception stack trace to be send along with the exception message.

Unfortunately, as the RavenHandler currently stands, it doesn't look like it's possible to send over custom tags. I'll look at sending a pull request at some point if I find we really need it, but for now the above works great!

Hope this helps and feel free to ask questions in the comments section below!

Thanks to Chris Duell for the idea to strip the date/time to make the instances stack up.