Accessing getLastEventId() from CakePHP

I’ve an issue trying to access the getLastEventId() from within CakePHP to provide to the User Feddback JS (Sentry.showReportDialog). Sentry has been initialised and is capturing Errors/Expections within the Cake app no problem.

“\Sentry\State\Hub::getCurrent()->getLastEventId()” will only provide the event ID if “use Sentry;” is added to the PHP script. The trouble is, on a non-namespaced php script that in itself fires a PHP warning: “Warning: The use statement with non-compound name ‘Sentry’ has no effect”. But it will provide the latest event ID.

Anyone integrated Sentry with CakePHP framework and extracted the getLastEventId() without the use statement error, or know a way to use/include the Sentry class within CakePHP in a better manner?

View templates in CakePHP run in the global namespace. You won’t need a use statement if you use \Sentry\State\Hub::getCurrent()->getLastEventId() (with the leading \) as that is a fully qualified classname.

If you wanted a simpler interface you could wrap the Sentry SDK methods into a View Helper. I’ve not personally done that but you could use cake bake helper to generate a skeleton and add the methods you want.

But when I don’t add use Sentry; and look for the ID value using \Sentry\State\Hub::getCurrent()->getLastEventId() the id is always null. Its only when use Sentry; is added to the view .ctp that the event id becomes available.

I’ll try and wrap them into a Helper. Cheers for taking a look, appreciate it.

Putting the getLastEventId() call into a helper will give you a good place to put use Sentry at the very least :slight_smile:

I put the call to getLastEventId within a helper, but the same behaviour exhibits, null gets returned. As soon as use Sentry; is added to the .ctp view the event id returns as expected but PHP fires a Notice about the use statement - well odd. I’ve tried overriding ExceptionRenderer, BaseErrorHandler and retrieving the event id within those but no joy.

What does your view Helper look like? It should have use Sentry; at the top of the class. The getLastEventId() may be null inside the helper if no error has been logged in the current request.

How are you using getLastEventId() is it within the error templates in order to show a user-feedback modal?

From SentryHelper:
use Sentry;
use Sentry\State\Hub;
public function getSentryEventId(){ return Hub::getCurrent()->getLastEventId(); }

I’m throwing an \Exception in the controller method to force an error, so on each reload an error is being caught and shown. Yes, I’m using getLastEventId() within error templates to show the user-feedback modal.

So in the error.ctp I’m testing for $this->SentryHelper->getSentryEventId() but its always null, until I add use Sentry; to the error.ctp as well, and as soon as that’s added the event id is duly returned but I get the PHP “use statement…” error.

I don’t have much experience with CakePHP but after some googling I think I know what is happening.

The Exception you are throwing in the controller is not actually caught by Sentry and should also not popup in your Sentry feed, this is because Cake is capturing the exception thus Sentry never sees it because Cake handled it. The reason when you add use Sentry; to the template you do get an ID is because an warning is generated and Sentry does see that (and reports is as ErrorException) which is the ID you are getting.

If the actual exception does show up in Sentry you are sending the event maybe after Cake renders the exception page thus not having the event ID available when you are trying to display it.


I replaced the error handler code in config/bootstrap.php with the following to get it to work correctly and be able to use \Sentry\State\Hub::getCurrent()->getLastEventId() in the errror500.ctp template file:

/*
 * Register application error and exception handlers.
 */
$isCli = PHP_SAPI === 'cli';
if ($isCli) {
    (new ConsoleErrorHandler(Configure::read('Error')))->register();
} else {
    \Sentry\init(['dsn' => 'YOUR_DSN' ]);

    class SentryErrorHandler extends ErrorHandler {
        public function handleException(Exception $exception)
        {
            \Sentry\captureException($exception);

            parent::handleException($exception);
        }
    }
    class SentryErrorHandlerMiddleware extends \Cake\Error\Middleware\ErrorHandlerMiddleware {
        public function handleException($exception, $request, $response)
        {
            \Sentry\captureException($exception);

            return parent::handleException($exception, $request, $response);
        }
    }

    (new SentryErrorHandler(Configure::read('Error')))->register();

    $appClass = Configure::read('App.namespace') . '\Application';
    if (class_exists($appClass)) {
        \Cake\Event\EventManager::instance()->on('Server.buildMiddleware', function ($event, $queue) {
            /* @var \Cake\Http\MiddlewareQueue $queue */
            $middleware = new SentryErrorHandlerMiddleware();
            try {
                $queue->insertAfter(\Cake\Error\Middleware\ErrorHandlerMiddleware::class, $middleware);
            } catch (LogicException $e) {
                $queue->prepend($middleware);
            }
        });
    }
}

It would be helpful to know how you implemented the PHP SDK in you application so we can see what might be happening!

At present I’m initilalising Sentry from within \App\Application::bootstrap (src/Application.php)

use function Sentry\init;

if (Configure::read('Sentry.enable')) {
		Configure::write('Sentry.config', [
			'server_name' => Configure::read('App.fullBaseUrl'),
			'project_root' => APP,
			'dsn' => Configure::read('API.sentry.dsn'),
			'release' => Configure::read('App.git.rev_short'),
			'environment' => Configure::read('App.environment'),
			'error_types' => Configure::read('Error.errorLevel'),
			'excluded_exceptions' => [],
			'send_default_pii' => true
		]);
		init(Configure::read('Sentry.config'));
}

I’ll try and initialise from within config/bootstrap.php instead as you’ve described…

Your setup/code worked a treat, nice one! Can i ask was that documented anywhere, I certainly missed that setup. Thanks so much for both your help.

It was not, this was a quick setup I threw together with a blank Cake app to see if it might be a bug in our SDK, fortunately it’s not.

We do not have a CakePHP integration ourselfs and/or docs at the moment (there are a few Cake plugins created by the community but they use our older SDK).