PhpSpec test if log written with same data - php

I need to test if my application logs written with correct data (I know in most cases it's not very important to check logs, but it's very important in this specific case).
So log looks like this:
$this->logger->error(
'Invalid survey provided',
[
'exception' => $e,
'survey' => $survey
]
);
and in the spec I have a code:
$exception = new ValidationException(
sprintf(
'Provided survey "%s" does not have all required fields %s',
json_encode($surveysResponse['result'][0]),
json_encode(Survey::$requiredFields)
)
);
$logger->error(
'Invalid survey provided',
[
'exception' => $exception,
'survey' => $surveysResponse['result'][0]
]
)->shouldBeCalled();
and spec failing b-z mock not matching, but I'm sure that same error message with same survey and exception with same error message actually logged. I'm not able to tell you exact issue as error output is huge and trimmed. But I'm 90% sure it's failing while comparing exception object because exceptions are not exact the same objects.

This might be the wrong approach, because the log entry will not be the same due to different timestamps on the log entry. Just preg_match() the log file, spanning multiple lines, obviously with a wildcarded timestamp. Then it should be save to assume that they're "the same", when the count of returned matches equals two (assuming a truncated log file, to begin with). Check out \PHPSpec\Matcher .beTrue() in combination with said condition.

Related

Severity of exception codes

