Passed
Pull Request — master (#51)
by Evgeniy
02:11
created

MessageFormatter::getPrefix()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 16
ccs 9
cts 9
cp 1
crap 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Log;
6
7
use DateTime;
8
9
use function gettype;
10
use function implode;
11
use function is_array;
12
use function is_string;
13
use function microtime;
14
use function sprintf;
15
use function strpos;
16
17
final class MessageFormatter
18
{
19
    /**
20
     * @var callable|null PHP callable that returns a string representation of the log message.
21
     *
22
     * If not set, {@see MessageFormatter::defaultFormat()} will be used.
23
     *
24
     * The signature of the callable should be `function (array $message): string;`.
25
     */
26
    private $format;
27
28
    /**
29
     * @var callable|null PHP callable that returns a string to be prefixed to every exported message.
30
     *
31
     * If not set, {@see MessageFormatter::getPrefix()} will be used, which prefixes
32
     * the message with context information such as user IP, user ID and session ID.
33
     *
34
     * The signature of the callable should be `function (array $message): string;`.
35
     */
36
    private $prefix;
37
38
    /**
39
     * @var string The date format for the log timestamp. Defaults to `Y-m-d H:i:s.u`.
40
     */
41
    private string $timestampFormat = 'Y-m-d H:i:s.u';
42
43
    /**
44
     * Sets the format for the string representation of the log message.
45
     *
46
     * @param callable $format The PHP callable to get a string representation of the log message.
47
     *
48
     * @see MessageFormatter::$format
49
     */
50 18
    public function setFormat(callable $format): void
51
    {
52 18
        $this->format = $format;
53 18
    }
54
55
    /**
56
     * Sets a PHP callable that returns a string to be prefixed to every exported message.
57
     *
58
     * @param callable $prefix The PHP callable to get a string prefix of the log message.
59
     *
60
     * @see MessageFormatter::$prefix
61
     */
62 18
    public function setPrefix(callable $prefix): void
63
    {
64 18
        $this->prefix = $prefix;
65 18
    }
66
67
    /**
68
     * Sets a date format for the log timestamp.
69
     *
70
     * @param string $timestampFormat The date format for the log timestamp.
71
     *
72
     * @see MessageFormatter::$timestampFormat
73
     */
74 4
    public function setTimestampFormat(string $timestampFormat): void
75
    {
76 4
        $this->timestampFormat = $timestampFormat;
77 4
    }
78
79
    /**
80
     * Formats a log message for display as a string.
81
     *
82
     * The message structure follows that in {@see MessageCollection::$messages}.
83
     *
84
     * @param array $message The log message to be formatted.
85
     *
86
     * @throws LogRuntimeException for a callable "format" that does not return a string.
87
     *
88
     * @return string The formatted log message.
89
     */
90 37
    public function format(array $message): string
91
    {
92 37
        if ($this->format === null) {
93 19
            return $this->defaultFormat($message);
94
        }
95
96 18
        $formatted = ($this->format)($message);
97
98 18
        if (!is_string($formatted)) {
99 12
            throw new LogRuntimeException(sprintf(
100 12
                'The PHP callable "format" must returns a string, %s received.',
101 12
                gettype($formatted)
102
            ));
103
        }
104
105 6
        return $this->getPrefix($message) . $formatted;
106
    }
107
108
    /**
109
     * Default formats a log message for display as a string.
110
     *
111
     * The message structure follows that in {@see MessageCollection::$messages}.
112
     *
113
     * @param array $message The log message to be default formatted.
114
     *
115
     * @return string The default formatted log message.
116
     */
117 19
    private function defaultFormat(array $message): string
118
    {
119 19
        [$level, $text, $context] = $message;
120 19
        $timestamp = $context['time'] ?? microtime(true);
121 19
        $category = $context['category'] ?? MessageCategoryFilter::DEFAULT;
122
123 19
        $traces = [];
124 19
        if (isset($context['trace']) && is_array($context['trace'])) {
125 1
            foreach ($context['trace'] as $trace) {
126 1
                if (isset($trace['file'], $trace['line'])) {
127 1
                    $traces[] = "in {$trace['file']}:{$trace['line']}";
128
                }
129
            }
130
        }
131
132 19
        return $this->getTime($timestamp) . " {$this->getPrefix($message)}[{$level}][{$category}] {$text}"
133 7
            . (empty($traces) ? '' : "\n    " . implode("\n    ", $traces));
134
    }
135
136
    /**
137
     * Gets a string to be prefixed to the given message.
138
     *
139
     * If {@see MessageFormatter::$prefix} is configured it will return the result of the callback.
140
     * The default implementation will return user IP, user ID and session ID as a prefix.
141
     * The message structure follows that in {@see MessageCollection::$messages}.
142
     *
143
     * @param array $message The log message being exported.
144
     *
145
     * @throws LogRuntimeException for a callable "prefix" that does not return a string.
146
     *
147
     * @return string The log prefix string.
148
     */
149 25
    private function getPrefix(array $message): string
150
    {
151 25
        if ($this->prefix === null) {
152 7
            return '';
153
        }
154
155 18
        $prefix = ($this->prefix)($message);
156
157 18
        if (!is_string($prefix)) {
158 12
            throw new LogRuntimeException(sprintf(
159 12
                'The PHP callable "prefix" must returns a string, %s received.',
160 12
                gettype($prefix)
161
            ));
162
        }
163
164 6
        return $prefix;
165
    }
166
167
    /**
168
     * Gets formatted timestamp for message, according to {@see MessageFormatter::$timestampFormat}.
169
     *
170
     * @param float|int $timestamp The timestamp to be formatted.
171
     *
172
     * @return string Formatted timestamp for message.
173
     */
174 19
    private function getTime($timestamp): string
175
    {
176 19
        $timestamp = (string) $timestamp;
177 19
        $format = strpos($timestamp, '.') === false ? 'U' : 'U.u';
178 19
        return DateTime::createFromFormat($format, $timestamp)->format($this->timestampFormat);
179
    }
180
}
181