Hi list.
We log all errors that happens in our production environment, but as
fatal errors can't be handled from within php, we end up with little
information to go on for further debugging. I'm not very familiar with
the php internals code, but I managed to throw in a hack that appears
to work. In the handler function for timeouts (zend_timeout), I raise
a WARNING, sleep for 1 second and then resume normal behavior, which
results in a fatal error. This gives userland code 1 second to log the
error somewhere, which should be sufficient for debugging.
Would like to get feedback as to if this has any hidden problems, but
otherwise I propose that it's included in the project.
--
troels
Hi,
well, maybe we should provide a better behaviour for all fatal errors, no ?
A frequent one I see is the fatal error for calls like "$obj->method()",
when $obj is not an object.
Isn't possible to allow catching of fatal errors, like other errors ?
Olivier
Hi list.
We log all errors that happens in our production environment, but as
fatal errors can't be handled from within php, we end up with little
information to go on for further debugging. I'm not very familiar with
the php internals code, but I managed to throw in a hack that appears
to work. In the handler function for timeouts (zend_timeout), I raise
a WARNING, sleep for 1 second and then resume normal behavior, which
results in a fatal error. This gives userland code 1 second to log the
error somewhere, which should be sufficient for debugging.Would like to get feedback as to if this has any hidden problems, but
otherwise I propose that it's included in the project.
Hi,
well, maybe we should provide a better behaviour for all fatal errors, no ?
A frequent one I see is the fatal error for calls like "$obj->method()",
when $obj is not an object.Isn't possible to allow catching of fatal errors, like other errors ?
Fatal errors might let the engine in some undefined state. The only safe
thing we can do is terminate the current script. fror other cases we
have catchable fatal errors. Maybe there are a few more cases where
fatal errors can be made catchable fatal errors, but these are case by
case decisions.
johannes
2010/3/22 Johannes Schlüter johannes@php.net
Hi,
well, maybe we should provide a better behaviour for all fatal errors, no
?
A frequent one I see is the fatal error for calls like "$obj->method()",
when $obj is not an object.Isn't possible to allow catching of fatal errors, like other errors ?
Fatal errors might let the engine in some undefined state. The only safe
thing we can do is terminate the current script. fror other cases we
have catchable fatal errors. Maybe there are a few more cases where
fatal errors can be made catchable fatal errors, but these are case by
case decisions.Then why is this snippet working:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
register_shutdown_function(
function (){
echo 111;
}
);
if(ob_get_level()){
ob_end_flush()
;
}
echo 123;
flush()
;
$obj->func();
echo 456;
script execution can continue on fatal error.
you can use the register_shutdown_function, or the ob_start function
callback param to continue the execution after an uncatchable fatal error.
I think either this kind of errors should be catchable(except the errors in
the engine itself, not in the userland) or the above mentioned two method
shouldn't be working.
Tyrael
johannes
We log all errors that happens in our production environment, but as
fatal errors can't be handled from within php, we end up with little
information to go on for further debugging. I'm not very familiar with
the php internals code, but I managed to throw in a hack that appears
to work. In the handler function for timeouts (zend_timeout), I raise
a WARNING, sleep for 1 second and then resume normal behavior, which
results in a fatal error. This gives userland code 1 second to log the
error somewhere, which should be sufficient for debugging.
A one second delay is no option there. And what actually happens is that
the warning triggers your custom error handler. After that it sleeps
then it dies.
This also creates a "nice" way to extend the script runtime after the
timeout occurred. aka. making the timeout useless for many scenarios it
was meant for.
johannes
2010/3/22 Johannes Schlüter johannes@php.net:
A one second delay is no option there. And what actually happens is that
the warning triggers your custom error handler. After that it sleeps
then it dies.
What do you mean by "no option"? Otherwise yes, that's what it does.
This also creates a "nice" way to extend the script runtime after the
timeout occurred. aka. making the timeout useless for many scenarios it
was meant for.
I'm not sure I understand. Are you implying that it is somehow
possible to circumvent the second (fatal) error with this change? How?
--
troels
What do you mean by "no option"? Otherwise yes, that's what it does.
Using sleep there is not a good practice. Since the custom error
handler is triggered, there is no need for the sleep call anyways.
I'm not sure I understand. Are you implying that it is somehow
possible to circumvent the second (fatal) error with this change? How?
Consider for a second what you are asking the language to do. The
script has run out of memory and instead of halting you want it to
switch into an error handler to log the error. What happens when that
error handler creates new variables or an object instance? Where does
that memory come from?
A better solution: generate a warning for scripts that use some target
% of memory. I hate to add more ini settings, but for simplicity
there could be a "memory_limit_warn" setting which you can set to
something like "95%". When a script reaches that memory threshold it
can trigger a warning so you can log it.
--
Herman Radtke
hermanradtke@gmail.com | http://hermanradtke.com
What do you mean by "no option"? Otherwise yes, that's what it does.
Using sleep there is not a good practice. Since the custom error
handler is triggered, there is no need for the sleep call anyways.
So control isn't returned to the C-code before the php error handler
finishes. Is that it?
Consider for a second what you are asking the language to do. The
script has run out of memory and instead of halting you want it to
switch into an error handler to log the error. What happens when that
error handler creates new variables or an object instance? Where does
that memory come from?
This patch handles timeout, not memory exhaustion.
Although a similar solution for memory exhaustion could be useful as well.
--
troels
This patch handles timeout, not memory exhaustion.
Apologies. My train of thought inexplicably switched over to memory.
I meant to assert that your custom error handler could extend the
length of the script to n extra seconds. This violates that idea of
the timeout.
Herman Radtke
hermanradtke@gmail.com | http://hermanradtke.com
On Mon, Mar 22, 2010 at 5:04 PM, Herman Radtke hermanradtke@gmail.comwrote:
This patch handles timeout, not memory exhaustion.
Apologies. My train of thought inexplicably switched over to memory.
I meant to assert that your custom error handler could extend the
length of the script to n extra seconds. This violates that idea of
the timeout.
try:
time php -r 'set_time_limit(1);echo
"start";register_shutdown_function(function(){sleep(10);echo "done";});'
violates what?
Tyrael
--
Herman Radtke
hermanradtke@gmail.com | http://hermanradtke.com
What do you mean by "no option"? Otherwise yes, that's what it does.
Using sleep there is not a good practice. Since the custom error
handler is triggered, there is no need for the sleep call anyways.So control isn't returned to the C-code before the php error handler
finishes. Is that it?
Just checked, and you're right about this. I've made a new patch,
which addresses this. Again, I have no idea about whether I'm
violating code style (Should zend_timeout_softswitch be declared or
named differently?), so comments on that please?
New patch attached - disregard the previous one.
--
troels
What do you mean by "no option"? Otherwise yes, that's what it does.
Using sleep there is not a good practice. Since the custom error
handler is triggered, there is no need for the sleep call anyways.So control isn't returned to the C-code before the php error handler
finishes. Is that it?Just checked, and you're right about this. I've made a new patch,
which addresses this. Again, I have no idea about whether I'm
violating code style (Should zend_timeout_softswitch be declared or
named differently?), so comments on that please?New patch attached - disregard the previous one.
Statics are bad, if its in multithreaded mode and two timeouts happen at once you'll get some funny behaviour. You need to store this in the thread local storage so the flag is per thread.
Scott
Statics are bad, if its in multithreaded mode and two timeouts happen at once you'll get some funny behaviour. You need to store this in the thread local storage so the flag is per thread.
Thanks. My C is severely rusty; Would it simply be a matter of
dropping the "static" modifier, or do I need to get hold of some kind
of handle and attach the flag to that? In which case, what would be
appropriate?
--
troels
Statics are bad, if its in multithreaded mode and two timeouts happen at once you'll get some funny behaviour. You need to store this in the thread local storage so the flag is per thread.
Thanks. My C is severely rusty; Would it simply be a matter of
dropping the "static" modifier, or do I need to get hold of some kind
of handle and attach the flag to that? In which case, what would be
appropriate?
You'll see places that have EG(...) that's Executor globals and they're per thread or static if its single threaded.
So if you define your new variable wherever timeout_seconds is defined you can add it there. I don't have a checkout to hand so can't point you in the exact place.
Scott
With the help of Scotts last suggestion, I made some changes. It seems
to work, but then I don't really know how to test it properly. I can
verify that A) it allows userland code the grace period of 1 second
for shutting down and B) shuts down regardless of the userland error
handler returning or not. I have tested by running the following:
php -r 'function err() { echo "Shutting down"; while (true) {}};
set_error_handler("err"); set_time_limit(2); while (true) {}'
New patch is attached.
--
troels
With the help of Scotts last suggestion, I made some changes. It seems
to work, but then I don't really know how to test it properly. I can
verify that A) it allows userland code the grace period of 1 second
for shutting down and B) shuts down regardless of the userland error
handler returning or not. I have tested by running the following:
Hi,
Thanks for your patch, but you're going to affect a whole group of users who
do advanced logging and recovery in the shutdown phase. This is why these
things have to be considered when they're first added.
A grace period of 1 second seems sufficient on a pristine condition unused
server, but when your server is loaded, a spike in load may cause a number
of shutdown handlers to take more than 1 second, and stop middway running,
causing a lot of unpredictability and trouble for those who rely on this
feature.
Regards,
Stan Vassilev
Hi Stan.
Thanks for your patch, but you're going to affect a whole group of users who
do advanced logging and recovery in the shutdown phase. This is why these
things have to be considered when they're first added.
How would they be affected? Current behavior would still be there.
A grace period of 1 second seems sufficient on a pristine condition unused
server, but when your server is loaded, a spike in load may cause a number
of shutdown handlers to take more than 1 second, and stop middway running,
causing a lot of unpredictability and trouble for those who rely on this
feature.
So, you mean that a patch that fixes 90% of the cases, but leaves the
10%, is worse than no patch, because of the confusion it might cause?
I guess that could be a valid point; Is it a generally agreed-on
strategy for php?
--
troels
On Mon, Mar 22, 2010 at 4:41 PM, Herman Radtke hermanradtke@gmail.comwrote:
What do you mean by "no option"? Otherwise yes, that's what it does.
Using sleep there is not a good practice. Since the custom error
handler is triggered, there is no need for the sleep call anyways.I'm not sure I understand. Are you implying that it is somehow
possible to circumvent the second (fatal) error with this change? How?Consider for a second what you are asking the language to do. The
script has run out of memory and instead of halting you want it to
switch into an error handler to log the error. What happens when that
error handler creates new variables or an object instance? Where does
that memory come from?The out of memory is a good example, but not the only one.
If you reached the memory limit, but the system has available memory, then
it should be handled with a soft limit/hard limit.
A better solution: generate a warning for scripts that use some target
% of memory. I hate to add more ini settings, but for simplicity
there could be a "memory_limit_warn" setting which you can set to
something like "95%". When a script reaches that memory threshold it
can trigger a warning so you can log it.
you can write that in userland with memory_get_usage.
but its just one case from the many.
Tyrael
--
Herman Radtke
hermanradtke@gmail.com | http://hermanradtke.com
Op 22-3-2010 16:14, Johannes Schlüter schreef:
We log all errors that happens in our production environment, but as
fatal errors can't be handled from within php, we end up with little
information to go on for further debugging. I'm not very familiar with
the php internals code, but I managed to throw in a hack that appears
to work. In the handler function for timeouts (zend_timeout), I raise
a WARNING, sleep for 1 second and then resume normal behavior, which
results in a fatal error. This gives userland code 1 second to log the
error somewhere, which should be sufficient for debugging.A one second delay is no option there. And what actually happens is that
the warning triggers your custom error handler. After that it sleeps
then it dies.This also creates a "nice" way to extend the script runtime after the
timeout occurred. aka. making the timeout useless for many scenarios it
was meant for.
This could be made configurable. Shared hosting providers probably want
to disable the 'overriding' of the timeout. At my work; all code is
written by our own developers; so there's no evil in there ;) (And it
would be usefull to give extra debugging information)
-- Jille
johannes
2010/3/22 Jille Timmermans jille@quis.cx
Op 22-3-2010 16:14, Johannes Schlüter schreef:
We log all errors that happens in our production environment, but as
fatal errors can't be handled from within php, we end up with little
information to go on for further debugging. I'm not very familiar with
the php internals code, but I managed to throw in a hack that appears
to work. In the handler function for timeouts (zend_timeout), I raise
a WARNING, sleep for 1 second and then resume normal behavior, which
results in a fatal error. This gives userland code 1 second to log the
error somewhere, which should be sufficient for debugging.A one second delay is no option there. And what actually happens is that
the warning triggers your custom error handler. After that it sleeps
then it dies.This also creates a "nice" way to extend the script runtime after the
timeout occurred. aka. making the timeout useless for many scenarios it
was meant for.This could be made configurable. Shared hosting providers probably want to
disable the 'overriding' of the timeout. At my work; all code is written by
our own developers; so there's no evil in there ;) (And it would be usefull
to give extra debugging information)If you mentioned it, it would be a good thing, to have a possibility to
control the execution time INCLUDING the time spent waiting for external
resources.
if you run
time php -r 'set_time_limit(5);sleep 10
;echo "done";';
you will see what I'm talking about.
Tyrael
-- Jille
johannes