LogLaddy::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 1
eloc 3
c 3
b 0
f 1
nc 1
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
/*
4
 * LogLaddy
5
 *
6
 * I carry a log – yes. Is it funny to you? It is not to me.
7
 * Behind all things are reasons. Reasons can even explain the absurd.
8
 *
9
 * LogLaddy manages error reporting
10
 * PSR-3 Compliant
11
 */
12
13
namespace HexMakina\LogLaddy;
14
15
// Debugger
16
use Psr\Log\{LogLevel, LoggerInterface};
17
use HexMakina\Debugger\Debugger;
18
19
class LogLaddy implements LoggerInterface
20
{
21
    public const OSD_SESSION_KEY = 'HexMakina:LogLaddy:OSD';
22
    private PHPErrorToPSRLevel $errorMappper;
23
    private array $messages;
24
25
    public function __construct()
26
    {
27
        $this->errorMappper = new PHPErrorToPSRLevel();
28
        $this->messages = [];
29
30
        $this->setHandlers();
31
    }
32
33
    /**
34
     * sets handler for errors (errorHandler()) and throwables (exceptionHandler())
35
     *      uses set_error_handler([$instance, 'errorHandler']);
36
     *      uses set_exception_handler([$instance, 'exceptionHandler']);
37
     * 
38
     * https://www.php.net/manual/en/function.set-error-handler
39
     */
40
    public function setHandlers(): void
41
    {
42
        set_error_handler([$this, 'errorHandler']);
43
        set_exception_handler([$this, 'exceptionHandler']);
44
    }
45
46
47
    public function resetHandlers(): void
48
    {
49
        restore_error_handler();
50
        restore_exception_handler();
51
    }
52
53
    /**
54
     * Handles PHP errors and logs them using the specified error level.
55
     *
56
     * @param int $error The error code.
57
     * @param string $message The error message.
58
     * @param string $file The file where the error occurred (optional).
59
     * @param int $line The line number where the error occurred (optional).
60
     * @return bool Returns false to indicate that the error should not be handled by the default PHP error handler.
61
     */
62
    public function errorHandler(int $error, string $message, string $file = '', int $line = 0): bool
63
    {
64
        $level = $this->errorMappper->map($error);
65
        $context = ['file' => $file, 'line' => $line];
66
67
        $this->log($level, $message, $context);
68
69
        return false;
70
    }
71
72
73
    /**
74
     * Handles exceptions by logging them with the critical log level.
75
     *
76
     * @param \Throwable $throwable The exception to handle.
77
     * @return void
78
     */
79
    public function exceptionHandler(\Throwable $throwable): void
80
    {
81
        $message = $throwable->getMessage();
82
        $context = ['exception' => $throwable];
83
        $this->log(LogLevel::CRITICAL, $message, $context);
84
    }
85
86
    public function log($level, $message, array $context = []): void
87
    {
88
        switch ($level) {
89
            case LogLevel::DEBUG:
90
                Debugger::visualDump($message, $level, true);
91
                break;
92
93
            case LogLevel::INFO:
94
            case LogLevel::NOTICE:
95
            case LogLevel::WARNING:
96
                Debugger::visualDump($message, $level, true);
97
                break;
98
99
            case LogLevel::ERROR:
100
            case LogLevel::CRITICAL:
101
            case LogLevel::ALERT:
102
            case LogLevel::EMERGENCY:
103
                if (isset($context['exception']) && $context['exception'] instanceof \Throwable) {
104
                    $message = $context['exception'];
105
                    $level = 'Uncaught ' . get_class($context['exception']);
106
                }
107
108
                Debugger::visualDump($message, $level, true);
109
                http_response_code(500);
110
                die;
111
112
            default:
113
                throw new \Psr\Log\InvalidArgumentException('UNDEFINED_LOGLEVEL_' . $level);
114
        }
115
    }
116
117
    private function osd($level, string $message, array $context = array())
118
    {
119
        $this->messages[$level] ??= [];
120
        $this->messages[$level][] = [$message, $context];
121
    }
122
123
124
    /**
125
     * System is unusable.
126
     */
127
    public function emergency($message, array $context = array())
128
    {
129
        $this->osd(LogLevel::EMERGENCY, $message, $context);
130
    }
131
132
    /**
133
     * Action must be taken immediately.
134
     * Example: Entire website down, database unavailable, etc. This should
135
     * trigger the SMS alerts and wake you up.
136
     */
137
    public function alert($message, array $context = array())
138
    {
139
        $this->osd(LogLevel::ALERT, $message, $context);
140
    }
141
142
    /**
143
     * Critical conditions.
144
     * Example: Application component unavailable, unexpected exception.
145
     */
146
    public function critical($message, array $context = array())
147
    {
148
        $this->osd(LogLevel::CRITICAL, $message, $context);
149
    }
150
151
    /**
152
     * Runtime errors that do not require immediate action but should typically
153
     * be logged and monitored.
154
     */
155
    public function error($message, array $context = array())
156
    {
157
        $this->osd(LogLevel::ERROR, $message, $context);
158
    }
159
160
    /**
161
     * Exceptional occurrences that are not errors.
162
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
163
     * that are not necessarily wrong.
164
     */
165
    public function warning($message, array $context = array())
166
    {
167
        $this->osd(LogLevel::WARNING, $message, $context);
168
    }
169
170
    /**
171
     * Normal but significant events.
172
     */
173
    public function notice($message, array $context = array())
174
    {
175
        $this->osd(LogLevel::NOTICE, $message, $context);
176
    }
177
178
    /**
179
     * Interesting events.
180
     * Example: User logs in, SQL logs.
181
     */
182
    public function info($message, array $context = array())
183
    {
184
        $this->osd(LogLevel::INFO, $message, $context);
185
    }
186
187
    /**
188
     * Detailed debug information.
189
     *
190
     */
191
    public function debug($message, array $context = array())
192
    {
193
        $this->osd(LogLevel::DEBUG, $message, $context);
194
    }
195
}
196