Passed
Push — feature_AddTestsAndReduceCodeC... ( b4fc83...65fe10 )
by Markus
02:09
created

SeqCompactJsonFormatter   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 207
rs 8.8
c 0
b 0
f 0
wmc 36

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getContentType() 0 2 1
A getExtractExtras() 0 3 1
A __construct() 0 6 1
A setExtractExtras() 0 5 1
A setExtractContent() 0 5 1
A getExtractContent() 0 3 1
A normalizeArray() 0 15 3
A normalize() 0 11 4
B processLogRecord() 0 15 8
A processExtras() 0 11 4
A processDateTime() 0 8 2
A processMessage() 0 8 2
A processContextArray() 0 7 3
A processContext() 0 9 2
A processContextException() 0 10 2
1
<?php
2
3
namespace Msschl\Monolog\Formatter;
4
5
use DateTime;
6
use Monolog\Formatter\FormatterInterface;
7
use Monolog\Formatter\JsonFormatter;
8
use Throwable;
9
10
/**
11
 * This file is part of the msschl\monolog-seq-handler package.
12
 *
13
 * Copyright (c) 2018 Markus Schlotbohm
14
 *
15
 * For the full copyright and license information, please view the LICENSE.md
16
 * file that was distributed with this source code.
17
 */
18
class SeqCompactJsonFormatter extends SeqBaseFormatter
19
{
20
21
    /**
22
     * The extract context flag.
23
     * Whether to extract the context array to the root or not.
24
     *
25
     * @var bool
26
     */
27
    protected $extractContext;
28
29
    /**
30
     * The extract extras flag.
31
     * Whether to extract the extras array to the root or not.
32
     *
33
     * @var bool
34
     */
35
    protected $extractExtras;
36
37
    /**
38
     * Initializes a new instance of the {@see SeqCompactJsonFormatter} class.
39
     *
40
     * @param  bool $extractContext Flag that indicates whether to extract the extras array
41
     *                              to the root or not.
42
     * @param  bool $extractExtras  Flag that indicates whether to extract the context array
43
     *                              to the root or not.
44
     */
45
	public function __construct(bool $extractContext = true, bool $extractExtras = true)
46
	{
47
        $this->appendNewline = false;
48
        $this->batchMode = JsonFormatter::BATCH_MODE_NEWLINES;
49
        $this->extractContext = $extractContext;
50
        $this->extractExtras = $extractExtras;
51
	}
52
53
    /**
54
     * Returns a string with the content type for the seq-formatter.
55
     *
56
     * @return string
57
     */
58
    public function getContentType() : string {
59
        return 'application/vnd.serilog.clef';
60
    }
61
62
    /**
63
     * Gets whether the flag extract content is set or not.
64
     *
65
     * @return bool
66
     */
67
    public function getExtractContent() : bool
68
    {
69
        return $this->extractContext;
70
    }
71
72
    /**
73
     * Sets the flag extract content.
74
     *
75
     * @param  bool $value The flag.
76
     * @return self
77
     */
78
    public function setExtractContent(bool $value)
79
    {
80
        $this->extractContext = $value;
81
82
        return $this;
83
    }
84
85
    /**
86
     * Gets whether the flag extract extras is set or not.
87
     *
88
     * @return bool
89
     */
90
    public function getExtractExtras()
91
    {
92
        return $this->extractExtras;
93
    }
94
95
    /**
96
     * Sets the flag extract extras.
97
     *
98
     * @param  bool $value The flag.
99
     * @return self
100
     */
101
    public function setExtractExtras(bool $value)
102
    {
103
        $this->extractExtras = $value;
104
105
        return $this;
106
    }
107
108
    /**
109
     * Normalizes given $data.
110
     *
111
     * @param mixed $data The data to normalize.
112
     * @return mixed
113
     */
114
    protected function normalize($data)
115
    {
116
        if (is_array($data) || $data instanceof \Traversable) {
117
            return $this->normalizeArray($data);
118
        }
119
120
        if ($data instanceof \Throwable) {
121
            return $this->normalizeException($data);
122
        }
123
124
        return $data;
125
    }
126
127
    private function normalizeArray($array)
128
    {
129
        $normalized = array();
130
131
        $count = 1;
132
        foreach ($array as $key => $value) {
133
            if ($count++ >= 1000) {
134
                $normalized['...'] = 'Over 1000 items, aborting normalization';
135
                break;
136
            }
137
138
            $normalized = $this->processLogRecord($normalized, $key, $value, $count);
139
        }
140
141
        return $normalized;
142
    }
143
144
    private function processLogRecord($array, $key, $value, /** @scrutinizer ignore-unused */ $count)
145
    {
146
        switch ($key) {
147
            case 'message': return $this->processMessage($array, $value);
148
            case 'datetime': return $this->processDateTime($array, $value);
149
            case 'level':
150
                $array['@l'] = $this->logLevelMap[$value];
151
                $array['LogLevelCode'] = $value;
152
                return $array;
153
            case 'level_name': return $array;
154
            case 'extra': return $this->processExtras($array, $value);
155
            case 'context': return $this->processContext($array, $value);
156
            default:
157
                $array[is_int($key) ? $key : SeqCompactJsonFormatter::ConvertSnakeCaseToPascalCase($key)] = $this->normalize($value);
158
                return $array;
159
        }
160
    }
161
162
    private function processMessage($array, $value)
163
    {
164
        $array['@m'] = $value;
165
        if (!(strpos($value, '{') === false)) {
166
            $array['@mt'] = $value;
167
        }
168
169
        return $array;
170
    }
171
172
    private function processDateTime($array, $value)
173
    {
174
        if ($value instanceof \DateTime) {
175
            $value = $value->format(DateTime::ISO8601);
176
        }
177
        $array['@t'] = $value;
178
179
        return $array;
180
    }
181
182
    private function processExtras($array, $value)
183
    {
184
        if (is_array($value) && is_array($normalizedArray = $this->normalize($value))) {
185
            if ($this->extractExtras) {
186
                $array = array_merge($normalizedArray, $array);
187
            } else {
188
                $array['Extra'] = $normalizedArray;
189
            }
190
        }
191
192
        return $array;
193
    }
194
195
    private function processContext($array, $value)
196
    {
197
        if (!is_array($value)) {
198
            return $array;
199
        }
200
201
        $array = $this->processContextArray($array, $value);
202
203
        return $this->processContextException($array, $value);
204
    }
205
206
    private function processContextArray(array $array, array $value) : array
207
    {
208
        if (is_array($normalizedArray = $this->normalize($value))) {
209
            return $this->extractContext ? array_merge($normalizedArray, $array) : $normalizedArray;
210
        }
211
212
        return $array;
213
    }
214
215
    private function processContextException(array $array, array $value) : array
216
    {
217
        $exception = $this->extractException($value);
218
        if ($exception === null) {
219
            return $array;
220
        }
221
222
        $array['@x'] = $this->normalizeException($exception);
223
224
        return $array;
225
    }
226
}