diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index eb071329..779e18bb 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -202,8 +202,12 @@ class NormalizerFormatter implements FormatterInterface $data['faultactor'] = $e->faultactor; } - if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) { - $data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail); + if (isset($e->detail)) { + if (is_string($e->detail)) { + $data['detail'] = $e->detail; + } elseif (is_object($e->detail) || is_array($e->detail)) { + $data['detail'] = $this->toJson($e->detail, true); + } } } diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index c1ff25b5..f61e5eb6 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use InvalidArgumentException; use Monolog\Logger; +use Monolog\Utils; /** * Stores logs to files that are rotated every day and a limited number of files are kept. @@ -46,7 +47,7 @@ class RotatingFileHandler extends StreamHandler */ public function __construct(string $filename, int $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { - $this->filename = $filename; + $this->filename = Utils::canonicalizePath($filename); $this->maxFiles = $maxFiles; $this->nextRotation = new \DateTimeImmutable('tomorrow'); $this->filenameFormat = '{filename}-{date}'; diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 4cce3c39..215ae02c 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Stores to any stream resource @@ -46,7 +47,7 @@ class StreamHandler extends AbstractProcessingHandler if (is_resource($stream)) { $this->stream = $stream; } elseif (is_string($stream)) { - $this->url = $stream; + $this->url = Utils::canonicalizePath($stream); } else { throw new \InvalidArgumentException('A stream must either be a resource or a string.'); } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 240b3742..a6977b92 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -34,6 +34,34 @@ final class Utils return substr($string, $start, $length); } + /** + * Makes sure if a relative path is passed in it is turned into an absolute path + * + * @param string $streamUrl stream URL or path without protocol + */ + public static function canonicalizePath(string $streamUrl): string + { + $prefix = ''; + if ('file://' === substr($streamUrl, 0, 7)) { + $streamUrl = substr($streamUrl, 7); + $prefix = 'file://'; + } + + // other type of stream, not supported + if (false !== strpos($streamUrl, '://')) { + return $streamUrl; + } + + // already absolute + if (substr($streamUrl, 0, 1) === '/' || substr($streamUrl, 1, 1) === ':' || substr($streamUrl, 0, 2) === '\\\\') { + return $prefix.$streamUrl; + } + + $streamUrl = getcwd() . '/' . $streamUrl; + + return $prefix.$streamUrl; + } + /** * Return the JSON representation of a value * diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 9ea7f080..3b06380b 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -87,7 +87,7 @@ class NormalizerFormatterTest extends TestCase } $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', (object) ['foo' => 'world']); + $e = new \SoapFault('foo', 'bar', 'hello', 'world'); $formatted = $formatter->format([ 'exception' => $e, ]); @@ -105,6 +105,26 @@ class NormalizerFormatterTest extends TestCase 'detail' => 'world', ], ], $formatted); + + $formatter = new NormalizerFormatter('Y-m-d'); + $e = new \SoapFault('foo', 'bar', 'hello', (object) array('bar' => (object) array('biz' => 'baz'), 'foo' => 'world')); + $formatted = $formatter->format(array( + 'exception' => $e, + )); + + unset($formatted['exception']['trace']); + + $this->assertEquals(array( + 'exception' => array( + 'class' => 'SoapFault', + 'message' => 'bar', + 'code' => 0, + 'file' => $e->getFile().':'.$e->getLine(), + 'faultcode' => 'foo', + 'faultactor' => 'hello', + 'detail' => '{"bar":{"biz":"baz"},"foo":"world"}', + ), + ), $formatted); } public function testFormatToStringExceptionHandle() diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index 529e88ea..c74b96eb 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -13,6 +13,29 @@ namespace Monolog; class UtilsTest extends \PHPUnit_Framework_TestCase { + /** + * @param string $expected + * @param string $input + * @dataProvider providePathsToCanonicalize + */ + public function testCanonicalizePath($expected, $input) + { + $this->assertSame($expected, Utils::canonicalizePath($input)); + } + + public function providePathsToCanonicalize() + { + return array( + array('/foo/bar', '/foo/bar'), + array('file://'.getcwd().'/bla', 'file://bla'), + array(getcwd().'/bla', 'bla'), + array(getcwd().'/./bla', './bla'), + array('file:///foo/bar', 'file:///foo/bar'), + array('any://foo', 'any://foo'), + array('\\\\network\path', '\\\\network\path'), + ); + } + /** * @param int $code * @param string $msg