-
-
Notifications
You must be signed in to change notification settings - Fork 453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[2.0] Refactor the error and exception handlers #584
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a good work for now! 👍
For test, mind that a try...catch
would stop even failed assertions.
lib/Raven/Client.php
Outdated
/** | ||
* @var ErrorHandler The instance of the error handler | ||
*/ | ||
private $errorHandler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move this back up to reduce the diff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided to remove the property as the client does not necessarily need to know the instance of the error handler and so that there is no circular reference between them
lib/Raven/ErrorHandler.php
Outdated
// This prevents duplicated exceptions in PHP 7.0+ | ||
if (PHP_VERSION_ID >= 70000 && E_ERROR === $type) { | ||
return false; | ||
if (!empty($error) && $error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you should wrap those two lines with a private method to give it a name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracting the code that just checks whether the error is a fatal error does not makes much sense imho, and there would also be the cost of calling one more function
tests/ErrorHandlerTest.php
Outdated
* @expectedException \UnexpectedValueException | ||
* @expectedExceptionMessage The value of the $reservedMemorySize argument must be an integer greater than 0. | ||
*/ | ||
public function testConstructorThrowsWhenReservedMemorySizeIsWrong() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're not using the data from the provider
lib/Raven/ErrorHandler.php
Outdated
// If there is no exception handler that can run after the current one | ||
// give back the exception to the native PHP handler | ||
if (null === $this->previousExceptionHandler) { | ||
throw $exception; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't re-throwing change the stack trace of the exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a few tests it seems it doesn't
lib/Raven/ErrorHandler.php
Outdated
$this->previousExceptionHandler = null; | ||
|
||
try { | ||
call_user_func($previousExceptionHandler, $exception); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$previousExceptionHandler($exception)
is maybe slightly faster?
lib/Raven/ErrorHandler.php
Outdated
|
||
return $this; | ||
$this->handleException($previousExceptionHandlerException); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this loop-prone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it should be as the next time the function will be called $this->previousExceptionHandler
will be null
and after sending the exception to Sentry the exception itself will be rethrown
tests/phpt/fatal_error.phpt
Outdated
$pendingRequests = Assert::getObjectAttribute($transport, 'pendingRequests'); | ||
|
||
Assert::assertEmpty($pendingRequests); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those asserts can trigger the autoloading. If this is done under PHP 5 inside an error handling context, it fails silently. You should add an echo
at the end and expect it to be sure that all those assertions are executed correctly.
$foo = str_repeat('x', 1024 * 1024 * 30); | ||
?> | ||
--EXPECTF-- | ||
Fatal error: Allowed memory size of %d bytes exhausted (tried to allocate %d bytes) in %s on line %d |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't you add something to be sure that you really handled the error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, I've added an echo
statement after all the assertions whose existence is checked in the --EXPECTF--
section of the PHPT test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM now! 👍 Great work!
I still have to complete the refactor of the ErrorHandler for the breadcrumbs. Please don't merge this PR yet until I remove the WIP prefix |
Sorry, I thought it was complete! |
@dcramer @stayallive @Jean85 In |
IMHO the option is indipentent from the practical implementation of the handler. I agree that we can reuse the same code to do that stuff, but I would leave them separate, so an end user would still be able to customize the breadcrumbs. Maybe we can create two instances? Or two different child classes? |
Would it makes sense for an user to use only the error handler that registers the breadcrumbs and not the handler that captures the error itself? |
No, obviously not, why? |
Because then it would not make sense to have two error handlers, one for capturing the errors and one for registering the breadcrumb. Or at least, I don't see the sense behind this. Having two handlers means reserving memory for both of them (to handle fatal errors) and duplicating the logic for each of them. Also, I don't see why an user would want to not register the breadcrumbs but instead capture the errors |
The scenario that I want to preserve is the possibility of replacing (or enhancing) the breadcrumb handler. If you collapse both handler this would not be possible anymore. |
Drop the install_default_breadcrumb_handlers configuration option
I updated the PR by refactoring the breadcrumb handler and it's ready for another round of code reviews. The zendframework/zend-diactoros#298 issue persists and if nothing changes before releasing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic work!! 🎉
lib/Raven/AbstractErrorHandler.php
Outdated
|
||
$errorAsException = new \ErrorException(self::ERROR_LEVELS_DESCRIPTION[$level] . ': ' . $message, 0, $level, $file, $line); | ||
|
||
$backtrace = $errorAsException->getTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be inlined
I fixed the fact that fatal errors were reported twice in PHP 7+ (yes, again...) and this should be the good time. Before merging, should I switch PSR-7 library in this PR or do you prefer to postpone it later? |
I think that switching PSR-7 implementor should be done in a separate PSR, let's keep it simple! |
This PR is a huge refactoring of the error and exception handlers. I tried to make them as transparent as possible in regards to other handlers, so the error handler converts the errors to exceptions to be able to log them but never throws them unless necessary. The aim of my work is to fix the many bugs that we're experiencing in
1.x
, in particular #579, #552, #391, #343. I'm currently tracking an issue with Zend Diactoros (zendframework/zend-diactoros#298) that prevents any error past the first one from being logged through custom error handlers after usage of theStream
class.