Message::logLevelToSyslog()   A
last analyzed

Complexity

Conditions 6
Paths 5

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
c 2
b 0
f 0
nc 5
nop 1
dl 0
loc 19
rs 9.2222
ccs 9
cts 9
cp 1
crap 6
1
<?php
2
declare(strict_types=1);
3
4
/*
5
 * This file is part of the php-gelf package.
6
 *
7
 * (c) Benjamin Zikarsky <http://benjamin-zikarsky.de>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Gelf;
14
15
use DateTimeInterface;
16
use Psr\Log\LogLevel;
17
use RuntimeException;
18
19
/**
20
 * A message complying to the GELF standard
21
 * <https://github.com/Graylog2/graylog2-docs/wiki/GELF>
22
 *
23
 * @author Benjamin Zikarsky <[email protected]>
24
 */
25
class Message implements MessageInterface
26
{
27
    private string $version;
28
    private string $host;
29
    private float $timestamp;
30
    private int $level;
31
32
    private ?string $shortMessage = null;
33
    private ?string $fullMessage = null;
34
    private array $additionals = [];
35
36
    /**
37
     * A list of the PSR LogLevel constants which is also a mapping of
38
     * syslog code to psr-value
39
     *
40
     * @var array
41
     */
42
    private static array $psrLevels = [
43
        LogLevel::EMERGENCY,    // 0
44
        LogLevel::ALERT,        // 1
45
        LogLevel::CRITICAL,     // 2
46
        LogLevel::ERROR,        // 3
47
        LogLevel::WARNING,      // 4
48
        LogLevel::NOTICE,       // 5
49
        LogLevel::INFO,         // 6
50
        LogLevel::DEBUG         // 7
51
    ];
52
53
    /**
54
     * Creates a new message
55
     *
56
     * Populates timestamp and host with sane default values
57
     */
58
    public function __construct()
59 37
    {
60
        $this->timestamp = microtime(true);
61 37
        $this->host = gethostname();
62 37
        $this->level = 1; //ALERT
63 37
        $this->version = "1.1";
64 37
    }
65 37
66
    /**
67
     * Trys to convert a given log-level (psr or syslog) to
68
     * the psr representation
69
     */
70
    final public static function logLevelToPsr(int|string|null $level): string
71
    {
72
        $origLevel = $level;
73
74 5
        if (is_numeric($level)) {
75
            $level = intval($level);
76 5
            if (isset(self::$psrLevels[$level])) {
77
                return self::$psrLevels[$level];
78 5
            }
79 4
        } elseif (is_string($level)) {
80 4
            $level = strtolower($level);
81 4
            if (in_array($level, self::$psrLevels)) {
82
                return $level;
83 2
            }
84 2
        }
85 2
86 1
        throw new RuntimeException(
87
            sprintf("Cannot convert log-level '%s' to psr-style", $origLevel ?? '<null>')
88
        );
89
    }
90 2
91 2
    /**
92
     * Trys to convert a given log-level (psr or syslog) to
93
     * the syslog representation
94
     */
95
    final public static function logLevelToSyslog(int|string|null $level): int
96
    {
97
        $origLevel = $level;
98
99
        if (is_numeric($level)) {
100
            $level = intval($level);
101
            if ($level < 8 && $level > -1) {
102 21
                return $level;
103
            }
104 21
        } elseif (is_string($level)) {
105
            $level = strtolower($level);
106 21
            $syslogLevel = array_search($level, self::$psrLevels);
107 14
            if (false !== $syslogLevel) {
108 14
                return $syslogLevel;
109 14
            }
110
        }
111 17
112 17
        throw new RuntimeException(
113 17
            sprintf("Cannot convert log-level '%s' to syslog-style", $origLevel ?? '<null>')
114 17
        );
115 16
    }
116
117
    public function getVersion(): string
118
    {
119 2
        return $this->version;
120 2
    }
121
122
    public function setVersion(string $version): self
123
    {
124 13
        $this->version = $version;
125
126 13
        return $this;
127
    }
128
129 3
    public function getHost(): string
130
    {
131 3
        return $this->host;
132
    }
133 3
134
    public function setHost(string $host): self
135
    {
136 13
        $this->host = $host;
137
138 13
        return $this;
139
    }
140
141 2
    public function getShortMessage(): ?string
142
    {
143 2
        return $this->shortMessage;
144
    }
145 2
146
    public function setShortMessage(?string $shortMessage): self
147
    {
148 17
        $this->shortMessage = $shortMessage;
149
150 17
        return $this;
151
    }
152
153 17
    public function getFullMessage(): ?string
154
    {
155 17
        return $this->fullMessage;
156
    }
157 17
158
    public function setFullMessage(?string $fullMessage): self
159
    {
160 14
        $this->fullMessage = $fullMessage;
161
162 14
        return $this;
163
    }
164
165 3
    public function getTimestamp(): float
166
    {
167 3
        return $this->timestamp;
168
    }
169 3
170
    public function setTimestamp(float|int|DateTimeInterface $timestamp): self
171
    {
172 14
        if ($timestamp instanceof DateTimeInterface) {
173
            $timestamp = $timestamp->format("U.u");
174 14
        }
175
176
        $this->timestamp = (float)$timestamp;
177 3
178
        return $this;
179 3
    }
180 2
181
    public function getLevel(): string
182
    {
183 3
        return self::logLevelToPsr($this->level);
184
    }
185 3
186
    public function getSyslogLevel(): int
187
    {
188 2
        return self::logLevelToSyslog($this->level);
189
    }
190 2
191
    public function setLevel(string|int $level): self
192
    {
193 13
        $this->level = self::logLevelToSyslog($level);
194
195 13
        return $this;
196
    }
197
198 18
    public function getAdditional(string $key): mixed
199
    {
200 18
        if (!isset($this->additionals[$key])) {
201
            throw new RuntimeException(
202 16
                sprintf("Additional key '%s' is not defined", $key)
203
            );
204
        }
205 14
206
        return $this->additionals[$key];
207 14
    }
208
209
    public function hasAdditional(string $key): bool
210 16
    {
211
        return isset($this->additionals[$key]);
212 16
    }
213
214 16
    public function setAdditional(string $key, mixed $value): self
215
    {
216
        if ($key === '') {
217 14
            throw new RuntimeException("Additional field key cannot be empty");
218
        }
219 14
220
        $this->additionals[$key] = $value;
221
222 4
        return $this;
223
    }
224 4
225
    public function getAllAdditionals(): array
226 4
    {
227
        return $this->additionals;
228
    }
229 14
230
    public function toArray(): array
231 14
    {
232
        $message = [
233
            'version'       => $this->getVersion(),
234 4
            'host'          => $this->getHost(),
235
            'short_message' => $this->getShortMessage(),
236 4
            'full_message'  => $this->getFullMessage(),
237
            'level'         => $this->getSyslogLevel(),
238 4
            'timestamp'     => $this->getTimestamp()
239
        ];
240
241 3
        // add additionals
242
        foreach ($this->getAllAdditionals() as $key => $value) {
243 3
            $message["_" . $key] = $value;
244 1
        }
245 1
246
        // return after filtering empty strings and null values
247
        return array_filter($message, function ($message) {
248
            return is_bool($message)
249 2
                || (is_string($message) && strlen($message))
250
                || is_int($message)
251
                || !empty($message);
252 1
        });
253
    }
254
}
255