1 | <?php |
||
2 | namespace Elgg; |
||
3 | |||
4 | use Elgg\Printer\ErrorLogPrinter; |
||
5 | |||
6 | /** |
||
7 | * WARNING: API IN FLUX. DO NOT USE DIRECTLY. |
||
8 | * |
||
9 | * Use the elgg_* versions instead. |
||
10 | * |
||
11 | * @access private |
||
12 | * |
||
13 | * @package Elgg.Core |
||
14 | * @subpackage Logging |
||
15 | * @since 1.9.0 |
||
16 | */ |
||
17 | class Logger { |
||
18 | |||
19 | const OFF = 0; |
||
20 | const ERROR = 400; |
||
21 | const WARNING = 300; |
||
22 | const NOTICE = 250; |
||
23 | const INFO = 200; |
||
24 | |||
25 | protected static $levels = [ |
||
26 | 0 => 'OFF', |
||
27 | 200 => 'INFO', |
||
28 | 250 => 'NOTICE', |
||
29 | 300 => 'WARNING', |
||
30 | 400 => 'ERROR', |
||
31 | ]; |
||
32 | |||
33 | /** |
||
34 | * @var int |
||
35 | */ |
||
36 | public static $verbosity; |
||
37 | |||
38 | /** |
||
39 | * @var int The logging level |
||
40 | */ |
||
41 | protected $level = self::ERROR; |
||
42 | |||
43 | /** |
||
44 | * @var PluginHooksService |
||
45 | */ |
||
46 | protected $hooks; |
||
47 | |||
48 | /** |
||
49 | * @var Context |
||
50 | */ |
||
51 | private $context; |
||
52 | |||
53 | /** |
||
54 | * @var array |
||
55 | */ |
||
56 | private $disabled_stack; |
||
57 | |||
58 | /** |
||
59 | * @var Printer |
||
60 | */ |
||
61 | private $printer; |
||
62 | |||
63 | /** |
||
64 | * @var Config |
||
65 | */ |
||
66 | private $config; |
||
67 | |||
68 | /** |
||
69 | * Constructor |
||
70 | * |
||
71 | * @param PluginHooksService $hooks Hooks service |
||
72 | * @param Context $context Context service |
||
73 | * @param Config $config Config |
||
74 | * @param Printer $printer Printer |
||
75 | */ |
||
76 | 4417 | public function __construct(PluginHooksService $hooks, Context $context, Config $config, Printer $printer = null) { |
|
77 | 4417 | $this->hooks = $hooks; |
|
78 | 4417 | $this->context = $context; |
|
79 | 4417 | if (!isset($printer)) { |
|
80 | 60 | $printer = new ErrorLogPrinter(); |
|
81 | } |
||
82 | 4417 | $this->printer = $printer; |
|
83 | 4417 | $this->config = $config; |
|
84 | |||
85 | 4417 | $php_error_level = error_reporting(); |
|
86 | |||
87 | // value is in settings.php, use until boot values are available |
||
88 | 4417 | if ($this->config->hasInitialValue('debug')) { |
|
89 | 4417 | $this->setLevel($this->config->debug); |
|
90 | 4417 | return; |
|
91 | } |
||
92 | |||
93 | 9 | $this->level = self::OFF; |
|
94 | |||
95 | 9 | if (($php_error_level & E_NOTICE) == E_NOTICE) { |
|
96 | 9 | $this->level = self::NOTICE; |
|
97 | } elseif (($php_error_level & E_WARNING) == E_WARNING) { |
||
98 | $this->level = self::WARNING; |
||
99 | } elseif (($php_error_level & E_ERROR) == E_ERROR) { |
||
100 | $this->level = self::ERROR; |
||
101 | } |
||
102 | 9 | } |
|
103 | |||
104 | /** |
||
105 | * Set the logging level |
||
106 | * |
||
107 | * @param int $level The logging level |
||
108 | * @return void |
||
109 | */ |
||
110 | 4777 | public function setLevel($level) { |
|
111 | 4777 | if (!$level) { |
|
112 | // 0 or empty string |
||
113 | 6 | $this->level = self::OFF; |
|
114 | 6 | return; |
|
115 | } |
||
116 | |||
117 | // @todo Elgg has used string constants for logging levels |
||
118 | 4777 | if (is_string($level)) { |
|
119 | 4777 | $level = strtoupper($level); |
|
120 | 4777 | $level = array_search($level, self::$levels); |
|
121 | |||
122 | 4777 | if ($level !== false) { |
|
123 | 4777 | $this->level = $level; |
|
124 | } else { |
||
125 | $this->warn(__METHOD__ .": invalid level ignored."); |
||
126 | } |
||
127 | 4777 | return; |
|
128 | } |
||
129 | |||
130 | 1 | if (isset(self::$levels[$level])) { |
|
131 | 1 | $this->level = $level; |
|
132 | } else { |
||
133 | $this->warn(__METHOD__ .": invalid level ignored."); |
||
134 | } |
||
135 | 1 | } |
|
136 | |||
137 | /** |
||
138 | * Get the current logging level |
||
139 | * |
||
140 | * @return int |
||
141 | */ |
||
142 | 38 | public function getLevel() { |
|
143 | 38 | return $this->level; |
|
144 | } |
||
145 | |||
146 | /** |
||
147 | * Set custom printer |
||
148 | * |
||
149 | * @param Printer $printer Printer |
||
150 | * @return void |
||
151 | */ |
||
152 | public function setPrinter(Printer $printer) { |
||
153 | $this->printer = $printer; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Add a message to the log |
||
158 | * |
||
159 | * @param string $message The message to log |
||
160 | * @param int $level The logging level |
||
161 | * @return bool Whether the messages was logged |
||
162 | */ |
||
163 | 5379 | public function log($message, $level = self::NOTICE) { |
|
164 | 5379 | if ($this->disabled_stack) { |
|
0 ignored issues
–
show
|
|||
165 | // capture to top of stack |
||
166 | 213 | end($this->disabled_stack); |
|
167 | 213 | $key = key($this->disabled_stack); |
|
168 | 213 | $this->disabled_stack[$key][] = [ |
|
169 | 213 | 'message' => $message, |
|
170 | 213 | 'level' => $level, |
|
171 | ]; |
||
172 | } |
||
173 | |||
174 | 5379 | if ($this->level == self::OFF || $level < $this->level) { |
|
175 | 5379 | return false; |
|
176 | } |
||
177 | |||
178 | 1089 | if (!array_key_exists($level, self::$levels)) { |
|
179 | return false; |
||
180 | } |
||
181 | |||
182 | // when capturing, still use consistent return value |
||
183 | 1089 | if ($this->disabled_stack) { |
|
0 ignored issues
–
show
The expression
$this->disabled_stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
184 | 108 | return true; |
|
185 | } |
||
186 | |||
187 | 992 | $levelString = self::$levels[$level]; |
|
188 | |||
189 | 992 | $this->process("$levelString: $message", $level); |
|
190 | |||
191 | 992 | return true; |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * Log message at the ERROR level |
||
196 | * |
||
197 | * @param string $message The message to log |
||
198 | * @return bool |
||
199 | */ |
||
200 | 41 | public function error($message) { |
|
201 | 41 | return $this->log($message, self::ERROR); |
|
202 | } |
||
203 | |||
204 | /** |
||
205 | * Log message at the WARNING level |
||
206 | * |
||
207 | * @param string $message The message to log |
||
208 | * @return bool |
||
209 | */ |
||
210 | 664 | public function warn($message) { |
|
211 | 664 | return $this->log($message, self::WARNING); |
|
212 | } |
||
213 | |||
214 | /** |
||
215 | * Log message at the NOTICE level |
||
216 | * |
||
217 | * @param string $message The message to log |
||
218 | * @return bool |
||
219 | */ |
||
220 | 553 | public function notice($message) { |
|
221 | 553 | return $this->log($message, self::NOTICE); |
|
222 | } |
||
223 | |||
224 | /** |
||
225 | * Log message at the INFO level |
||
226 | * |
||
227 | * @param string $message The message to log |
||
228 | * @return bool |
||
229 | */ |
||
230 | 5379 | public function info($message) { |
|
231 | 5379 | return $this->log($message, self::INFO); |
|
232 | } |
||
233 | |||
234 | /** |
||
235 | * Dump data to log |
||
236 | * |
||
237 | * @param mixed $data The data to log |
||
238 | * @return void |
||
239 | */ |
||
240 | public function dump($data) { |
||
241 | $this->process($data, self::ERROR); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Process logging data |
||
246 | * |
||
247 | * @param mixed $data The data to process |
||
248 | * @param int $level The logging level for this data |
||
249 | * @return void |
||
250 | */ |
||
251 | 992 | protected function process($data, $level) { |
|
252 | |||
253 | // plugin can return false to stop the default logging method |
||
254 | $params = [ |
||
255 | 992 | 'level' => $level, |
|
256 | 992 | 'msg' => $data, |
|
257 | ]; |
||
258 | |||
259 | 992 | if (!$this->hooks->trigger('debug', 'log', $params, true)) { |
|
260 | 1 | return; |
|
261 | } |
||
262 | |||
263 | 991 | $this->printer->write($data, $level); |
|
264 | 991 | } |
|
265 | |||
266 | /** |
||
267 | * Temporarily disable logging and capture logs (before tests) |
||
268 | * |
||
269 | * Call disable() before your tests and enable() after. enable() will return a list of |
||
270 | * calls to log() (and helper methods) that were not acted upon. |
||
271 | * |
||
272 | * @note This behaves like a stack. You must call enable() for each disable() call. |
||
273 | * |
||
274 | * @return void |
||
275 | * @see enable() |
||
276 | * @access private |
||
277 | * @internal |
||
278 | */ |
||
279 | 366 | public function disable() { |
|
280 | 366 | $this->disabled_stack[] = []; |
|
281 | 366 | } |
|
282 | |||
283 | /** |
||
284 | * Restore logging and get record of log calls (after tests) |
||
285 | * |
||
286 | * @return array |
||
287 | * @see disable() |
||
288 | * @access private |
||
289 | * @internal |
||
290 | */ |
||
291 | 366 | public function enable() { |
|
292 | 366 | return array_pop($this->disabled_stack); |
|
293 | } |
||
294 | |||
295 | /** |
||
296 | * Reset the hooks service for this instance (testing) |
||
297 | * |
||
298 | * @param PluginHooksService $hooks the plugin hooks service |
||
299 | * |
||
300 | * @return void |
||
301 | * @access private |
||
302 | * @internal |
||
303 | */ |
||
304 | 1 | public function setHooks(PluginHooksService $hooks) { |
|
305 | 1 | $this->hooks = $hooks; |
|
306 | 1 | } |
|
307 | } |
||
308 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.