scratch – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
115 office 1 <?php
2  
3 /*
4 * This file is part of the Monolog package.
5 *
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11  
12 namespace Monolog\Formatter;
13  
14 use Exception;
15 use Throwable;
16  
17 /**
18 * Encodes whatever record data is passed to it as json
19 *
20 * This can be useful to log to databases or remote APIs
21 *
22 * @author Jordi Boggiano <j.boggiano@seld.be>
23 */
24 class JsonFormatter extends NormalizerFormatter
25 {
26 const BATCH_MODE_JSON = 1;
27 const BATCH_MODE_NEWLINES = 2;
28  
29 protected $batchMode;
30 protected $appendNewline;
31  
32 /**
33 * @var bool
34 */
35 protected $includeStacktraces = false;
36  
37 /**
38 * @param int $batchMode
39 * @param bool $appendNewline
40 */
41 public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
42 {
43 $this->batchMode = $batchMode;
44 $this->appendNewline = $appendNewline;
45 }
46  
47 /**
48 * The batch mode option configures the formatting style for
49 * multiple records. By default, multiple records will be
50 * formatted as a JSON-encoded array. However, for
51 * compatibility with some API endpoints, alternative styles
52 * are available.
53 *
54 * @return int
55 */
56 public function getBatchMode()
57 {
58 return $this->batchMode;
59 }
60  
61 /**
62 * True if newlines are appended to every formatted record
63 *
64 * @return bool
65 */
66 public function isAppendingNewlines()
67 {
68 return $this->appendNewline;
69 }
70  
71 /**
72 * {@inheritdoc}
73 */
74 public function format(array $record)
75 {
76 return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
77 }
78  
79 /**
80 * {@inheritdoc}
81 */
82 public function formatBatch(array $records)
83 {
84 switch ($this->batchMode) {
85 case static::BATCH_MODE_NEWLINES:
86 return $this->formatBatchNewlines($records);
87  
88 case static::BATCH_MODE_JSON:
89 default:
90 return $this->formatBatchJson($records);
91 }
92 }
93  
94 /**
95 * @param bool $include
96 */
97 public function includeStacktraces($include = true)
98 {
99 $this->includeStacktraces = $include;
100 }
101  
102 /**
103 * Return a JSON-encoded array of records.
104 *
105 * @param array $records
106 * @return string
107 */
108 protected function formatBatchJson(array $records)
109 {
110 return $this->toJson($this->normalize($records), true);
111 }
112  
113 /**
114 * Use new lines to separate records instead of a
115 * JSON-encoded array.
116 *
117 * @param array $records
118 * @return string
119 */
120 protected function formatBatchNewlines(array $records)
121 {
122 $instance = $this;
123  
124 $oldNewline = $this->appendNewline;
125 $this->appendNewline = false;
126 array_walk($records, function (&$value, $key) use ($instance) {
127 $value = $instance->format($value);
128 });
129 $this->appendNewline = $oldNewline;
130  
131 return implode("\n", $records);
132 }
133  
134 /**
135 * Normalizes given $data.
136 *
137 * @param mixed $data
138 *
139 * @return mixed
140 */
141 protected function normalize($data)
142 {
143 if (is_array($data) || $data instanceof \Traversable) {
144 $normalized = array();
145  
146 $count = 1;
147 foreach ($data as $key => $value) {
148 if ($count++ >= 1000) {
149 $normalized['...'] = 'Over 1000 items, aborting normalization';
150 break;
151 }
152 $normalized[$key] = $this->normalize($value);
153 }
154  
155 return $normalized;
156 }
157  
158 if ($data instanceof Exception || $data instanceof Throwable) {
159 return $this->normalizeException($data);
160 }
161  
162 return $data;
163 }
164  
165 /**
166 * Normalizes given exception with or without its own stack trace based on
167 * `includeStacktraces` property.
168 *
169 * @param Exception|Throwable $e
170 *
171 * @return array
172 */
173 protected function normalizeException($e)
174 {
175 // TODO 2.0 only check for Throwable
176 if (!$e instanceof Exception && !$e instanceof Throwable) {
177 throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
178 }
179  
180 $data = array(
181 'class' => get_class($e),
182 'message' => $e->getMessage(),
183 'code' => $e->getCode(),
184 'file' => $e->getFile().':'.$e->getLine(),
185 );
186  
187 if ($this->includeStacktraces) {
188 $trace = $e->getTrace();
189 foreach ($trace as $frame) {
190 if (isset($frame['file'])) {
191 $data['trace'][] = $frame['file'].':'.$frame['line'];
192 } elseif (isset($frame['function']) && $frame['function'] === '{closure}') {
193 // We should again normalize the frames, because it might contain invalid items
194 $data['trace'][] = $frame['function'];
195 } else {
196 // We should again normalize the frames, because it might contain invalid items
197 $data['trace'][] = $this->normalize($frame);
198 }
199 }
200 }
201  
202 if ($previous = $e->getPrevious()) {
203 $data['previous'] = $this->normalizeException($previous);
204 }
205  
206 return $data;
207 }
208 }