scratch – Blame information for rev 115

Subversion Repositories:
Rev:
Rev Author Line No. Line
115 office 1 <?php
2  
3 /*
4 * This file is part of the Monolog package.
5 *
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11  
12 namespace Monolog;
13  
14 use Monolog\Handler\HandlerInterface;
15 use Monolog\Handler\StreamHandler;
16 use Psr\Log\LoggerInterface;
17 use Psr\Log\InvalidArgumentException;
18  
19 /**
20 * Monolog log channel
21 *
22 * It contains a stack of Handlers and a stack of Processors,
23 * and uses them to store records that are added to it.
24 *
25 * @author Jordi Boggiano <j.boggiano@seld.be>
26 */
27 class Logger implements LoggerInterface
28 {
29 /**
30 * Detailed debug information
31 */
32 const DEBUG = 100;
33  
34 /**
35 * Interesting events
36 *
37 * Examples: User logs in, SQL logs.
38 */
39 const INFO = 200;
40  
41 /**
42 * Uncommon events
43 */
44 const NOTICE = 250;
45  
46 /**
47 * Exceptional occurrences that are not errors
48 *
49 * Examples: Use of deprecated APIs, poor use of an API,
50 * undesirable things that are not necessarily wrong.
51 */
52 const WARNING = 300;
53  
54 /**
55 * Runtime errors
56 */
57 const ERROR = 400;
58  
59 /**
60 * Critical conditions
61 *
62 * Example: Application component unavailable, unexpected exception.
63 */
64 const CRITICAL = 500;
65  
66 /**
67 * Action must be taken immediately
68 *
69 * Example: Entire website down, database unavailable, etc.
70 * This should trigger the SMS alerts and wake you up.
71 */
72 const ALERT = 550;
73  
74 /**
75 * Urgent alert.
76 */
77 const EMERGENCY = 600;
78  
79 /**
80 * Monolog API version
81 *
82 * This is only bumped when API breaks are done and should
83 * follow the major version of the library
84 *
85 * @var int
86 */
87 const API = 1;
88  
89 /**
90 * Logging levels from syslog protocol defined in RFC 5424
91 *
92 * @var array $levels Logging levels
93 */
94 protected static $levels = array(
95 self::DEBUG => 'DEBUG',
96 self::INFO => 'INFO',
97 self::NOTICE => 'NOTICE',
98 self::WARNING => 'WARNING',
99 self::ERROR => 'ERROR',
100 self::CRITICAL => 'CRITICAL',
101 self::ALERT => 'ALERT',
102 self::EMERGENCY => 'EMERGENCY',
103 );
104  
105 /**
106 * @var \DateTimeZone
107 */
108 protected static $timezone;
109  
110 /**
111 * @var string
112 */
113 protected $name;
114  
115 /**
116 * The handler stack
117 *
118 * @var HandlerInterface[]
119 */
120 protected $handlers;
121  
122 /**
123 * Processors that will process all log records
124 *
125 * To process records of a single handler instead, add the processor on that specific handler
126 *
127 * @var callable[]
128 */
129 protected $processors;
130  
131 /**
132 * @var bool
133 */
134 protected $microsecondTimestamps = true;
135  
136 /**
137 * @param string $name The logging channel
138 * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
139 * @param callable[] $processors Optional array of processors
140 */
141 public function __construct($name, array $handlers = array(), array $processors = array())
142 {
143 $this->name = $name;
144 $this->handlers = $handlers;
145 $this->processors = $processors;
146 }
147  
148 /**
149 * @return string
150 */
151 public function getName()
152 {
153 return $this->name;
154 }
155  
156 /**
157 * Return a new cloned instance with the name changed
158 *
159 * @return static
160 */
161 public function withName($name)
162 {
163 $new = clone $this;
164 $new->name = $name;
165  
166 return $new;
167 }
168  
169 /**
170 * Pushes a handler on to the stack.
171 *
172 * @param HandlerInterface $handler
173 * @return $this
174 */
175 public function pushHandler(HandlerInterface $handler)
176 {
177 array_unshift($this->handlers, $handler);
178  
179 return $this;
180 }
181  
182 /**
183 * Pops a handler from the stack
184 *
185 * @return HandlerInterface
186 */
187 public function popHandler()
188 {
189 if (!$this->handlers) {
190 throw new \LogicException('You tried to pop from an empty handler stack.');
191 }
192  
193 return array_shift($this->handlers);
194 }
195  
196 /**
197 * Set handlers, replacing all existing ones.
198 *
199 * If a map is passed, keys will be ignored.
200 *
201 * @param HandlerInterface[] $handlers
202 * @return $this
203 */
204 public function setHandlers(array $handlers)
205 {
206 $this->handlers = array();
207 foreach (array_reverse($handlers) as $handler) {
208 $this->pushHandler($handler);
209 }
210  
211 return $this;
212 }
213  
214 /**
215 * @return HandlerInterface[]
216 */
217 public function getHandlers()
218 {
219 return $this->handlers;
220 }
221  
222 /**
223 * Adds a processor on to the stack.
224 *
225 * @param callable $callback
226 * @return $this
227 */
228 public function pushProcessor($callback)
229 {
230 if (!is_callable($callback)) {
231 throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
232 }
233 array_unshift($this->processors, $callback);
234  
235 return $this;
236 }
237  
238 /**
239 * Removes the processor on top of the stack and returns it.
240 *
241 * @return callable
242 */
243 public function popProcessor()
244 {
245 if (!$this->processors) {
246 throw new \LogicException('You tried to pop from an empty processor stack.');
247 }
248  
249 return array_shift($this->processors);
250 }
251  
252 /**
253 * @return callable[]
254 */
255 public function getProcessors()
256 {
257 return $this->processors;
258 }
259  
260 /**
261 * Control the use of microsecond resolution timestamps in the 'datetime'
262 * member of new records.
263 *
264 * Generating microsecond resolution timestamps by calling
265 * microtime(true), formatting the result via sprintf() and then parsing
266 * the resulting string via \DateTime::createFromFormat() can incur
267 * a measurable runtime overhead vs simple usage of DateTime to capture
268 * a second resolution timestamp in systems which generate a large number
269 * of log events.
270 *
271 * @param bool $micro True to use microtime() to create timestamps
272 */
273 public function useMicrosecondTimestamps($micro)
274 {
275 $this->microsecondTimestamps = (bool) $micro;
276 }
277  
278 /**
279 * Adds a log record.
280 *
281 * @param int $level The logging level
282 * @param string $message The log message
283 * @param array $context The log context
284 * @return Boolean Whether the record has been processed
285 */
286 public function addRecord($level, $message, array $context = array())
287 {
288 if (!$this->handlers) {
289 $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
290 }
291  
292 $levelName = static::getLevelName($level);
293  
294 // check if any handler will handle this message so we can return early and save cycles
295 $handlerKey = null;
296 reset($this->handlers);
297 while ($handler = current($this->handlers)) {
298 if ($handler->isHandling(array('level' => $level))) {
299 $handlerKey = key($this->handlers);
300 break;
301 }
302  
303 next($this->handlers);
304 }
305  
306 if (null === $handlerKey) {
307 return false;
308 }
309  
310 if (!static::$timezone) {
311 static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
312 }
313  
314 // php7.1+ always has microseconds enabled, so we do not need this hack
315 if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) {
316 $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
317 } else {
318 $ts = new \DateTime(null, static::$timezone);
319 }
320 $ts->setTimezone(static::$timezone);
321  
322 $record = array(
323 'message' => (string) $message,
324 'context' => $context,
325 'level' => $level,
326 'level_name' => $levelName,
327 'channel' => $this->name,
328 'datetime' => $ts,
329 'extra' => array(),
330 );
331  
332 foreach ($this->processors as $processor) {
333 $record = call_user_func($processor, $record);
334 }
335  
336 while ($handler = current($this->handlers)) {
337 if (true === $handler->handle($record)) {
338 break;
339 }
340  
341 next($this->handlers);
342 }
343  
344 return true;
345 }
346  
347 /**
348 * Adds a log record at the DEBUG level.
349 *
350 * @param string $message The log message
351 * @param array $context The log context
352 * @return Boolean Whether the record has been processed
353 */
354 public function addDebug($message, array $context = array())
355 {
356 return $this->addRecord(static::DEBUG, $message, $context);
357 }
358  
359 /**
360 * Adds a log record at the INFO level.
361 *
362 * @param string $message The log message
363 * @param array $context The log context
364 * @return Boolean Whether the record has been processed
365 */
366 public function addInfo($message, array $context = array())
367 {
368 return $this->addRecord(static::INFO, $message, $context);
369 }
370  
371 /**
372 * Adds a log record at the NOTICE level.
373 *
374 * @param string $message The log message
375 * @param array $context The log context
376 * @return Boolean Whether the record has been processed
377 */
378 public function addNotice($message, array $context = array())
379 {
380 return $this->addRecord(static::NOTICE, $message, $context);
381 }
382  
383 /**
384 * Adds a log record at the WARNING level.
385 *
386 * @param string $message The log message
387 * @param array $context The log context
388 * @return Boolean Whether the record has been processed
389 */
390 public function addWarning($message, array $context = array())
391 {
392 return $this->addRecord(static::WARNING, $message, $context);
393 }
394  
395 /**
396 * Adds a log record at the ERROR level.
397 *
398 * @param string $message The log message
399 * @param array $context The log context
400 * @return Boolean Whether the record has been processed
401 */
402 public function addError($message, array $context = array())
403 {
404 return $this->addRecord(static::ERROR, $message, $context);
405 }
406  
407 /**
408 * Adds a log record at the CRITICAL level.
409 *
410 * @param string $message The log message
411 * @param array $context The log context
412 * @return Boolean Whether the record has been processed
413 */
414 public function addCritical($message, array $context = array())
415 {
416 return $this->addRecord(static::CRITICAL, $message, $context);
417 }
418  
419 /**
420 * Adds a log record at the ALERT level.
421 *
422 * @param string $message The log message
423 * @param array $context The log context
424 * @return Boolean Whether the record has been processed
425 */
426 public function addAlert($message, array $context = array())
427 {
428 return $this->addRecord(static::ALERT, $message, $context);
429 }
430  
431 /**
432 * Adds a log record at the EMERGENCY level.
433 *
434 * @param string $message The log message
435 * @param array $context The log context
436 * @return Boolean Whether the record has been processed
437 */
438 public function addEmergency($message, array $context = array())
439 {
440 return $this->addRecord(static::EMERGENCY, $message, $context);
441 }
442  
443 /**
444 * Gets all supported logging levels.
445 *
446 * @return array Assoc array with human-readable level names => level codes.
447 */
448 public static function getLevels()
449 {
450 return array_flip(static::$levels);
451 }
452  
453 /**
454 * Gets the name of the logging level.
455 *
456 * @param int $level
457 * @return string
458 */
459 public static function getLevelName($level)
460 {
461 if (!isset(static::$levels[$level])) {
462 throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels)));
463 }
464  
465 return static::$levels[$level];
466 }
467  
468 /**
469 * Converts PSR-3 levels to Monolog ones if necessary
470 *
471 * @param string|int Level number (monolog) or name (PSR-3)
472 * @return int
473 */
474 public static function toMonologLevel($level)
475 {
476 if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) {
477 return constant(__CLASS__.'::'.strtoupper($level));
478 }
479  
480 return $level;
481 }
482  
483 /**
484 * Checks whether the Logger has a handler that listens on the given level
485 *
486 * @param int $level
487 * @return Boolean
488 */
489 public function isHandling($level)
490 {
491 $record = array(
492 'level' => $level,
493 );
494  
495 foreach ($this->handlers as $handler) {
496 if ($handler->isHandling($record)) {
497 return true;
498 }
499 }
500  
501 return false;
502 }
503  
504 /**
505 * Adds a log record at an arbitrary level.
506 *
507 * This method allows for compatibility with common interfaces.
508 *
509 * @param mixed $level The log level
510 * @param string $message The log message
511 * @param array $context The log context
512 * @return Boolean Whether the record has been processed
513 */
514 public function log($level, $message, array $context = array())
515 {
516 $level = static::toMonologLevel($level);
517  
518 return $this->addRecord($level, $message, $context);
519 }
520  
521 /**
522 * Adds a log record at the DEBUG level.
523 *
524 * This method allows for compatibility with common interfaces.
525 *
526 * @param string $message The log message
527 * @param array $context The log context
528 * @return Boolean Whether the record has been processed
529 */
530 public function debug($message, array $context = array())
531 {
532 return $this->addRecord(static::DEBUG, $message, $context);
533 }
534  
535 /**
536 * Adds a log record at the INFO level.
537 *
538 * This method allows for compatibility with common interfaces.
539 *
540 * @param string $message The log message
541 * @param array $context The log context
542 * @return Boolean Whether the record has been processed
543 */
544 public function info($message, array $context = array())
545 {
546 return $this->addRecord(static::INFO, $message, $context);
547 }
548  
549 /**
550 * Adds a log record at the NOTICE level.
551 *
552 * This method allows for compatibility with common interfaces.
553 *
554 * @param string $message The log message
555 * @param array $context The log context
556 * @return Boolean Whether the record has been processed
557 */
558 public function notice($message, array $context = array())
559 {
560 return $this->addRecord(static::NOTICE, $message, $context);
561 }
562  
563 /**
564 * Adds a log record at the WARNING level.
565 *
566 * This method allows for compatibility with common interfaces.
567 *
568 * @param string $message The log message
569 * @param array $context The log context
570 * @return Boolean Whether the record has been processed
571 */
572 public function warn($message, array $context = array())
573 {
574 return $this->addRecord(static::WARNING, $message, $context);
575 }
576  
577 /**
578 * Adds a log record at the WARNING level.
579 *
580 * This method allows for compatibility with common interfaces.
581 *
582 * @param string $message The log message
583 * @param array $context The log context
584 * @return Boolean Whether the record has been processed
585 */
586 public function warning($message, array $context = array())
587 {
588 return $this->addRecord(static::WARNING, $message, $context);
589 }
590  
591 /**
592 * Adds a log record at the ERROR level.
593 *
594 * This method allows for compatibility with common interfaces.
595 *
596 * @param string $message The log message
597 * @param array $context The log context
598 * @return Boolean Whether the record has been processed
599 */
600 public function err($message, array $context = array())
601 {
602 return $this->addRecord(static::ERROR, $message, $context);
603 }
604  
605 /**
606 * Adds a log record at the ERROR level.
607 *
608 * This method allows for compatibility with common interfaces.
609 *
610 * @param string $message The log message
611 * @param array $context The log context
612 * @return Boolean Whether the record has been processed
613 */
614 public function error($message, array $context = array())
615 {
616 return $this->addRecord(static::ERROR, $message, $context);
617 }
618  
619 /**
620 * Adds a log record at the CRITICAL level.
621 *
622 * This method allows for compatibility with common interfaces.
623 *
624 * @param string $message The log message
625 * @param array $context The log context
626 * @return Boolean Whether the record has been processed
627 */
628 public function crit($message, array $context = array())
629 {
630 return $this->addRecord(static::CRITICAL, $message, $context);
631 }
632  
633 /**
634 * Adds a log record at the CRITICAL level.
635 *
636 * This method allows for compatibility with common interfaces.
637 *
638 * @param string $message The log message
639 * @param array $context The log context
640 * @return Boolean Whether the record has been processed
641 */
642 public function critical($message, array $context = array())
643 {
644 return $this->addRecord(static::CRITICAL, $message, $context);
645 }
646  
647 /**
648 * Adds a log record at the ALERT level.
649 *
650 * This method allows for compatibility with common interfaces.
651 *
652 * @param string $message The log message
653 * @param array $context The log context
654 * @return Boolean Whether the record has been processed
655 */
656 public function alert($message, array $context = array())
657 {
658 return $this->addRecord(static::ALERT, $message, $context);
659 }
660  
661 /**
662 * Adds a log record at the EMERGENCY level.
663 *
664 * This method allows for compatibility with common interfaces.
665 *
666 * @param string $message The log message
667 * @param array $context The log context
668 * @return Boolean Whether the record has been processed
669 */
670 public function emerg($message, array $context = array())
671 {
672 return $this->addRecord(static::EMERGENCY, $message, $context);
673 }
674  
675 /**
676 * Adds a log record at the EMERGENCY level.
677 *
678 * This method allows for compatibility with common interfaces.
679 *
680 * @param string $message The log message
681 * @param array $context The log context
682 * @return Boolean Whether the record has been processed
683 */
684 public function emergency($message, array $context = array())
685 {
686 return $this->addRecord(static::EMERGENCY, $message, $context);
687 }
688  
689 /**
690 * Set the timezone to be used for the timestamp of log records.
691 *
692 * This is stored globally for all Logger instances
693 *
694 * @param \DateTimeZone $tz Timezone object
695 */
696 public static function setTimezone(\DateTimeZone $tz)
697 {
698 self::$timezone = $tz;
699 }
700 }