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); |
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
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
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...
|
|||
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 |