Completed
Push — test-tidy-up ( 8b0fd0...7e2db7 )
by Craig
02:53
created

Logger::log()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 15
cts 15
cp 1
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 13
nc 4
nop 3
crap 4
1
<?php
2
3
namespace League\CLImate;
4
5
use League\CLImate\CLImate;
6
use Psr\Log\AbstractLogger;
7
use Psr\Log\LogLevel;
8
9
/**
10
 * A PSR-3 compatible logger that uses CLImate for output.
11
 */
12
class Logger extends AbstractLogger
13
{
14
    /**
15
     * @var array $levels Conversion of the level strings to their numeric representations.
16
     */
17
    private $levels = [
18
        LogLevel::EMERGENCY =>  1,
19
        LogLevel::ALERT     =>  2,
20
        LogLevel::CRITICAL  =>  3,
21
        LogLevel::ERROR     =>  4,
22
        LogLevel::WARNING   =>  5,
23
        LogLevel::NOTICE    =>  6,
24
        LogLevel::INFO      =>  7,
25
        LogLevel::DEBUG     =>  8,
26
    ];
27
28
    /**
29
     * @var int $level Ignore logging attempts at a level less than this.
30
     */
31
    private $level;
32
33
    /**
34
     * @var CLImate $climate The underlying climate instance we are using for output.
35
     */
36
    private $climate;
37
38
    /**
39
     * Create a new Logger instance.
40
     *
41
     * @param mixed   $level   Either a LogLevel constant, or a string (eg 'debug'), or a number (1-8)
42
     * @param CLImate $climate An existing CLImate instance to use for output
43
     */
44 88
    public function __construct($level = LogLevel::INFO, CLImate $climate = null)
45
    {
46 88
        $this->setLogLevel($level);
47
48 88
        if ($climate === null) {
49
            $climate = new CLImate;
50
        }
51 88
        $this->climate = $climate;
52
53
        # Define some default styles to use for the output
54
        $commands = [
55 88
            "emergency" =>  ["white", "bold", "background_red"],
56 22
            "alert"     =>  ["white", "background_yellow"],
57 22
            "critical"  =>  ["red", "bold"],
58 22
            "error"     =>  ["red"],
59 22
            "warning"   =>  "yellow",
60 22
            "notice"    =>  "light_cyan",
61 22
            "info"      =>  "green",
62 22
            "debug"     =>  "dark_gray",
63 22
        ];
64
65
        # If any of the required styles are not defined then define them now
66 88
        foreach ($commands as $command => $style) {
67 88
            if (!$this->climate->style->get($command)) {
68 66
                $this->climate->style->addCommand($command, $style);
69
            }
70 22
        }
71 88
    }
72
73
74
    /**
75
     * Get a numeric log level for the passed parameter.
76
     *
77
     * @param mixed $level Either a LogLevel constant, or a string (eg 'debug'), or a number (1-8)
78
     *
79
     * @return int
80
     */
81 88
    private function convertLevel($level)
82
    {
83
        # If this is one of the defined string log levels then return it's numeric value
84 88
        $key = strtolower($level);
85 88
        if (isset($this->levels[$key])) {
86 88
            return $this->levels[$key];
87
        }
88
89
        # If it doesn't look like a number, default to the most severe log level
90 16
        if (!is_numeric($level)) {
91 4
            return 1;
92
        }
93
94
        # If it's lower than the lowest level then default to the lowest level
95 12
        if ($level < 1) {
96 4
            return 1;
97
        }
98
99
        # If it's higher than the highest level then default to the highest
100 8
        if ($level > 8) {
101 4
            return 8;
102
        }
103
104
        # If it's already a valid numeric log level then return it
105 4
        return $level;
106
    }
107
108
109
    /**
110
     * Set the current level we are logging at.
111
     *
112
     * @param mixed $level Ignore logging attempts at a level less the $level
113
     *
114
     * @return static
115
     */
116 88
    public function setLogLevel($level)
117
    {
118 88
        $this->level = $this->convertLevel($level);
119
120 88
        return $this;
121
    }
122
123
124
    /**
125
     * Log messages to a CLImate instance.
126
     *
127
     * @param mixed          $level    The level of the log message
128
     * @param string|object  $message  If an object is passed it must implement __toString()
129
     * @param array          $context  Placeholders to be substituted in the message
130
     *
131
     * @return static
132
     */
133 88
    public function log($level, $message, array $context = [])
134
    {
135 88
        if ($this->convertLevel($level) > $this->level) {
136 12
            return $this;
137
        }
138
139
        # Handle objects implementing __toString
140 80
        $message = (string) $message;
141
142
        # Handle any placeholders in the $context array
143 80
        foreach ($context as $key => $val) {
144 16
            $placeholder = "{" . $key . "}";
145
146
            # If this context key is used as a placeholder, then replace it, and remove it from the $context array
147 16
            if (strpos($message, $placeholder) !== false) {
148 8
                $val = (string) $val;
149 8
                $message = str_replace($placeholder, $val, $message);
150 14
                unset($context[$key]);
151 2
            }
152 20
        }
153
154
        # Send the message to the climate instance
155 80
        $this->climate->{$level}($message);
156
157
        # Append any context information not used as placeholders
158 80
        $this->outputRecursiveContext($level, $context, 1);
159
160 80
        return $this;
161
    }
162
163
164
    /**
165
     * Handle recursive arrays in the logging context.
166
     *
167
     * @param mixed  $level    The level of the log message
168
     * @param array  $context  The array of context to output
169
     * @param int    $indent   The current level of indentation to be used
170
     *
171
     * @return void
172
     */
173 80
    private function outputRecursiveContext($level, array $context, $indent)
174
    {
175 80
        foreach ($context as $key => $val) {
176 12
            $this->climate->tab($indent);
177
178 12
            $this->climate->{$level}()->inline("{$key}: ");
179
180 12
            if (is_array($val)) {
181 4
                $this->climate->{$level}("[");
182 4
                $this->outputRecursiveContext($level, $val, $indent + 1);
183 4
                $this->climate->tab($indent)->{$level}("]");
184 1
            } else {
185 12
                $this->climate->{$level}((string) $val);
186
            }
187 20
        }
188 80
    }
189
}
190