215 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?php
 | 
						|
 | 
						|
/*
 | 
						|
 * This file is part of the Monolog package.
 | 
						|
 *
 | 
						|
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 | 
						|
 *
 | 
						|
 * For the full copyright and license information, please view the LICENSE
 | 
						|
 * file that was distributed with this source code.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Monolog\Formatter;
 | 
						|
 | 
						|
use Exception;
 | 
						|
use Monolog\Utils;
 | 
						|
use Throwable;
 | 
						|
 | 
						|
/**
 | 
						|
 * Encodes whatever record data is passed to it as json
 | 
						|
 *
 | 
						|
 * This can be useful to log to databases or remote APIs
 | 
						|
 *
 | 
						|
 * @author Jordi Boggiano <j.boggiano@seld.be>
 | 
						|
 */
 | 
						|
class JsonFormatter extends NormalizerFormatter
 | 
						|
{
 | 
						|
    const BATCH_MODE_JSON = 1;
 | 
						|
    const BATCH_MODE_NEWLINES = 2;
 | 
						|
 | 
						|
    protected $batchMode;
 | 
						|
    protected $appendNewline;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var bool
 | 
						|
     */
 | 
						|
    protected $includeStacktraces = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param int $batchMode
 | 
						|
     * @param bool $appendNewline
 | 
						|
     */
 | 
						|
    public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
 | 
						|
    {
 | 
						|
        $this->batchMode = $batchMode;
 | 
						|
        $this->appendNewline = $appendNewline;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The batch mode option configures the formatting style for
 | 
						|
     * multiple records. By default, multiple records will be
 | 
						|
     * formatted as a JSON-encoded array. However, for
 | 
						|
     * compatibility with some API endpoints, alternative styles
 | 
						|
     * are available.
 | 
						|
     *
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    public function getBatchMode()
 | 
						|
    {
 | 
						|
        return $this->batchMode;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * True if newlines are appended to every formatted record
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function isAppendingNewlines()
 | 
						|
    {
 | 
						|
        return $this->appendNewline;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * {@inheritdoc}
 | 
						|
     */
 | 
						|
    public function format(array $record)
 | 
						|
    {
 | 
						|
        return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * {@inheritdoc}
 | 
						|
     */
 | 
						|
    public function formatBatch(array $records)
 | 
						|
    {
 | 
						|
        switch ($this->batchMode) {
 | 
						|
            case static::BATCH_MODE_NEWLINES:
 | 
						|
                return $this->formatBatchNewlines($records);
 | 
						|
 | 
						|
            case static::BATCH_MODE_JSON:
 | 
						|
            default:
 | 
						|
                return $this->formatBatchJson($records);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param bool $include
 | 
						|
     */
 | 
						|
    public function includeStacktraces($include = true)
 | 
						|
    {
 | 
						|
        $this->includeStacktraces = $include;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Return a JSON-encoded array of records.
 | 
						|
     *
 | 
						|
     * @param  array  $records
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function formatBatchJson(array $records)
 | 
						|
    {
 | 
						|
        return $this->toJson($this->normalize($records), true);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Use new lines to separate records instead of a
 | 
						|
     * JSON-encoded array.
 | 
						|
     *
 | 
						|
     * @param  array  $records
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function formatBatchNewlines(array $records)
 | 
						|
    {
 | 
						|
        $instance = $this;
 | 
						|
 | 
						|
        $oldNewline = $this->appendNewline;
 | 
						|
        $this->appendNewline = false;
 | 
						|
        array_walk($records, function (&$value, $key) use ($instance) {
 | 
						|
            $value = $instance->format($value);
 | 
						|
        });
 | 
						|
        $this->appendNewline = $oldNewline;
 | 
						|
 | 
						|
        return implode("\n", $records);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Normalizes given $data.
 | 
						|
     *
 | 
						|
     * @param mixed $data
 | 
						|
     *
 | 
						|
     * @return mixed
 | 
						|
     */
 | 
						|
    protected function normalize($data, $depth = 0)
 | 
						|
    {
 | 
						|
        if ($depth > 9) {
 | 
						|
            return 'Over 9 levels deep, aborting normalization';
 | 
						|
        }
 | 
						|
 | 
						|
        if (is_array($data) || $data instanceof \Traversable) {
 | 
						|
            $normalized = array();
 | 
						|
 | 
						|
            $count = 1;
 | 
						|
            foreach ($data as $key => $value) {
 | 
						|
                if ($count++ > 1000) {
 | 
						|
                    $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                $normalized[$key] = $this->normalize($value, $depth+1);
 | 
						|
            }
 | 
						|
 | 
						|
            return $normalized;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($data instanceof Exception || $data instanceof Throwable) {
 | 
						|
            return $this->normalizeException($data);
 | 
						|
        }
 | 
						|
 | 
						|
        return $data;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Normalizes given exception with or without its own stack trace based on
 | 
						|
     * `includeStacktraces` property.
 | 
						|
     *
 | 
						|
     * @param Exception|Throwable $e
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function normalizeException($e)
 | 
						|
    {
 | 
						|
        // TODO 2.0 only check for Throwable
 | 
						|
        if (!$e instanceof Exception && !$e instanceof Throwable) {
 | 
						|
            throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
 | 
						|
        }
 | 
						|
 | 
						|
        $data = array(
 | 
						|
            'class' => Utils::getClass($e),
 | 
						|
            'message' => $e->getMessage(),
 | 
						|
            'code' => $e->getCode(),
 | 
						|
            'file' => $e->getFile().':'.$e->getLine(),
 | 
						|
        );
 | 
						|
 | 
						|
        if ($this->includeStacktraces) {
 | 
						|
            $trace = $e->getTrace();
 | 
						|
            foreach ($trace as $frame) {
 | 
						|
                if (isset($frame['file'])) {
 | 
						|
                    $data['trace'][] = $frame['file'].':'.$frame['line'];
 | 
						|
                } elseif (isset($frame['function']) && $frame['function'] === '{closure}') {
 | 
						|
                    // We should again normalize the frames, because it might contain invalid items
 | 
						|
                    $data['trace'][] = $frame['function'];
 | 
						|
                } else {
 | 
						|
                    // We should again normalize the frames, because it might contain invalid items
 | 
						|
                    $data['trace'][] = $this->normalize($frame);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($previous = $e->getPrevious()) {
 | 
						|
            $data['previous'] = $this->normalizeException($previous);
 | 
						|
        }
 | 
						|
 | 
						|
        return $data;
 | 
						|
    }
 | 
						|
}
 |