Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
20 / 20
CRAP
100.00% covered (success)
100.00%
1 / 1
Logger
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
20 / 20
24
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 setDestination
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getDestination
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setConfig
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 log
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
5
 makeId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLastLog
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logDebug
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logInfo
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logNotice
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logWarning
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logError
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logCritical
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logAlert
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logEmergency
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLevel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 replaceContext
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDebugCollector
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 write
n/a
0 / 0
n/a
0 / 0
0
1<?php declare(strict_types=1);
2/*
3 * This file is part of Aplus Framework Log Library.
4 *
5 * (c) Natan Felles <natanfelles@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10namespace Framework\Log;
11
12use Framework\Log\Debug\LogCollector;
13use JetBrains\PhpStorm\Pure;
14
15/**
16 * Class Logger.
17 *
18 * @see https://www.php-fig.org/psr/psr-3/
19 *
20 * @package log
21 */
22abstract class Logger
23{
24    /**
25     * Logs destination.
26     */
27    protected string $destination;
28    /**
29     * @var array<mixed>
30     */
31    protected array $config;
32    /**
33     * Active log level.
34     */
35    protected LogLevel $level = LogLevel::DEBUG;
36    protected Log | null $lastLog = null;
37    protected LogCollector $debugCollector;
38
39    /**
40     * Logger constructor.
41     *
42     * @param string $destination
43     * @param LogLevel $level
44     * @param array<mixed> $config
45     */
46    public function __construct(
47        string $destination,
48        LogLevel $level = LogLevel::DEBUG,
49        array $config = []
50    ) {
51        $this->setDestination($destination);
52        $this->setLevel($level);
53        $this->setConfig($config);
54    }
55
56    protected function setDestination(string $destination) : static
57    {
58        $this->destination = $destination;
59        return $this;
60    }
61
62    public function getDestination() : string
63    {
64        return $this->destination;
65    }
66
67    /**
68     * @param array<mixed> $config
69     *
70     * @return static
71     */
72    protected function setConfig(array $config) : static
73    {
74        $this->config = $config;
75        return $this;
76    }
77
78    /**
79     * @return array<mixed>
80     */
81    protected function getConfig() : array
82    {
83        return $this->config;
84    }
85
86    /**
87     * Logs with an arbitrary level.
88     *
89     * @param LogLevel $level
90     * @param string $message
91     * @param array<string> $context
92     *
93     * @return bool
94     */
95    public function log(LogLevel $level, string $message, array $context = []) : bool
96    {
97        $debug = isset($this->debugCollector);
98        if ($debug) {
99            $start = \microtime(true);
100        }
101        $this->lastLog = null;
102        if ($level->value < $this->getLevel()->value) {
103            return true;
104        }
105        $time = \time();
106        $id = $this->makeId();
107        $message = $this->replaceContext($message, $context);
108        $log = new Log($level, $message, $time, $id);
109        $written = $this->write($log);
110        if ($written) {
111            $this->lastLog = $log;
112        }
113        if ($debug) {
114            $end = \microtime(true);
115            $this->debugCollector->addData([
116                'start' => $start,
117                'end' => $end,
118                'date' => \date('Y-m-d', $time),
119                'time' => \date('H:i:s', $time),
120                'id' => $id,
121                'level' => $level->value,
122                'levelName' => $level->name,
123                'message' => $message,
124                'written' => $written,
125            ]);
126        }
127        return $written;
128    }
129
130    protected function makeId() : string
131    {
132        return \bin2hex(\random_bytes(6));
133    }
134
135    /**
136     * Get the last accepted log in the current instance.
137     *
138     * @return Log|null The last Log or null if the last was not accepted
139     */
140    #[Pure]
141    public function getLastLog() : ?Log
142    {
143        return $this->lastLog;
144    }
145
146    /**
147     * Detailed debug information.
148     *
149     * @param string $message
150     * @param array<string> $context
151     *
152     * @return bool
153     */
154    public function logDebug(string $message, array $context = []) : bool
155    {
156        return $this->log(LogLevel::DEBUG, $message, $context);
157    }
158
159    /**
160     * Interesting events.
161     *
162     * Example: User logs in, SQL logs.
163     *
164     * @param string $message
165     * @param array<string> $context
166     *
167     * @return bool
168     */
169    public function logInfo(string $message, array $context = []) : bool
170    {
171        return $this->log(LogLevel::INFO, $message, $context);
172    }
173
174    /**
175     * Normal but significant events.
176     *
177     * @param string $message
178     * @param array<string> $context
179     *
180     * @return bool
181     */
182    public function logNotice(string $message, array $context = []) : bool
183    {
184        return $this->log(LogLevel::NOTICE, $message, $context);
185    }
186
187    /**
188     * Exceptional occurrences that are not errors.
189     *
190     * Example: Use of deprecated APIs, poor use of an API, undesirable things
191     * that are not necessarily wrong.
192     *
193     * @param string $message
194     * @param array<string> $context
195     *
196     * @return bool
197     */
198    public function logWarning(string $message, array $context = []) : bool
199    {
200        return $this->log(LogLevel::WARNING, $message, $context);
201    }
202
203    /**
204     * Runtime errors that do not require immediate action but should typically
205     * be logged and monitored.
206     *
207     * @param string $message
208     * @param array<string> $context
209     *
210     * @return bool
211     */
212    public function logError(string $message, array $context = []) : bool
213    {
214        return $this->log(LogLevel::ERROR, $message, $context);
215    }
216
217    /**
218     * Critical conditions.
219     *
220     * Example: Application component unavailable, unexpected exception.
221     *
222     * @param string $message
223     * @param array<string> $context
224     *
225     * @return bool
226     */
227    public function logCritical(string $message, array $context = []) : bool
228    {
229        return $this->log(LogLevel::CRITICAL, $message, $context);
230    }
231
232    /**
233     * Action must be taken immediately.
234     *
235     * Example: Entire website down, database unavailable, etc. This should
236     * trigger the SMS alerts and wake you up.
237     *
238     * @param string $message
239     * @param array<string> $context
240     *
241     * @return bool
242     */
243    public function logAlert(string $message, array $context = []) : bool
244    {
245        return $this->log(LogLevel::ALERT, $message, $context);
246    }
247
248    /**
249     * System is unusable.
250     *
251     * @param string $message
252     * @param array<string> $context
253     *
254     * @return bool
255     */
256    public function logEmergency(string $message, array $context = []) : bool
257    {
258        return $this->log(LogLevel::EMERGENCY, $message, $context);
259    }
260
261    public function getLevel() : LogLevel
262    {
263        return $this->level;
264    }
265
266    public function setLevel(LogLevel $level) : static
267    {
268        $this->level = $level;
269        return $this;
270    }
271
272    /**
273     * @param string $message
274     * @param array<string> $context
275     *
276     * @return string
277     */
278    #[Pure]
279    protected function replaceContext(string $message, array $context) : string
280    {
281        return \strtr($message, $context);
282    }
283
284    public function setDebugCollector(LogCollector $debugCollector) : static
285    {
286        $this->debugCollector = $debugCollector;
287        $this->debugCollector->setLogger($this);
288        return $this;
289    }
290
291    abstract protected function write(Log $log) : bool;
292}