| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- <?php declare(strict_types=1);
- /*
- * 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 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;
- public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $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.
- */
- public function getBatchMode(): int
- {
- return $this->batchMode;
- }
- /**
- * True if newlines are appended to every formatted record
- */
- public function isAppendingNewlines(): bool
- {
- return $this->appendNewline;
- }
- /**
- * {@inheritdoc}
- */
- public function format(array $record): string
- {
- return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
- }
- /**
- * {@inheritdoc}
- */
- public function formatBatch(array $records): string
- {
- 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(bool $include = true)
- {
- $this->includeStacktraces = $include;
- }
- /**
- * Return a JSON-encoded array of records.
- */
- protected function formatBatchJson(array $records): string
- {
- return $this->toJson($this->normalize($records), true);
- }
- /**
- * Use new lines to separate records instead of a
- * JSON-encoded array.
- */
- protected function formatBatchNewlines(array $records): string
- {
- $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, int $depth = 0)
- {
- if ($depth > 9) {
- return 'Over 9 levels deep, aborting normalization';
- }
- if (is_array($data) || $data instanceof \Traversable) {
- $normalized = [];
- $count = 1;
- foreach ($data as $key => $value) {
- if ($count++ >= 1000) {
- $normalized['...'] = 'Over 1000 items, aborting normalization';
- break;
- }
- $normalized[$key] = $this->normalize($value, $depth + 1);
- }
- return $normalized;
- }
- if ($data instanceof Throwable) {
- return $this->normalizeException($data, $depth);
- }
- return $data;
- }
- /**
- * Normalizes given exception with or without its own stack trace based on
- * `includeStacktraces` property.
- */
- protected function normalizeException(Throwable $e, int $depth = 0): array
- {
- $data = [
- 'class' => get_class($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, $depth + 1);
- }
- return $data;
- }
- }
|