From d9c0be8785b6fe87aa000ed3c536df7f1fb561bf Mon Sep 17 00:00:00 2001 From: Olivier Paroz Date: Mon, 8 Dec 2014 03:53:07 +0100 Subject: [PATCH] Dump Arrays, Objects and Exceptions to the log This is a first draft. It has only been tested with the ownlcloud logger. Some internal fields are JSON encoded several times which makes it harder to read. Most of the normalizer is borrowed from Monolog https://github.com/Seldaek/monolog/blob/master/src/Monolog/Formatter/NormalizerFormatter.php --- lib/private/log.php | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/lib/private/log.php b/lib/private/log.php index 021cc1578a7..86e9533647a 100644 --- a/lib/private/log.php +++ b/lib/private/log.php @@ -1,6 +1,8 @@ + * Copyright (c) 2014 Jordi Boggiano + * Copyright (c) 2014 Olivier Paroz * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. @@ -147,6 +149,8 @@ class Log implements ILogger { // interpolate $message as defined in PSR-3 $replace = array(); foreach ($context as $key => $val) { + // Allows us to dump arrays, objects and exceptions to the log + $val = $this->normalize($val); $replace['{' . $key . '}'] = $val; } @@ -156,4 +160,78 @@ class Log implements ILogger { $logger = $this->logger; call_user_func(array($logger, 'write'), $app, $message, $level); } + + private function normalize($data) { + if (null === $data || is_scalar($data)) { + return $data; + } + + if (is_array($data) || $data instanceof \Traversable) { + $normalized = array(); + $count = 1; + foreach ($data as $key => $value) { + if ($count++ >= 1000) { + $normalized['...'] = 'Over 1000 items, aborting normalization'; + break; + } + $normalized[$key] = $this->normalize($value); + } + + //return $normalized; + return $this->toJson($normalized, true); + } + + if (is_object($data)) { + if ($data instanceof \Exception) { + return $this->normalizeException($data); + } + + $arrayObject = new \ArrayObject($data); + $serializedObject = $arrayObject->getArrayCopy(); + return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($serializedObject, true)); + } + + if (is_resource($data)) { + return '[resource]'; + } + + return '[unknown(' . gettype($data) . ')]'; + } + + private function normalizeException(\Exception $e) { + $data = array( + 'class' => get_class($e), + 'message' => $e->getMessage(), + 'file' => $e->getFile() . ':' . $e->getLine(), + ); + $trace = $e->getTrace(); + foreach ($trace as $frame) { + if (isset($frame['file'])) { + $data['trace'][] = $frame['file'] . ':' . $frame['line']; + } else { + $data['trace'][] = $this->toJson($frame, true); + } + } + if ($previous = $e->getPrevious()) { + $data['previous'] = $this->normalizeException($previous); + } + + return $this->toJson($data, true); + } + + private function toJson($data, $ignoreErrors = false) { + // suppress json_encode errors since it's twitchy with some inputs + if ($ignoreErrors) { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return @json_encode($data); + } + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return json_encode($data); + } } -- 2.39.5