Target::setPrefix()   A
last analyzed

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 147
    public function __construct()
86
    {
87 147
        $this->categories = new CategoryFilter();
88 147
        $this->formatter = new Formatter();
89
    }
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
    }
114
115
    /**
116
     * Sets a list of log message categories that this target is interested in.
117
     *
118
     * @param string[] $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 string[] $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 string[] $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
            Logger::assertLevelIsValid($level);
164 8
            $levels[$key] = $level;
165
        }
166
167 9
        $this->levels = $levels;
168 9
        return $this;
169
    }
170
171
    /**
172
     * Sets a user parameters in the `key => value` format that should be logged in a each message.
173
     *
174
     * @param array $commonContext The user parameters in the `key => value` format.
175
     *
176
     * @return self
177
     *
178
     * @see Target::$commonContext
179
     */
180 29
    public function setCommonContext(array $commonContext): self
181
    {
182 29
        $this->commonContext = $commonContext;
183 29
        return $this;
184
    }
185
186
    /**
187
     * Sets a PHP callable that returns a string representation of the log message.
188
     *
189
     * @param callable $format The PHP callable to get a string value from.
190
     *
191
     * @return self
192
     *
193
     * @see Formatter::$format
194
     */
195 24
    public function setFormat(callable $format): self
196
    {
197 24
        $this->formatter->setFormat($format);
198 24
        return $this;
199
    }
200
201
    /**
202
     * Sets a PHP callable that returns a string to be prefixed to every exported message.
203
     *
204
     * @param callable $prefix The PHP callable to get a string prefix of the log message.
205
     *
206
     * @return self
207
     *
208
     * @see Formatter::$prefix
209
     */
210 12
    public function setPrefix(callable $prefix): self
211
    {
212 12
        $this->formatter->setPrefix($prefix);
213 12
        return $this;
214
    }
215
216
    /**
217
     * Sets how many messages should be accumulated before they are exported.
218
     *
219
     * @param int $exportInterval The number of log messages to accumulate before exporting.
220
     *
221
     * @return self
222
     *
223
     * @see Target::$exportInterval
224
     */
225 3
    public function setExportInterval(int $exportInterval): self
226
    {
227 3
        $this->exportInterval = $exportInterval;
228 3
        return $this;
229
    }
230
231
    /**
232
     * Sets a date format for the log timestamp.
233
     *
234
     * @param string $format The date format for the log timestamp.
235
     *
236
     * @return self
237
     *
238
     * @see Target::$timestampFormat
239
     */
240 3
    public function setTimestampFormat(string $format): self
241
    {
242 3
        $this->formatter->setTimestampFormat($format);
243 3
        return $this;
244
    }
245
246
    /**
247
     * Sets a PHP callable that returns a boolean indicating whether this log target is enabled.
248
     *
249
     * The signature of the callable should be `function (): bool;`.
250
     *
251
     * @param callable $value The PHP callable to get a boolean value.
252
     *
253
     * @return self
254
     *
255
     * @see Target::$enabled
256
     */
257 7
    public function setEnabled(callable $value): self
258
    {
259 7
        $this->enabled = $value;
260 7
        return $this;
261
    }
262
263
    /**
264
     * Enables the log target.
265
     *
266
     * @return self
267
     *
268
     * @see Target::$enabled
269
     */
270 1
    public function enable(): self
271
    {
272 1
        $this->enabled = true;
273 1
        return $this;
274
    }
275
276
    /**
277
     * Disables the log target.
278
     *
279
     * @return self
280
     *
281
     * @see Target::$enabled
282
     */
283 1
    public function disable(): self
284
    {
285 1
        $this->enabled = false;
286 1
        return $this;
287
    }
288
289
    /**
290
     * Check whether the log target is enabled.
291
     *
292
     * @throws RuntimeException for a callable "enabled" that does not return a boolean.
293
     *
294
     * @return bool The value indicating whether this log target is enabled.
295
     *
296
     * @see Target::$enabled
297
     */
298 30
    public function isEnabled(): bool
299
    {
300 30
        if (is_bool($this->enabled)) {
301 24
            return $this->enabled;
302
        }
303
304 7
        if (!is_bool($enabled = ($this->enabled)())) {
305 6
            throw new RuntimeException(sprintf(
306 6
                'The PHP callable "enabled" must returns a boolean, %s received.',
307 6
                gettype($enabled)
308 6
            ));
309
        }
310
311 1
        return $enabled;
312
    }
313
314
    /**
315
     * Gets a list of log messages that are retrieved from the logger so far by this log target.
316
     *
317
     * @return Message[] The list of log messages.
318
     */
319 56
    protected function getMessages(): array
320
    {
321 56
        return $this->messages;
322
    }
323
324
    /**
325
     * Gets a list of formatted log messages.
326
     *
327
     * @return string[] The list of formatted log messages.
328
     */
329 1
    protected function getFormattedMessages(): array
330
    {
331 1
        $formatted = [];
332
333 1
        foreach ($this->messages as $key => $message) {
334 1
            $formatted[$key] = $this->formatter->format($message, $this->commonContext);
335
        }
336
337 1
        return $formatted;
338
    }
339
340
    /**
341
     * Formats all log messages for display as a string.
342
     *
343
     * @param string $separator The log messages string separator.
344
     *
345
     * @return string The string formatted log messages.
346
     */
347 20
    protected function formatMessages(string $separator = ''): string
348
    {
349 20
        $formatted = '';
350
351 20
        foreach ($this->messages as $message) {
352 20
            $formatted .= $this->formatter->format($message, $this->commonContext) . $separator;
353
        }
354
355 8
        return $formatted;
356
    }
357
358
    /**
359
     * Gets a user parameters in the `key => value` format that should be logged in a each message.
360
     *
361
     * @return array The user parameters in the `key => value` format.
362
     */
363 25
    protected function getCommonContext(): array
364
    {
365 25
        return $this->commonContext;
366
    }
367
368
    /**
369
     * Filters the given messages according to their categories and levels.
370
     *
371
     * @param array $messages List log messages to be filtered.
372
     *
373
     * @throws InvalidArgumentException for non-instance Message.
374
     */
375 89
    private function filterMessages(array $messages): void
376
    {
377 89
        foreach ($messages as $i => $message) {
378 89
            if (!($message instanceof Message)) {
379 8
                throw new InvalidArgumentException('You must provide an instance of \Yiisoft\Log\Message.');
380
            }
381
382 81
            if (!empty($this->levels) && !in_array($message->level(), $this->levels, true)) {
383 7
                unset($messages[$i]);
384 7
                continue;
385
            }
386
387
            /** @var string $category */
388 81
            $category = $message->context('category', '');
389
390 81
            if ($this->categories->isExcluded($category)) {
391 13
                unset($messages[$i]);
392 13
                continue;
393
            }
394
395 80
            $this->messages[] = $message;
396
        }
397
    }
398
}
399