Passed
Push — master ( dc96af...1f8a30 )
by Alexander
02:08
created

Target::setCommonContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 153
    public function __construct()
86
    {
87 153
        $this->categories = new CategoryFilter();
88 153
        $this->formatter = new Formatter();
89 153
    }
90
91
    /**
92
     * Processes the given log messages.
93
     *
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 89
    public function collect(array $messages, bool $final): void
101
    {
102 89
        $this->filterMessages($messages);
103 81
        $count = count($this->messages);
104
105 81
        if ($count > 0 && ($final || ($this->exportInterval > 0 && $count >= $this->exportInterval))) {
106
            // set exportInterval to 0 to avoid triggering export again while exporting
107 45
            $oldExportInterval = $this->exportInterval;
108 45
            $this->exportInterval = 0;
109 45
            $this->export();
110 39
            $this->exportInterval = $oldExportInterval;
111 39
            $this->messages = [];
112
        }
113 75
    }
114
115
    /**
116
     * Sets a list of log message categories that this target is interested in.
117
     *
118
     * @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 18
    public function setCategories(array $categories): self
127
    {
128 18
        $this->categories->include($categories);
129 12
        return $this;
130
    }
131
132
    /**
133
     * Sets a list of log message categories that this target is NOT interested in.
134
     *
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 9
    public function setExcept(array $except): self
144
    {
145 9
        $this->categories->exclude($except);
146 3
        return $this;
147
    }
148
149
    /**
150
     * Sets a list of log message levels that current target is interested in.
151
     *
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 15
    public function setLevels(array $levels): self
161
    {
162 15
        foreach ($levels as $key => $level) {
163 14
            $levels[$key] = Logger::validateLevel($level);
164
        }
165
166 9
        $this->levels = $levels;
167 9
        return $this;
168
    }
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 29
    public function setCommonContext(array $commonContext): self
180
    {
181 29
        $this->commonContext = $commonContext;
182 29
        return $this;
183
    }
184
185
    /**
186
     * 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 24
    public function setFormat(callable $format): self
195
    {
196 24
        $this->formatter->setFormat($format);
197 24
        return $this;
198
    }
199
200
    /**
201
     * 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 12
    public function setPrefix(callable $prefix): self
210
    {
211 12
        $this->formatter->setPrefix($prefix);
212 12
        return $this;
213
    }
214
215
    /**
216
     * 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 3
    public function setExportInterval(int $exportInterval): self
225
    {
226 3
        $this->exportInterval = $exportInterval;
227 3
        return $this;
228
    }
229
230
    /**
231
     * 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 3
    public function setTimestampFormat(string $format): self
240
    {
241 3
        $this->formatter->setTimestampFormat($format);
242 3
        return $this;
243
    }
244
245
    /**
246
     * 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 7
    public function setEnabled(callable $value): self
257
    {
258 7
        $this->enabled = $value;
259 7
        return $this;
260
    }
261
262
    /**
263
     * Enables the log target.
264
     *
265
     * @return self
266
     *
267
     * @see Target::$enabled
268
     */
269 1
    public function enable(): self
270
    {
271 1
        $this->enabled = true;
272 1
        return $this;
273
    }
274
275
    /**
276
     * Disables the log target.
277
     *
278
     * @return self
279
     *
280
     * @see Target::$enabled
281
     */
282 1
    public function disable(): self
283
    {
284 1
        $this->enabled = false;
285 1
        return $this;
286
    }
287
288
    /**
289
     * 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 30
    public function isEnabled(): bool
298
    {
299 30
        if (is_bool($this->enabled)) {
300 24
            return $this->enabled;
301
        }
302
303 7
        if (!is_bool($enabled = ($this->enabled)())) {
304 6
            throw new RuntimeException(sprintf(
305 6
                'The PHP callable "enabled" must returns a boolean, %s received.',
306 6
                gettype($enabled)
307
            ));
308
        }
309
310 1
        return $enabled;
311
    }
312
313
    /**
314
     * Gets a list of log messages that are retrieved from the logger so far by this log target.
315
     *
316
     * @return Message[] The list of log messages.
317
     */
318 56
    protected function getMessages(): array
319
    {
320 56
        return $this->messages;
321
    }
322
323
    /**
324
     * Gets a list of formatted log messages.
325
     *
326
     * @return string[] The list of formatted log messages.
327
     */
328 1
    protected function getFormattedMessages(): array
329
    {
330 1
        $formatted = [];
331
332 1
        foreach ($this->messages as $key => $message) {
333 1
            $formatted[$key] = $this->formatter->format($message, $this->commonContext);
334
        }
335
336 1
        return $formatted;
337
    }
338
339
    /**
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 20
    protected function formatMessages(string $separator = ''): string
347
    {
348 20
        $formatted = '';
349
350 20
        foreach ($this->messages as $message) {
351 20
            $formatted .= $this->formatter->format($message, $this->commonContext) . $separator;
352
        }
353
354 8
        return $formatted;
355
    }
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 25
    protected function getCommonContext(): array
363
    {
364 25
        return $this->commonContext;
365
    }
366
367
    /**
368
     * Filters the given messages according to their categories and levels.
369
     *
370
     * @param array $messages List log messages to be filtered.
371
     *
372
     * @throws InvalidArgumentException for non-instance Message.
373
     *
374
     * @return Message[] The filtered log messages.
375
     */
376 89
    private function filterMessages(array $messages): array
377
    {
378 89
        foreach ($messages as $i => $message) {
379 89
            if (!($message instanceof Message)) {
380 8
                throw new InvalidArgumentException('You must provide an instance of \Yiisoft\Log\Message.');
381
            }
382
383 81
            if ((!empty($this->levels) && !in_array(($message->level()), $this->levels, true))) {
384 7
                unset($messages[$i]);
385 7
                continue;
386
            }
387
388 81
            if ($this->categories->isExcluded($message->context('category', ''))) {
389 13
                unset($messages[$i]);
390 13
                continue;
391
            }
392
393 80
            $this->messages[] = $message;
394
        }
395
396 81
        return $messages;
397
    }
398
}
399