From: Olivier Paroz Date: Mon, 8 Dec 2014 02:53:07 +0000 (+0100) Subject: Dump Arrays, Objects and Exceptions to the log X-Git-Tag: v8.0.0alpha1~157 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d9c0be8785b6fe87aa000ed3c536df7f1fb561bf;p=nextcloud-server.git 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 --- 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); + } }