Passed
Push — master ( c333cb...c41b44 )
by Evgeniy
02:19
created

MessageFormatter::setTimestampFormat()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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