vendor/monolog/monolog/src/Monolog/Logger.php line 610

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