I am trying to sort out error and exception handlers. With a fatal error, I send myself a text message, and with other errors I get an email. (I added the arrays at the end in case they may be useful.)
For errors there is https://php.net/manual/en/errorfunc.constants.php I but cannot find anything similar for exceptions.
I believe I can set my own exception values but are there agreed severity levels for general exceptions, PDOExceptions etc. The only place I find severity mentioned is in ErrorException. (I only use PDOExceptions at the moment but am trying to catch other "general" ones.)
Is a severity helper chart available somewhere? I freely admit I am struggling with exceptions.
PS I had a look at https://www.php.net/manual/en/errorexception.getseverity.php but that looks like it is for errors being sent as exceptions. I am quite confused now.
Error code arrays in case they are useful.
$phpErrorCodes = array (
1 => "E_ERROR",
2 => "E_WARNING",
4 => "E_PARSE",
8 => "E_NOTICE",
16 => "E_CORE_ERROR",
32 => "E_CORE_WARNING",
64 => "E_COMPILE_ERROR",
128 => "E_COMPILE_WARNING",
256 => "E_USER_ERROR",
512 => "E_USER_WARNING",
1024 => "E_USER_NOTICE",
2048 => "E_STRICT E_ALL",
4096 => "E_RECOVERABLE_ERROR",
8192 => "E_DEPRECATED",
16384=> "E_USER_DEPRECATED",
32767=> "E_ALL");
$phpErrorCodesFatal = array (
1 => "E_ERROR",
16 => "E_CORE_ERROR",
64 => "E_COMPILE_ERROR",
4096 => "E_RECOVERABLE_ERROR");
$phpErrorCodesFatalNumberOnly = array (
1 ,
16 ,
64 ,
4096);
//4096 recoverable but dangerous so treated as fatal
Exceptions
Let me try to clarify some misconceptions here.
Are there severity codes for exceptions?
No. All exceptions are severe.
An exception will stop the execution of your script. They are used to prevent the execution of the code which follows if the preceding code could not be executed.
How do I know if they are important?
All exceptions are important. When an exception is triggered it tells you as a developer that something unexpected has happened in the code. The code which you have written simply did not anticipate this happening and to prevent undefined behaviour it should stop processing immediately.
Unhandled exceptions would show up as PHP Warning. - mario
That is not true. Any unhandled exception will be converted to PHP Fatal error. If your application doesn't know how to handle an exceptional situation then PHP must immediately stop! It is not a warning you can ignore or silence; it's a fatal error.
As a rule of thumb I should treat exceptions as fatal errors?
Not necessarily. In rare cases a developer might expect a particular piece of code to throw an exception, which is possible to recover from or work around. The code logic anticipates something going wrong and has a way around the problem. If the exception is caught and handled this will not result in a fatal error.
The difference between an exception and a fatal error is that you can catch and recover from an exception, but not from a fatal error.
So if I don't do anything then exceptions turn to errors.
If you have not caught the exception and you do not have your own error handled implemented then PHP will default to the built-in error handler. The logic is that it will stop the script and throw an error with the exception as a message. This error will then, based on your configuration settings, either be logged on the server or displayed to the user.
Errors
PHP has a bad history. One of the problems with early PHP versions was that it was very lenient when it comes to badly written code. It would either try to guess what the correct action should be or merely warn the user about some serious problem. The outcome of this was that a lot of developers learned to simply ignore the warnings, notices and sometimes even errors.
With PHP 7 few things have changed.
PHP 7 changes how most errors are reported by PHP. Instead of reporting errors through the traditional error reporting mechanism used by PHP 5, most errors are now reported by throwing Error exceptions. An error is still not an exception, but it behaves like one. You can catch the error and if you don't you will still see "Fatal error: Uncaught Error: ...".
Modern PHP functionalities will now use exceptions. This means that userland code should also try to follow the same approach. Throw an exception when your code should stop the execution (don't use die/exit for this) and only catch them when when you know how to recover.
With future PHP releases the notices and warnings might be changed to Error exceptions. Don't ignore them now. Treat all of them as severe problems in your code and fix them now.
As per the comments, the general advice with exceptions is that you should catch them all - in that sense, all unhandled exceptions are severe.
However, you could still classify exceptions in your system in the way that you want. Let's say that at the top level of your app you have a call that enters the main app:
try
{
$this->mainApp();
}
catch (SeriousRuntimeException $e)
{
$this->handleSeriousError($e);
}
catch (TrivialRuntimeException $e)
{
$this->handleTrivialError($e);
}
Then in your code you can throw a SeriousRuntimeException or a TrivialRuntimeException as you see fit. In some cases you will have external exceptions to deal with, and you will need to convert them like so:
try
{
$this->databaseOperation();
}
catch (PDOException $e)
{
// Copy the exception properties that are important to you.
// Throw the appropriate severity based on what handler you
// want to run.
throw new SeriousRuntimeException($e->getMessage());
}
In this example I assume that both exception types are fatal, but they are handled differently. It is conceivable that you could have an exception type that is so trivial that the app keeps running (e.g. in a listener loop - it logs the fault and then carries on).

Show error page in Laravel?

Before I get into the question, I'll give you a brief introduction into what I want to do. I want to be able to show a friend;y view to users when a error happens in my Laravel project but unfortunately I don't know how to do this and was hoping some of you may be able to help me?
Hello. Today I am asking a question about Laravel. For a long time I have wanted to log EVERY single error in my laravel project. Now some of you may say that its easy, just overwrite the handle() method in the App\Exceptions\Handler class.
While that's relatively easy to do, it doesn't handle EVERY single error. I have noticed it doesn't handle Query exceptions.
What I am asking is how can I handle EVERY exception. What I mainly want to do is log the error in a database table, and disable a nice view to the end user. Then if I am the one, or another member of my team that receives the error, they can easily check in the database without having to show any critical details to the end user.
I followed this tutorial but it's the same, it doesn't log every single exception.
http://blog.sarav.co/registering-custom-exception-handler-laravel-5/
You can simply add some code in the App\Exceptions\Handler::render method, for example:
public function render($request, Exception $exception)
{
if($exception instanceof \Illuminate\Database\QueryException) {
// Do something with the $exception
// dd($exception); // analyze it
// return a response/redirect
}
return parent::render($request, $exception);
}
In this $exception instance, you can find many useful information using following methods (Omit magic methods, it's a dump of get_class_methods):
array:12 [▼
0 => "__construct"
1 => "getSql"
2 => "getBindings"
3 => "__wakeup"
4 => "getMessage"
5 => "getCode"
6 => "getFile"
7 => "getLine"
8 => "getTrace"
9 => "getPrevious"
10 => "getTraceAsString"
11 => "__toString"
]
Also, the property $exception->errorInfo will give you some information as well, for example (One particular errorInfo):
errorInfo: array:3 [▼
0 => "42S22"
1 => 1054
2 => "Unknown column 'ids' in 'field list'"
]
Note: FYI, error and exception are two different things so the set_error_handler and the set_exception_handler both are for different reasons, an error handler will not catch an exception.
Use set_error_handler to set custom exception. Or you could use log4php they have a package for laravel I believe.

Get Monolog JSON Stack Trace as Array

I'm using Laravel 4.2 and want to get logs out as JSON. Laravel uses Monolog, so I've configured the JSON formatter like so:
$logHandler = new Monolog\Handler\StreamHandler(Config::get('app.logFile'), Monolog\Logger::DEBUG);
$logHandler->setFormatter(new Monolog\Formatter\JsonFormatter);
Log::getMonolog()->pushHandler($logHandler);
The problem is that stack traces are included as part of the message string, like so:
{
"message": "exception 'Exception' with message 'Socket operation failed: Host name lookup failure' in /var/www/vendor/clue/socket-raw/Socket/Raw/Socket.php:388\nStack trace:\n#0 /var/www/vendor/clue/socket-raw/So..."
}
Can someone point me in the right direction to make the stack trace its own separate array in the json?
Long overdue update:
The primary problem is that Laravel, and lots of code following its example, tries to log the exception by itself, e.g., Log::error($e). This is the wrong way to log an exception with Monolog. That first parameter is supposed to be a simple message string. In processing it, Monolog\Logger::addRecord() explicitly casts the message to a string:
$record = array(
'message' => (string) $message,
//...
);
If $message is actually an exception, you get the whole stack trace as a string. Unfortunately, this is what Laravel's default exception handler does.
The correct way to get a stack trace as an array is to pass the exception in as context so that it's available non-stringified to the formatter. For instance:
Log::error($e->getMessage(), ['exception' => $e]);
Something equivalent is what you need to put in your custom exception handler for Laravel, and then you can use a proper JSON formatter and get what you except.

Unit test exception-messages formatted with sprintf

How can I test if an exception throws the expected error message, when I format my error messages like this:
throw new \Exception(sprintf('Random string: "%s".', 'blablabla'));
Obviously testing with $this->assertEquals() won't work, since I don't know what %s is going to be. Is there a straight forward way to test Exception messages that use sprintf?
I believe that you should know what '%s' is going to be by triggering the part of your code you want an exception in, in a controlled way.
You could trigger the exceptions you are expecting, then you can use assertEquals with the error message you are expecting to be triggered

Method error handling for user friendly messages

I have an object oriented app (written in an MVC framework) and often my error handling procedures are ad-hoc. Sometimes I return 0 for no error, sometimes a true for success. In general there is not a lot of consistency.
My scenario is that I have a controller calling a method from my model. If that method fails, I want it to return a human-readable reason as to why the error could not be completed. This error will be passed on to the user. For instance a userDelete() method. I just want to know whether the user was deleted, and if not, why?
My previous approach was to return true if deleted, and a string otherwise. This made if statements a little tricky because
if ($output = $this->someMethod())
will return true for a string, so that doesn't help much.
My considerations for alternatives are:
Return an array
array ('status'=>'error', 'message' => 'You did not specify an existing user')
This will be compatible with the if statement shown above (i.e. will return 'false' when an array is returned). I would return true for a successful function call.
Use PHP's Exception class and try/catch blocks
When the code falls into an error (i.e. perform a check to see whether user exists, and it turns out negative)
if ($query->count == 0) {
throw new Exception("User does not exist");
}
and then on the calling page I would write:
try {
$this->someMethod();
} catch (Exception $e) {
echo $e->getMessage() //Or some other way of handling the error
}
If I proceed with this alternative, is that "bad form" in PHP? Should Exceptions be only used for actual coding errors (i.e. division by 0) instead of for 'higher level' application error handling / user feedback?
Remember: I plan on sending these error messages back to the user at some point during execution ... should I be concerned that other Exceptions thrown by PHP itself will make their way back to the user? Should I extend the Exception class to prevent this?
Personally I use something similar to your array idea since I can return and store that status and all other pieces of useful log info if I need to. If all goes well I simply return an empty array for consistency since if(someFunct()) would be true on success (if I used true as success) or on non-empty array. This way I just equate empty array (!someFunc()) to be success.
However, feel free to look at this post which I found to be pretty good about this topic.

Categories