Completed
Pull Request — master (#24)
by
unknown
06:24 queued 03:07
created

Logger::message()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 3
nop 2
dl 0
loc 22
rs 8.6737
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Chris dePage <[email protected]>
4
 * @copyright 2009-2018 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Cli\Logger;
9
10
use Garden\Cli\Logger\Writer\WriterInterface;
11
12
/**
13
 * Garden logger that accepts multiple writers.
14
 */
15
class Logger implements LoggerInterface {
16
17
    /**
18
     * @var LoggerInterface[] An array of writers.
19
     */
20
    protected $writers = [];
21
22
    /**
23
     * @var int The max indent level to send to the writers.
24
     */
25
    protected $maxLevel = 2;
26
27
    /**
28
     * @var array An array of currently running tasks.
29
     */
30
    protected $taskStack = [];
31
32
    /**
33
     * Add a writer.
34
     *
35
     * @param WriterInterface $writer A writer to use.
36
     *
37
     * @return $this
38
     */
39
    public function addWriter(WriterInterface $writer) {
40
        array_push($this->writers, $writer);
41
42
        return $this;
43
    }
44
45
    /**
46
     * Set the maximum indent level to send to the writers.
47
     *
48
     * @param int $maxLevel The maximum indent level
49
     *
50
     * @return $this
51
     */
52
    public function setMaxLevel(int $maxLevel) {
53
        if ($maxLevel < 0) {
54
            throw new \InvalidArgumentException("The max level must be greater than zero.", 416);
55
        }
56
57
        $this->maxLevel = $maxLevel;
58
59
        return $this;
60
    }
61
62
    /**
63
     * Get the max indent level to send to the writers.
64
     *
65
     * @return int Returns the maxLevel.
66
     */
67
    public function getMaxLevel() {
68
        return $this->maxLevel;
69
    }
70
71
    /**
72
     * Log a message that designates the beginning of a task.
73
     *
74
     * @param string $str The message to output.
75
     * @return $this
76
     */
77
    public function begin(string $str) {
78
        $indentLevel = count($this->taskStack) + 1;
79
        $task = [$str, microtime(true), $indentLevel];
80
81
        array_push($this->taskStack, $task);
82
83
        // if the current indent level is less than the max, we trigger the logging behaviour
84
        if ($indentLevel <= $this->getMaxLevel()) {
85
            $this->write(time(), LogLevels::INFO, $str, $indentLevel);
86
        }
87
88
        return $this;
89
    }
90
91
    /**
92
     * Log an error message.
93
     *
94
     * @param string $str The message to output.
95
     *
96
     * @return $this
97
     */
98
    public function error(string $str) {
99
        $indentLevel = count($this->taskStack);
100
        $this->write(time(), LogLevels::ERROR, $str, $indentLevel);
101
102
        return $this;
103
    }
104
105
    /**
106
     * Log a success message.
107
     *
108
     * @param string $str The message to output.
109
     *
110
     * @return $this
111
     */
112
    public function success(string $str) {
113
        $indentLevel = count($this->taskStack);
114
        $this->write(time(), LogLevels::SUCCESS, $str, $indentLevel);
115
116
        return $this;
117
    }
118
119
    /**
120
     * Log a warning message.
121
     *
122
     * @param string $str The message to output.
123
     *
124
     * @return $this
125
     */
126
    public function warn(string $str) {
127
        $indentLevel = count($this->taskStack);
128
        $this->write(time(), LogLevels::WARNING, $str, $indentLevel);
129
130
        return $this;
131
    }
132
133
    /**
134
     * Log an info message.
135
     *
136
     * @param string $str The message to output.
137
     * @param bool $force Whether or not to force output of the message even if it's past the max depth.
138
     *
139
     * @return $this
140
     */
141
    public function message(string $str, bool $force = false) {
142
        $indentLevel = count($this->taskStack);
143
144
        if ($indentLevel > $this->getMaxLevel()) {
145
146
            // if not forced we drop the message
147
            if (!$force) {
148
                return $this;
149
            }
150
151
            // output everything that hasn't been output so far
152
            foreach ($this->taskStack as $task) {
153
                list($taskStr, $taskTimestamp, $taskIndentLevel) = $task;
154
                if ($taskIndentLevel > $this->getMaxLevel()) {
155
                  $this->write($taskTimestamp, LogLevels::INFO, $taskStr, $taskIndentLevel);
156
                }
157
            }
158
        }
159
160
        $this->write(time(), LogLevels::INFO, $str, $indentLevel);
161
162
        return $this;
163
    }
164
165
    /**
166
     * Log a message that represents a task being completed in success.
167
     *
168
     * @param string $str The message to output.
169
     * @param bool $force Whether or not to force a message past the max level to be output.
170
     *
171
     * @return $this
172
     */
173
    public function endSuccess(string $str, bool $force = false) {
174
        return $this->end($str, $force, LogLevels::SUCCESS);
175
    }
176
177
    /**
178
     * Log a message that represents a task being completed in an error.
179
     *
180
     * When formatting is turned on, error messages are output in red. Error messages are always output even if they are
181
     * past the maximum depth.
182
     *
183
     * @param string $str The message to output.
184
     *
185
     * @return $this
186
     */
187
    public function endError(string $str) {
188
        return $this->end($str, true, LogLevels::ERROR);
189
    }
190
191
    /**
192
     * Log a message that designates a task being completed.
193
     *
194
     * @param string $str The message to output.
195
     * @param bool $force Whether or not to always output the message even if the task is past the max depth.
196
     * @param string $logLevel The level/type of log to write.
197
     *
198
     * @return $this
199
     */
200
    public function end(string $str = '', bool $force =  false, $logLevel = LogLevels::INFO) {
201
        // get the task we are finishing (there has to be one)
202
        $task = array_pop($this->taskStack);
203
        if (is_null($task)) {
204
            trigger_error('Called Logger::end() without calling Logger::begin()', E_USER_NOTICE);
205
        } else {
206
            list($taskStr, $taskTimestamp, $indentLevel) = $task;
207
            $duration = microtime(true) - $taskTimestamp;
208
209
            if (count($this->taskStack) >= $this->getMaxLevel()) {
210
                if (!$force || !isset($taskStr) || $indentLevel >= $this->getMaxLevel()) {
211
                    return $this;
212
                }
213
            }
214
215
            // update the $str so we prepend the original task $str to it
216
            $str = trim($taskStr.' '.$str);
217
        }
218
219
        return $this->write(time(), $logLevel, $str, $indentLevel || 0, $duration || null);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $indentLevel does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
$indentLevel || 0 of type boolean is incompatible with the type integer expected by parameter $indentLevel of Garden\Cli\Logger\Logger::write(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

219
        return $this->write(time(), $logLevel, $str, /** @scrutinizer ignore-type */ $indentLevel || 0, $duration || null);
Loading history...
Comprehensibility Best Practice introduced by
The variable $duration does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
$duration || null of type boolean is incompatible with the type null|double expected by parameter $duration of Garden\Cli\Logger\Logger::write(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

219
        return $this->write(time(), $logLevel, $str, $indentLevel || 0, /** @scrutinizer ignore-type */ $duration || null);
Loading history...
220
    }
221
222
    /**
223
     * Log a message that ends a task with an HTTP status code.
224
     *
225
     * @param int $httpStatus The HTTP status code that represents the completion of a task.
226
     * @param bool $force Whether or not to force message output.
227
     *
228
     * @return $this
229
     *
230
     * @see LogFormatter::endSuccess(), LogFormatter::endError().
231
     */
232
    public function endHttpStatus(int $httpStatus, bool $force = false) {
233
        $statusStr = sprintf('%03d', $httpStatus);
234
235
        if ($httpStatus == 0 || $httpStatus >= 400) {
236
            $this->endError($statusStr);
237
        } elseif ($httpStatus >= 200 && $httpStatus < 300) {
238
            $this->endSuccess($statusStr, $force);
239
        } else {
240
            $this->end($statusStr, $force);
241
        }
242
243
        return $this;
244
    }
245
246
    /**
247
     * Write the stream.
248
     *
249
     * @param int $timestamp The unix timestamp of the log.
250
     * @param string $logLevel The level of the message (e.g. SUCCESS, WARNING, ERROR).
251
     * @param int $indentLevel The nesting level of the message.
252
     * @param string $message The message.
253
     * @param float|null $duration The duration to add to the message.
254
     *
255
     * @return $this
256
     */
257
    public function write(int $timestamp, string $logLevel, string $message, $indentLevel = 0, $duration = null) {
258
        foreach($this->writers as $writer) {
259
            $writer->write($timestamp, $logLevel, $message, $indentLevel, $duration);
0 ignored issues
show
Bug introduced by
The method write() does not exist on Garden\Cli\Logger\LoggerInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Garden\Cli\Logger\LoggerInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

259
            $writer->/** @scrutinizer ignore-call */ 
260
                     write($timestamp, $logLevel, $message, $indentLevel, $duration);
Loading history...
260
        }
261
262
        return $this;
263
    }
264
}
265