Passed
Push — master ( 0cbf53...16fe61 )
by Alexander
01:50
created

Log   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 105
rs 10
c 0
b 0
f 0
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A log() 0 7 3
A __callStatic() 0 9 1
A file() 0 11 2
A handler() 0 15 4
A std() 0 6 2
1
<?php
2
3
namespace alkemann\h2l;
4
5
use alkemann\h2l\exceptions\ConfigMissing;
6
7
/**
8
 * Class Log
9
 *
10
 * Follows http://www.php-fig.org/psr/psr-3/
11
 * See https://github.com/php-fig/log
12
 *
13
 *
14
 * 0 Emergency: system is unusable
15
 * 1 Alert: action must be taken immediately
16
 * 2 Critical: critical conditions
17
 * 3 Error: error conditions
18
 * 4 Warning: warning conditions
19
 * 5 Notice: normal but significant condition
20
 * 6 Informational: informational messages
21
 * 7 Debug: debug-level messages
22
 *
23
 * @package alkemann\h2l
24
 * @method static void debug($message, array $context = []) Log debug level
25
 * @method static void info($message, array $context = []) Log info level
26
 * @method static void notice($message, array $context = []) Log notice level
27
 * @method static void warning($message, array $context = []) Log warning level
28
 * @method static void error($message, array $context = []) Log error level
29
 * @method static void critical($message, array $context = []) Log critical level
30
 * @method static void alert($message, array $context = []) Log alert level
31
 * @method static void emergency($message, array $context = []) Log emergency level
32
 */
33
class Log
34
{
35
36
    /**
37
     * Set handlers here, either a callable or an object that implements Psr\Log\LoggerInterface
38
     * @var array
39
     */
40
    protected static $handlers = [];
41
42
    /**
43
     * Add handler, it should implement Psr\Log\LoggerInterface
44
     *
45
     * @param string $name unique name for this handler
46
     * @param object|callable $handler an object that implement Psr\Log\LoggerInterface or a callable
47
     */
48
    public static function handler(string $name, $handler): void
49
    {
50
        if (is_callable($handler) === false) {
51
            if (is_object($handler)) {
52
                // TODO check if object implements interface?
53
                if (!method_exists($handler, 'log')) {
54
                    throw new \InvalidArgumentException(
55
                        "$name is not a valid handler, it must implement the Psr\Log\LoggerInterface"
56
                    );
57
                }
58
            } else {
59
                throw new \InvalidArgumentException("$name is not a valid handler");
60
            }
61
        }
62
        static::$handlers[$name] = $handler;
63
    }
64
65
    /**
66
     * Support the log levels of debug, info, notice, warning, error, critical, alert, emergency
67
     *
68
     * @param string $method
69
     * @param array $args
70
     */
71
    public static function __callStatic(string $method, array $args = []): void
72
    {
73
        /*
1 ignored issue
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
74
        if (!in_array($method, ['debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency'])) {
75
            throw new \Psr\Log\InvalidArgumentException("Undefined level")
76
        }
77
        */
78
        array_unshift($args, $method);
79
        call_user_func_array(['alkemann\h2l\Log', 'log'], $args);
80
    }
81
82
    /**
83
     * Send $message with level $level to all handlers
84
     *
85
     * @param $level
86
     * @param $message
87
     * @param array $context
88
     */
89
    public static function log($level, $message, array $context = []): void
1 ignored issue
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
90
    {
91
        foreach (static::$handlers as $handlerName => $handler) {
92
            if (is_callable($handler)) { // avoid this?
93
                $handler($level, $message, $context);
94
            } else {
95
                $handler->$level($message, $context);
96
            }
97
        }
98
    }
99
100
    /**
101
     * A standard output handler, INFO, DEBUG, NOTICE to `php://stdout` and rest to `php://stderr`
102
     *
103
     * You can enable it like this: `Log::handler('standard', [Log::class, 'std']);`
104
     *
105
     * @codeCoverageIgnore
106
     * @param string $level
107
     * @param string $message
108
     * @param array $context
109
     */
110
    private static function std(string $level, string $message, array $context = []): void
111
    {
112
        $level = strtoupper($level);
113
        $string = "{$level}: {$message}\n";
114
        $channel = in_array($level, ['INFO', 'DEBUG', 'NOTICE']) ? 'php://stdout' : 'php://stderr';
115
        file_put_contents($channel, $string);
116
    }
117
118
    /**
119
     * A default naive file handler that can be used initially, but should be replaced for prod
120
     *
121
     * @codeCoverageIgnore
122
     * @param string $level
123
     * @param string $message
124
     * @param array $context
125
     * @throws ConfigMissing
126
     */
127
    private static function file(string $level, string $message, array $context = []): void
128
    {
129
        $path = Environment::get('logs_path');
130
        if (is_null($path)) {
131
            throw new ConfigMissing("File handler requires a `logs_path` in Environment");
132
        }
133
        $file = $path . 'app.log';
134
        $fileHandler = fopen($file, 'a');
135
        $string = date('Y-m-d H:i:s') . " " . strtoupper($level) . " " . $message . PHP_EOL;
136
        fwrite($fileHandler, $string);
137
        fclose($fileHandler);
138
    }
139
}
140