Test Failed
Pull Request — master (#56)
by Evgeniy
02:21
created

Target::filterMessages()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 11
nc 5
nop 1
dl 0
loc 21
rs 9.2222
c 1
b 0
f 0
ccs 8
cts 8
cp 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Log;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
use Yiisoft\Log\Message\CategoryFilter;
10
use Yiisoft\Log\Message\Formatter;
11
12
use function count;
13
use function gettype;
14
use function in_array;
15
use function is_bool;
16
use function sprintf;
17
18
/**
19
 * Target is the base class for all log target classes.
20
 *
21
 * A log target object will filter the messages logged by {@see \Yiisoft\Log\Logger} according
22
 * to its {@see Target::setLevels()} and {@see Target::setCategories()}. It may also export
23
 * the filtered messages to specific destination defined by the target, such as emails, files.
24
 *
25
 * Level filter and category filter are combinatorial, i.e., only messages
26
 * satisfying both filter conditions will be handled. Additionally, you may
27
 * specify {@see Target::setExcept()} to exclude messages of certain categories.
28
 */
29
abstract class Target
30
{
31
    private CategoryFilter $categories;
32
    private Formatter $formatter;
33
34
    /**
35
     * @var Message[] The log messages.
36
     */
37
    private array $messages = [];
38
39
    /**
40
     * @var string[] The log message levels that this target is interested in.
41
     *
42
     * @see LogLevel See constants for valid level names.
43
     *
44
     * The value should be an array of level names.
45
     *
46
     * For example:
47
     *
48
     * ```php
49
     * ['error', 'warning'],
50
     * // or
51
     * [LogLevel::ERROR, LogLevel::WARNING]
52
     * ```
53
     *
54
     * Defaults is empty array, meaning all available levels.
55
     */
56
    private array $levels = [];
57
58
    /**
59
     * @var array The user parameters in the `key => value` format that should be logged in a each message.
60
     */
61
    private array $commonContext = [];
62
63
    /**
64
     * @var int How many log messages should be accumulated before they are exported.
65
     *
66
     * Defaults to 1000. Note that messages will always be exported when the application terminates.
67
     * Set this property to be 0 if you don't want to export messages until the application terminates.
68
     */
69
    private int $exportInterval = 1000;
70
71
    /**
72
     * @var bool|callable Enables or disables the current target to export.
73
     */
74
    private $enabled = true;
75
76
    /**
77
     * Exports log messages to a specific destination.
78
     * Child classes must implement this method.
79
     */
80
    abstract protected function export(): void;
81
82
    /**
83
     * When defining a constructor in child classes, you must call `parent::__construct()`.
84
     */
85
    public function __construct()
86
    {
87
        $this->categories = new CategoryFilter();
88 140
        $this->formatter = new Formatter();
89
    }
90 140
91 140
    /**
92 140
     * Processes the given log messages.
93 140
     *
94
     * This method will filter the given messages with levels and categories.
95
     * And if requested, it will also export the filtering result to specific medium (e.g. email).
96
     *
97
     * @param Message[] $messages Log messages to be processed.
98
     * @param bool $final Whether this method is called at the end of the current application.
99
     */
100
    public function collect(array $messages, bool $final): void
101
    {
102
        $this->filterMessages($messages);
103
        $count = count($this->messages);
104
105 72
        if ($count > 0 && ($final || ($this->exportInterval > 0 && $count >= $this->exportInterval))) {
106
            // set exportInterval to 0 to avoid triggering export again while exporting
107 72
            $oldExportInterval = $this->exportInterval;
108 68
            $this->exportInterval = 0;
109
            $this->export();
110 68
            $this->exportInterval = $oldExportInterval;
111
            $this->messages = [];
112 31
        }
113 31
    }
114 31
115 25
    /**
116 25
     * Sets a list of log message categories that this target is interested in.
117
     *
118 62
     * @param array $categories The list of log message categories.
119
     *
120
     * @throws InvalidArgumentException for invalid log message categories structure.
121
     *
122
     * @return self
123
     *
124
     * @see CategoryFilter::$include
125
     */
126
    public function setCategories(array $categories): self
127
    {
128
        $this->categories->include($categories);
129
        return $this;
130
    }
131 18
132
    /**
133 18
     * Sets a list of log message categories that this target is NOT interested in.
134 12
     *
135
     * @param array $except The list of log message categories.
136
     *
137
     * @throws InvalidArgumentException for invalid log message categories structure.
138
     *
139
     * @return self
140
     *
141
     * @see CategoryFilter::$exclude
142
     */
143
    public function setExcept(array $except): self
144
    {
145
        $this->categories->exclude($except);
146
        return $this;
147
    }
148 9
149
    /**
150 9
     * Sets a list of log message levels that current target is interested in.
151 3
     *
152
     * @param array $levels The list of log message levels.
153
     *
154
     * @throws InvalidArgumentException for invalid log message level.
155
     *
156
     * @return self
157
     *
158
     * @see Target::$levels
159
     */
160
    public function setLevels(array $levels): self
161
    {
162
        foreach ($levels as $key => $level) {
163
            $levels[$key] = Logger::validateLevel($level);
164
        }
165 15
166
        $this->levels = $levels;
167 15
        return $this;
168 9
    }
169
170
    /**
171
     * Sets a user parameters in the `key => value` format that should be logged in a each message.
172
     *
173
     * @param array $commonContext The user parameters in the `key => value` format.
174
     *
175
     * @return self
176
     *
177
     * @see Target::$commonContext
178
     */
179
    public function setCommonContext(array $commonContext): self
180
    {
181
        $this->commonContext = $commonContext;
182 131
        return $this;
183
    }
184 131
185 131
    /**
186 131
     * Sets a PHP callable that returns a string representation of the log message.
187
     *
188
     * @param callable $format The PHP callable to get a string value from.
189
     *
190
     * @return self
191
     *
192
     * @see Formatter::$format
193
     */
194
    public function setFormat(callable $format): self
195
    {
196
        $this->formatter->setFormat($format);
197
        return $this;
198 23
    }
199
200 23
    /**
201 23
     * Sets a PHP callable that returns a string to be prefixed to every exported message.
202
     *
203
     * @param callable $prefix The PHP callable to get a string prefix of the log message.
204
     *
205
     * @return self
206
     *
207
     * @see Formatter::$prefix
208
     */
209
    public function setPrefix(callable $prefix): self
210
    {
211
        $this->formatter->setPrefix($prefix);
212
        return $this;
213 24
    }
214
215 24
    /**
216 24
     * Sets how many messages should be accumulated before they are exported.
217
     *
218
     * @param int $exportInterval The number of log messages to accumulate before exporting.
219
     *
220
     * @return self
221
     *
222
     * @see Target::$exportInterval
223
     */
224
    public function setExportInterval(int $exportInterval): self
225
    {
226
        $this->exportInterval = $exportInterval;
227
        return $this;
228 12
    }
229
230 12
    /**
231 12
     * Sets a date format for the log timestamp.
232
     *
233
     * @param string $format The date format for the log timestamp.
234
     *
235
     * @return self
236
     *
237
     * @see Target::$timestampFormat
238
     */
239
    public function setTimestampFormat(string $format): self
240
    {
241
        $this->formatter->setTimestampFormat($format);
242
        return $this;
243 3
    }
244
245 3
    /**
246 3
     * Sets a PHP callable that returns a boolean indicating whether this log target is enabled.
247
     *
248
     * The signature of the callable should be `function (): bool;`.
249
     *
250
     * @param callable $value The PHP callable to get a boolean value.
251
     *
252
     * @return self
253
     *
254
     * @see Target::$enabled
255
     */
256
    public function setEnabled(callable $value): self
257
    {
258 3
        $this->enabled = $value;
259
        return $this;
260 3
    }
261 3
262
    /**
263
     * Enables the log target.
264
     *
265
     * @return self
266
     *
267
     * @see Target::$enabled
268
     */
269
    public function enable(): self
270
    {
271
        $this->enabled = true;
272
        return $this;
273 7
    }
274
275 7
    /**
276 7
     * Disables the log target.
277
     *
278
     * @return self
279
     *
280
     * @see Target::$enabled
281
     */
282
    public function disable(): self
283
    {
284
        $this->enabled = false;
285
        return $this;
286 1
    }
287
288 1
    /**
289 1
     * Check whether the log target is enabled.
290
     *
291
     * @throws RuntimeException for a callable "enabled" that does not return a boolean.
292
     *
293
     * @return bool The value indicating whether this log target is enabled.
294
     *
295
     * @see Target::$enabled
296
     */
297
    public function isEnabled(): bool
298
    {
299 1
        if (is_bool($this->enabled)) {
300
            return $this->enabled;
301 1
        }
302 1
303
        if (!is_bool($enabled = ($this->enabled)())) {
304
            throw new RuntimeException(sprintf(
305
                'The PHP callable "enabled" must returns a boolean, %s received.',
306
                gettype($enabled)
307
            ));
308
        }
309
310
        return $enabled;
311
    }
312
313
    /**
314 30
     * Gets a list of log messages that are retrieved from the logger so far by this log target.
315
     *
316 30
     * @return Message[] The list of log messages.
317 24
     */
318
    protected function getMessages(): array
319
    {
320 7
        return $this->messages;
321 6
    }
322 6
323 6
    /**
324
     * Gets a list of formatted log messages.
325
     *
326
     * @return string[] The list of formatted log messages.
327 1
     */
328
    protected function getFormattedMessages(): array
329
    {
330
        $formatted = [];
331
332
        foreach ($this->messages as $key => $message) {
333
            $formatted[$key] = $this->formatter->format($message, $this->commonContext);
334
        }
335
336
        return $formatted;
337 42
    }
338
339 42
    /**
340
     * Formats all log messages for display as a string.
341
     *
342
     * @param string $separator The log messages string separator.
343
     *
344
     * @return string The string formatted log messages.
345
     */
346
    protected function formatMessages(string $separator = ''): string
347 1
    {
348
        $formatted = '';
349 1
350
        foreach ($this->messages as $message) {
351 1
            $formatted .= $this->formatter->format($message, $this->commonContext) . $separator;
352 1
        }
353
354
        return $formatted;
355 1
    }
356
357
    /**
358
     * Gets a user parameters in the `key => value` format that should be logged in a each message.
359
     *
360
     * @return array The user parameters in the `key => value` format.
361
     */
362
    protected function getCommonContext(): array
363
    {
364
        return $this->commonContext;
365 21
    }
366
367 21
    /**
368
     * Filters the given messages according to their categories and levels.
369 21
     *
370 21
     * @param array $messages List log messages to be filtered.
371
     *
372
     * @throws InvalidArgumentException for non-instance Message.
373 9
     *
374
     * @return Message[] The filtered log messages.
375
     */
376
    private function filterMessages(array $messages): array
377
    {
378
        foreach ($messages as $i => $message) {
379
            if (!($message instanceof Message)) {
380
                throw new InvalidArgumentException('You must provide an instance of \Yiisoft\Log\Message.');
381
            }
382
383
            if ((!empty($this->levels) && !in_array(($message->level()), $this->levels, true))) {
384
                unset($messages[$i]);
385 72
                continue;
386
            }
387 72
388 72
            if ($this->categories->isExcluded($message->context('category', ''))) {
389
                unset($messages[$i]);
390 72
                continue;
391 7
            }
392 7
393
            $this->messages[] = $message;
394
        }
395 72
396 13
        return $messages;
397 13
    }
398
}
399