Get Monolog JSON Stack Trace as Array - php

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.

Related

PhpSpec test if log written with same data

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.

Do all PHP Exceptions have 'trace', 'message' and 'code' properties?

I have to write a log class that logs the data coming from an exception. To make things simpler, I wanted to know if it is okay to retrieve data inside the 'trace' array and extend this by adding 'message' and 'code' properties of the exception instance in PHP. But I am not sure if all thrown exception in PHP are guaranteed to have at least these three properties ('trace', 'message' and 'code'). Also suggest if there is a better way to log things.
Firstly it's better to use code already proven to be good. PHP community widely use Monolog library check it. If you still want to write your own logger you should stick to PSR-3 rules
Answering your question. PHP object thrown must be an instance of the Exception class or a subclass of Exception.
But you if you look at constructor of an Exception
public function __construct($message = null, $code = 0, Exception $previous = null);
You can throw empty exception.But there will be always code, file, trace and code. Code and Message can be empty.
You can read more about it on http://php.net/manual/en/language.exceptions.php

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

Facebook PHP SDK Throwing an Uncatchable OAuthException

I'm attempting to post an open graph action to the Facebook Graph API but receiving an OAuth Exception (#3501) User is already associated to the <object>. That's all well and good, I expect Facebook to throw that exception. I get some other exceptions regarding authenticating a user (maybe with old/stale sessions, whatever).
My question is, has anyone else experienced that this exception is uncatchable in php? In this specific example (of posting graph actions) I am absolutely wrapping the call to the api in a try/catch statement; but I still get the fatal error.
<?php
try {
//publishing to open graph
$this->fb->api('/me/app:action', 'POST', array(
'object' => 'http://www.domain.com/path/to/graph/object',
));
}
catch (Exception $e)
{
/*
We may get here if the user has already posted this action before...
or if our session somehow went sour
or bc facebook is down...
or one of any other 1000 reasons the graph api is currently
sucking...
in any case it doesn't much matter, this is not a mission critical
thing to worry about; if we don't post the graph action - we don't
post the graph action..nbd.
*/
}
The above code is the snippet the publishes the graph action (generalized, because the content of it isn't important to this example).
I realize that the Exception that the Facebook PHP SDK is throwing is a FacebookApiException but that class extends Exception. I can't for the life of me figure out why in the name of all things logical, I can't catch my exception like this.
Has anyone experienced this issue? Is this a bug in the FB PHP SDK? Am I missing something else here? Thanks for your help!
Also, for reference, the relevant parts of the FB PHP SDK are here:
FacebookAPIException Definition (base_facebook.php line 30)
Throwing OAuthException (base_facebook.php line 1105
Edit 5/1/12
After some more investigation, it turns out that this "Exception" isn't really being treated like an exception at all. Typical Exceptions print out a stack trace back to the method call which resulted in throwing the exception. These "OAuthExceptions" do not. Also, typical exceptions pring out their error string a bit differently, for example:
PHP Fatal error: Uncaught exception 'Exception' with message 'foo' /path/to/file.php:10
or
PHP Fatal error: Uncaught exception 'MyException' with message 'stupid php' /path/to/file:10
#0 /path/to/file.php(17): doTest()
#1 {main}
thrown in /path/to/file.php on line 10
In this particular case, we don't get any of that, and it looks much more like a typical fatal error:
PHP Fatal error: Uncaught OAuthException: (#3501) User is already associated \
to the <object> object on a unique action type <action>. Original Action ID: \
123123123
thrown in /path/to/app/libs/fb/base_facebook.php on line 1107, \
referer: http://www.domain.com/path/to/page
I can't make any sense of why this forsaken "Exception" is so weird/uncatchable.
The Solution:
I figured out the answer to my own question; I've added it below - it's developer error, not a bug. The answer is below.
Also, this very well could be part of a bug, if you wanted to say that being able to reference a class definition as a type-hint to the catch definition which didn't exist (or wasn't available in the current namespace) is a bug.
So, something that's not outline above is that I'm utilizing PHP namespaces. This is a big gotchta since namespaces are relatively new to php, it's super easily overlooked I feel. Regardless, it's a pretty silly oversight/error.
If you're in a defined namespace (that is, not the root (\) namespace) you don't have direct access to the Exception class. Instead of php throwing a warning about not knowing what that class is, it just ignores the fact that it doesn't know what it is - and doesn't catch the exception.
Solution 1:
import the exception class:
<?php
use \Exception;
// ...codes
try {
//...codes
}
catch (Exception $e)
{
//...codes
}
Solution 2:
provide the full path to the exception class:
<?php
try {
//.....
}
catch (\Exception $e)
{
// voila.
}

How to make Zend Framework error page to look more clearly and beautifully?

By default error page in ZF looks like this:
Fatal error: Uncaught exception 'Zend_Form_Exception' with message 'Method setDeault does not exist' in /usr/home/.../library/Zend/Form.php:2838
Stack trace:
#0 [internal function]: Zend_Form->__call('setDeault', Array)
#1 /usr/home/.../application/admin/controllers/TagsController.php(40): Web_Form_Admintags->setDeault('tagstext', '....')
#2 /usr/home/.../library/Zend/
Is there any ways to change this messy error description to more clearly form (something like Django error page)?
This is not an error page but a standard PHP output for uncaught exceptions. As far as I know there is no default error page in Zend Framework -- you will have to create your own by creating an appropriate view for the ErrorController.
AFAICR this is using the Error controller right? That message is basically the dump of the exception object. You can split this up by calling different parts individually rather than dumping the whole lot as a string. See the manual page I linked to.
Make sure you're only providing exception information when the APPLICATION_ENVIRONMENT is set to development as well.
The exception is formatted using new lines, which are however not transformed to in html.
You have several options...
Wrap the error with <pre></pre> tags
Create custom exception handler
function exception_handler($exception) {
echo "Uncaught exception: " , $exception->getMessage(), "\n";
}
set_exception_handler('exception_handler');

Categories