Passed
Push — main ( a25051...afa590 )
by Sammy
06:58
created

LogLaddy::log()   C

Complexity

Conditions 12
Paths 16

Size

Total Lines 33
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 24
c 1
b 0
f 0
nc 16
nop 3
dl 0
loc 33
rs 6.9666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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, with a NICE bonus
11
 */
12
13
namespace HexMakina\LogLaddy;
14
15
// Debugger
16
use Psr\Log\LogLevel;
17
use Psr\Log\InvalidArgumentException;
18
use HexMakina\Debugger\Debugger;
19
use HexMakina\BlackBox\StateAgentInterface;
20
21
class LogLaddy extends \Psr\Log\AbstractLogger
22
{
23
24
  /**
25
   * @var array<int,string> $level_mapping
26
   */
27
    private static array $level_mapping = [];
28
29
    private ?StateAgentInterface $state_agent;
30
31
32
    public function __construct(StateAgentInterface $stateAgent = null)
33
    {
34
        $this->state_agent = $stateAgent;
35
        $this->setHandlers();
36
    }
37
38
    public function setHandlers(): void
39
    {
40
        set_error_handler(
41
          function(int $level, string $message, string $file = '', int $line = 0): bool {
42
            return $this->errorHandler($level, $message, $file, $line);
43
          }
44
        );
45
46
        set_exception_handler(function (\Throwable $throwable) : bool {
47
            return $this->exceptionHandler($throwable);
48
        });
49
    }
50
51
    public function restoreHandlers(): void
52
    {
53
        restore_error_handler();
54
        restore_exception_handler();
55
    }
56
57
    /**
58
      * handler for errors
59
      * use set_error_handler([$instance, 'errorHandler']);
60
      *
61
      * https://www.php.net/manual/en/function.set-error-handler
62
      *
63
      */
64
    public function errorHandler(int $level, string $message, string $file = '', int $line = 0): bool
65
    {
66
        $loglevel = self::mapErrorLevelToLogLevel($level);
67
        $this->{$loglevel}($message);
68
69
        return true;
70
    }
71
72
    /*
73
    * handler for throwables,
74
    * use set_exception_handler([$instance, 'exceptionHandler']);
75
    */
76
    public function exceptionHandler(\Throwable $throwable): bool
77
    {
78
        $this->critical($throwable->getMessage(), ['exception' => $throwable]);
79
80
        return true;
81
    }
82
83
    public function log($level, $message, array $context = []): void
84
    {
85
        switch ($level) {
86
            case LogLevel::DEBUG:
87
                Debugger::visualDump($message, $level, true);
88
                break;
89
90
            case LogLevel::INFO:
91
            case LogLevel::NOTICE:
92
            case LogLevel::WARNING:
93
                if (is_null($this->state_agent)) {
94
                    Debugger::visualDump($message, $level, true);
95
                } else {
96
                    $this->state_agent->addMessage($level, $message, $context);
97
                }
98
99
                break;
100
101
            case LogLevel::ERROR:
102
            case LogLevel::CRITICAL:
103
            case LogLevel::ALERT:
104
            case LogLevel::EMERGENCY:
105
                if (isset($context['exception']) && $context['exception'] instanceof \Throwable) {
106
                    $message = $context['exception'];
107
                    $level = 'Uncaught ' . get_class($context['exception']);
108
                }
109
110
                Debugger::visualDump($message, $level, true);
111
                http_response_code(500);
112
                die;
113
114
            default:
115
                throw new \Psr\Log\InvalidArgumentException('UNDEFINED_LOGLEVEL_' . $level);
116
        }
117
    }
118
119
    private static function mapErrorLevelToLogLevel(int $level): string
120
    {
121
122
      // http://php.net/manual/en/errorfunc.constants.php
123
        if (empty(self::$level_mapping)) {
124
            self::createErrorLevelMap();
125
        }
126
127
        if (!isset(self::$level_mapping[$level])) {
128
            throw new \Exception(sprintf('%s(%d): %d is unknown', __FUNCTION__, $level, $level));
129
        }
130
131
        return self::$level_mapping[$level];
132
    }
133
134
   /**  Error level meaning, from \Psr\Log\LogLevel.php
135
     *
136
     * const EMERGENCY = 'emergency';
137
     *                 // System is unusable.
138
     * const ALERT     = 'alert';
139
     *                 // Action must be taken immediately, Example: Entire website down, database unavailable, etc.
140
     * const CRITICAL  = 'critical';
141
     *                 // Application component unavailable, unexpected exception.
142
     * const ERROR     = 'error';
143
     *                 // Run time errors that do not require immediate action
144
     * const WARNING   = 'warning';
145
     *                 // Exceptional occurrences that are not errors, undesirable things that are not necessarily wrong
146
     * const NOTICE    = 'notice';
147
     *                 // Normal but significant events.
148
     * const INFO      = 'info';
149
     *                 // Interesting events. User logs in, SQL logs.
150
     * const DEBUG     = 'debug';
151
     *                 // Detailed debug information.
152
     *
153
     *
154
     *  Error level mapping from \Psr\Log\LogLevel.php & http://php.net/manual/en/errorfunc.constants.php
155
     */
156
    private static function createErrorLevelMap(): void
157
    {
158
        $critical = array_fill_keys(
159
            [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR],
160
            LogLevel::CRITICAL
161
        );
162
163
        $error = array_fill_keys(
164
            [E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING],
165
            LogLevel::ERROR
166
        );
167
168
        $debug = array_fill_keys(
169
            [E_NOTICE, E_USER_NOTICE, E_STRICT,E_DEPRECATED,E_USER_DEPRECATED,E_ALL],
170
            LogLevel::DEBUG
171
        );
172
173
        self::$level_mapping = $critical + $error + $debug;
174
    }
175
}
176