Skip to content
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

JSONFormatter and normalizing of PHP objects #1733

Closed
digilist opened this issue Jul 9, 2022 · 2 comments
Closed

JSONFormatter and normalizing of PHP objects #1733

digilist opened this issue Jul 9, 2022 · 2 comments
Labels
Milestone

Comments

@digilist
Copy link

digilist commented Jul 9, 2022

Monolog version 2

Not sure if this is really a bug report or rather a feature request. But I noticed that some objects in the log context are not normalized like it is via the NormalizerFormatter and therefore disappear when using the JsonFormatter.

As an example, I am refering to the Symfony AuthenticatorManager that is writing a "Authenticator successful" log message after a successful authentication:

https://github.com/symfony/symfony/blob/25c2bb1c7c2f1d1f32955c5f0365ccbfcc447137/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php#L204

You can see there as well that the token is added to the log context (in my example it is an instance of UsernamePasswordToken).

On successful authentication and when using the StreamHandler with the default NormalizerFormatter, the output looks like this:

[2022-07-09T17:31:16.113589+02:00] security.INFO: Authenticator successful! {"token":{"Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken":"UsernamePasswordToken(user=\"foo@bar.com\", roles=\"ROLE_USER\")"},"authenticator":"Symfony\\Component\\Security\\Http\\Authenticator\\FormLoginAuthenticator"} {}

And when the JsonFormatter is used, it looks like this:

{"message":"Authenticator successful!","context":{"token":{},"authenticator":"Symfony\\Component\\Security\\Http\\Authenticator\\FormLoginAuthenticator"},"level":200,"level_name":"INFO","channel":"security","datetime":"2022-07-09T17:31:16.113589+02:00","extra":{}

As you can see, the token disappeared. I already did a bit of investigation and noticed that in the NormalizerFormatter::normalize() method contains some logic for objects:

if (is_object($data)) {
if ($data instanceof Throwable) {
return $this->normalizeException($data, $depth);
}
if ($data instanceof \JsonSerializable) {
/** @var null|scalar|array<mixed[]|scalar|null> $value */
$value = $data->jsonSerialize();
} elseif (method_exists($data, '__toString')) {
/** @var string $value */
$value = $data->__toString();
} else {
// the rest is normalized by json encoding and decoding it
/** @var null|scalar|array<mixed[]|scalar|null> $value */
$value = json_decode($this->toJson($data, true), true);
}
return [Utils::getClass($data) => $value];
}

The JsonFormatter::normalize() doesn't contain such logic.

My guess is that objects are not serialized, because json_encode is taking care of it. However, private fields in PHP are not part of the encoded JSON and therefore the information gets lost.

My suggestion for a fix would be to add a similar logic for the JSON normalizer if the objects implements JSONSerializable or has a __toString() method. What do you think about it? I can provide a PR if this proposal sounds reasonable to you.

@digilist digilist added the Bug label Jul 9, 2022
@Seldaek Seldaek added this to the 2.x milestone Jul 22, 2022
@Seldaek
Copy link
Owner

Seldaek commented Jul 22, 2022

JSONSerializable is already handled internally by json_encode, which is why there was no speical object treatment, but we need to add toString if it's present too.

@digilist
Copy link
Author

Thank you! 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants