Deprecated : Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 58
Deprecated : Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 76
Symfony Profiler
<?php declare( strict_types = 1 );
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog ;
use DateTimeZone ;
use Monolog\Handler\HandlerInterface ;
use Psr\Log\LoggerInterface ;
use Psr\Log\InvalidArgumentException ;
use Psr\Log\LogLevel ;
use Throwable ;
use Stringable ;
/**
* Monolog log channel
*
* It contains a stack of Handlers and a stack of Processors,
* and uses them to store records that are added to it.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @phpstan-type Level Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY
* @phpstan-type LevelName 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY'
* @phpstan-type Record array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]}
*/
class Logger implements LoggerInterface , ResettableInterface
{
/**
* Detailed debug information
*/
public const DEBUG = 100 ;
/**
* Interesting events
*
* Examples: User logs in, SQL logs.
*/
public const INFO = 200 ;
/**
* Uncommon events
*/
public const NOTICE = 250 ;
/**
* Exceptional occurrences that are not errors
*
* Examples: Use of deprecated APIs, poor use of an API,
* undesirable things that are not necessarily wrong.
*/
public const WARNING = 300 ;
/**
* Runtime errors
*/
public const ERROR = 400 ;
/**
* Critical conditions
*
* Example: Application component unavailable, unexpected exception.
*/
public const CRITICAL = 500 ;
/**
* Action must be taken immediately
*
* Example: Entire website down, database unavailable, etc.
* This should trigger the SMS alerts and wake you up.
*/
public const ALERT = 550 ;
/**
* Urgent alert.
*/
public const EMERGENCY = 600 ;
/**
* Monolog API version
*
* This is only bumped when API breaks are done and should
* follow the major version of the library
*
* @var int
*/
public const API = 2 ;
/**
* This is a static variable and not a constant to serve as an extension point for custom levels
*
* @var array<int, string> $levels Logging levels with the levels as key
*
* @phpstan-var array<Level, LevelName> $levels Logging levels with the levels as key
*/
protected static $levels = [
self :: DEBUG => 'DEBUG' ,
self :: INFO => 'INFO' ,
self :: NOTICE => 'NOTICE' ,
self :: WARNING => 'WARNING' ,
self :: ERROR => 'ERROR' ,
self :: CRITICAL => 'CRITICAL' ,
self :: ALERT => 'ALERT' ,
self :: EMERGENCY => 'EMERGENCY' ,
];
/**
* Mapping between levels numbers defined in RFC 5424 and Monolog ones
*
* @phpstan-var array<int, Level> $rfc_5424_levels
*/
private const RFC_5424_LEVELS = [
7 => self :: DEBUG ,
6 => self :: INFO ,
5 => self :: NOTICE ,
4 => self :: WARNING ,
3 => self :: ERROR ,
2 => self :: CRITICAL ,
1 => self :: ALERT ,
0 => self :: EMERGENCY ,
];
/**
* @var string
*/
protected $name ;
/**
* The handler stack
*
* @var HandlerInterface[]
*/
protected $handlers ;
/**
* Processors that will process all log records
*
* To process records of a single handler instead, add the processor on that specific handler
*
* @var callable[]
*/
protected $processors ;
/**
* @var bool
*/
protected $microsecondTimestamps = true ;
/**
* @var DateTimeZone
*/
protected $timezone ;
/**
* @var callable|null
*/
protected $exceptionHandler ;
/**
* @var int Keeps track of depth to prevent infinite logging loops
*/
private $logDepth = 0 ;
/**
* @var \WeakMap<\Fiber, int>|null Keeps track of depth inside fibers to prevent infinite logging loops
*/
private $fiberLogDepth ;
/**
* @var bool Whether to detect infinite logging loops
*
* This can be disabled via {@see useLoggingLoopDetection} if you have async handlers that do not play well with this
*/
private $detectCycles = true ;
/**
* @psalm-param array<callable(array): array> $processors
*
* @param string $name The logging channel, a simple descriptive name that is attached to all log records
* @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
* @param callable[] $processors Optional array of processors
* @param DateTimeZone|null $timezone Optional timezone, if not provided date_default_timezone_get() will be used
*/
public function __construct ( string $name , array $handlers = [], array $processors = [], ? DateTimeZone $timezone = null )
{
$this -> name = $name ;
$this -> setHandlers ( $handlers );
$this -> processors = $processors ;
$this -> timezone = $timezone ?: new DateTimeZone ( date_default_timezone_get () ?: 'UTC' );
if (\PHP_VERSION_ID >= 80100 ) {
// Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
/** @var \WeakMap<\Fiber, int> $fiberLogDepth */
$fiberLogDepth = new \WeakMap ();
$this -> fiberLogDepth = $fiberLogDepth ;
}
}
public function getName (): string
{
return $this -> name ;
}
/**
* Return a new cloned instance with the name changed
*/
public function withName ( string $name ): self
{
$new = clone $this ;
$new -> name = $name ;
return $new ;
}
/**
* Pushes a handler on to the stack.
*/
public function pushHandler ( HandlerInterface $handler ): self
{
array_unshift ( $this -> handlers , $handler );
return $this ;
}
/**
* Pops a handler from the stack
*
* @throws \LogicException If empty handler stack
*/
public function popHandler (): HandlerInterface
{
if (!$this -> handlers ) {
throw new \LogicException ( 'You tried to pop from an empty handler stack.' );
}
return array_shift ( $this -> handlers );
}
/**
* Set handlers, replacing all existing ones.
*
* If a map is passed, keys will be ignored.
*
* @param HandlerInterface[] $handlers
*/
public function setHandlers (array $handlers ): self
{
$this -> handlers = [];
foreach (array_reverse ( $handlers ) as $handler ) {
$this -> pushHandler ( $handler );
}
return $this ;
}
/**
* @return HandlerInterface[]
*/
public function getHandlers (): array
{
return $this -> handlers ;
}
/**
* Adds a processor on to the stack.
*/
public function pushProcessor (callable $callback ): self
{
array_unshift ( $this -> processors , $callback );
return $this ;
}
/**
* Removes the processor on top of the stack and returns it.
*
* @throws \LogicException If empty processor stack
* @return callable
*/
public function popProcessor (): callable
{
if (!$this -> processors ) {
throw new \LogicException ( 'You tried to pop from an empty processor stack.' );
}
return array_shift ( $this -> processors );
}
/**
* @return callable[]
*/
public function getProcessors (): array
{
return $this -> processors ;
}
/**
* Control the use of microsecond resolution timestamps in the 'datetime'
* member of new records.
*
* As of PHP7.1 microseconds are always included by the engine, so
* there is no performance penalty and Monolog 2 enabled microseconds
* by default. This function lets you disable them though in case you want
* to suppress microseconds from the output.
*
* @param bool $micro True to use microtime() to create timestamps
*/
public function useMicrosecondTimestamps ( bool $micro ): self
{
$this -> microsecondTimestamps = $micro ;
return $this ;
}
public function useLoggingLoopDetection ( bool $detectCycles ): self
{
$this -> detectCycles = $detectCycles ;
return $this ;
}
/**
* Adds a log record.
*
* @param int $level The logging level (a Monolog or RFC 5424 level)
* @param string $message The log message
* @param mixed[] $context The log context
* @param DateTimeImmutable $datetime Optional log date to log into the past or future
* @return bool Whether the record has been processed
*
* @phpstan-param Level $level
*/
public function addRecord ( int $level , string $message , array $context = [], DateTimeImmutable $datetime = null ): bool
{
if (isset(self :: RFC_5424_LEVELS [ $level ])) {
$level = self :: RFC_5424_LEVELS [ $level ];
}
if ($this -> detectCycles ) {
if (\PHP_VERSION_ID >= 80100 && $fiber = \Fiber :: getCurrent ()) {
$this -> fiberLogDepth [ $fiber ] = $this -> fiberLogDepth [ $fiber ] ?? 0 ;
$logDepth = ++ $this -> fiberLogDepth [ $fiber ];
} else {
$logDepth = ++ $this -> logDepth ;
}
} else {
$logDepth = 0 ;
}
if ($logDepth === 3 ) {
$this -> warning ( 'A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.' );
return false ;
} elseif ($logDepth >= 5 ) { // log depth 4 is let through, so we can log the warning above
return false ;
}
try {
$record = null ;
foreach ($this -> handlers as $handler ) {
if (null === $record ) {
// skip creating the record as long as no handler is going to handle it
if (! $handler -> isHandling ([ 'level' => $level ])) {
continue;
}
$levelName = static:: getLevelName ( $level );
$record = [
'message' => $message ,
'context' => $context ,
'level' => $level ,
'level_name' => $levelName ,
'channel' => $this -> name ,
'datetime' => $datetime ?? new DateTimeImmutable ( $this -> microsecondTimestamps , $this -> timezone ),
'extra' => [],
];
try {
foreach ($this -> processors as $processor ) {
$record = $processor ( $record );
}
} catch (Throwable $e ) {
$this -> handleException ( $e , $record );
return true ;
}
}
// once the record exists, send it to all handlers as long as the bubbling chain is not interrupted
try {
if (true === $handler -> handle ( $record )) {
break;
}
} catch (Throwable $e ) {
$this -> handleException ( $e , $record );
return true ;
}
}
} finally {
if ($this -> detectCycles ) {
if (isset($fiber )) {
$this -> fiberLogDepth [ $fiber ]--;
} else {
$this -> logDepth --;
}
}
}
return null !== $record ;
}
/**
* Ends a log cycle and frees all resources used by handlers.
*
* Closing a Handler means flushing all buffers and freeing any open resources/handles.
* Handlers that have been closed should be able to accept log records again and re-open
* themselves on demand, but this may not always be possible depending on implementation.
*
* This is useful at the end of a request and will be called automatically on every handler
* when they get destructed.
*/
public function close (): void
{
foreach ($this -> handlers as $handler ) {
$handler -> close ();
}
}
/**
* Ends a log cycle and resets all handlers and processors to their initial state.
*
* Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal
* state, and getting it back to a state in which it can receive log records again.
*
* This is useful in case you want to avoid logs leaking between two requests or jobs when you
* have a long running process like a worker or an application server serving multiple requests
* in one process.
*/
public function reset (): void
{
foreach ($this -> handlers as $handler ) {
if ($handler instanceof ResettableInterface ) {
$handler -> reset ();
}
}
foreach ($this -> processors as $processor ) {
if ($processor instanceof ResettableInterface ) {
$processor -> reset ();
}
}
}
/**
* Gets all supported logging levels.
*
* @return array<string, int> Assoc array with human-readable level names => level codes.
* @phpstan-return array<LevelName, Level>
*/
public static function getLevels (): array
{
return array_flip (static:: $levels );
}
/**
* Gets the name of the logging level.
*
* @throws \Psr\Log\InvalidArgumentException If level is not defined
*
* @phpstan-param Level $level
* @phpstan-return LevelName
*/
public static function getLevelName ( int $level ): string
{
if (!isset(static::$levels [ $level ])) {
throw new InvalidArgumentException ( 'Level "' . $level . '" is not defined, use one of: ' . implode ( ', ' , array_keys (static:: $levels )));
}
return static::$levels [ $level ];
}
/**
* Converts PSR-3 levels to Monolog ones if necessary
*
* @param string|int $level Level number (monolog) or name (PSR-3)
* @throws \Psr\Log\InvalidArgumentException If level is not defined
*
* @phpstan-param Level|LevelName|LogLevel::* $level
* @phpstan-return Level
*/
public static function toMonologLevel ( $level ): int
{
if (is_string ( $level )) {
if (is_numeric ( $level )) {
/** @phpstan-ignore-next-line */
return intval ( $level );
}
// Contains chars of all log levels and avoids using strtoupper() which may have
// strange results depending on locale (for example, "i" will become "İ" in Turkish locale)
$upper = strtr ( $level , 'abcdefgilmnortuwy' , 'ABCDEFGILMNORTUWY' );
if (defined ( __CLASS__ . '::' . $upper )) {
return constant ( __CLASS__ . '::' . $upper );
}
throw new InvalidArgumentException ( 'Level "' . $level . '" is not defined, use one of: ' . implode ( ', ' , array_keys (static:: $levels ) + static:: $levels ));
}
if (!is_int ( $level )) {
throw new InvalidArgumentException ( 'Level "' . var_export ( $level , true ). '" is not defined, use one of: ' . implode ( ', ' , array_keys (static:: $levels ) + static:: $levels ));
}
return $level ;
}
/**
* Checks whether the Logger has a handler that listens on the given level
*
* @phpstan-param Level $level
*/
public function isHandling ( int $level ): bool
{
$record = [
'level' => $level ,
];
foreach ($this -> handlers as $handler ) {
if ($handler -> isHandling ( $record )) {
return true ;
}
}
return false ;
}
/**
* Set a custom exception handler that will be called if adding a new record fails
*
* The callable will receive an exception object and the record that failed to be logged
*/
public function setExceptionHandler (?callable $callback ): self
{
$this -> exceptionHandler = $callback ;
return $this ;
}
public function getExceptionHandler (): ?callable
{
return $this -> exceptionHandler ;
}
/**
* Adds a log record at an arbitrary level.
*
* This method allows for compatibility with common interfaces.
*
* @param mixed $level The log level (a Monolog, PSR-3 or RFC 5424 level)
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*
* @phpstan-param Level|LevelName|LogLevel::* $level
*/
public function log ( $level , $message , array $context = []): void
{
if (!is_int ( $level ) && ! is_string ( $level )) {
throw new \InvalidArgumentException ( '$level is expected to be a string or int' );
}
if (isset(self :: RFC_5424_LEVELS [ $level ])) {
$level = self :: RFC_5424_LEVELS [ $level ];
}
$level = static:: toMonologLevel ( $level );
$this -> addRecord ( $level , (string) $message , $context );
}
/**
* Adds a log record at the DEBUG level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function debug ( $message , array $context = []): void
{
$this -> addRecord (static:: DEBUG , (string) $message , $context );
}
/**
* Adds a log record at the INFO level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function info ( $message , array $context = []): void
{
$this -> addRecord (static:: INFO , (string) $message , $context );
}
/**
* Adds a log record at the NOTICE level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function notice ( $message , array $context = []): void
{
$this -> addRecord (static:: NOTICE , (string) $message , $context );
}
/**
* Adds a log record at the WARNING level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function warning ( $message , array $context = []): void
{
$this -> addRecord (static:: WARNING , (string) $message , $context );
}
/**
* Adds a log record at the ERROR level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function error ( $message , array $context = []): void
{
$this -> addRecord (static:: ERROR , (string) $message , $context );
}
/**
* Adds a log record at the CRITICAL level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function critical ( $message , array $context = []): void
{
$this -> addRecord (static:: CRITICAL , (string) $message , $context );
}
/**
* Adds a log record at the ALERT level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function alert ( $message , array $context = []): void
{
$this -> addRecord (static:: ALERT , (string) $message , $context );
}
/**
* Adds a log record at the EMERGENCY level.
*
* This method allows for compatibility with common interfaces.
*
* @param string|Stringable $message The log message
* @param mixed[] $context The log context
*/
public function emergency ( $message , array $context = []): void
{
$this -> addRecord (static:: EMERGENCY , (string) $message , $context );
}
/**
* Sets the timezone to be used for the timestamp of log records.
*/
public function setTimezone ( DateTimeZone $tz ): self
{
$this -> timezone = $tz ;
return $this ;
}
/**
* Returns the timezone to be used for the timestamp of log records.
*/
public function getTimezone (): DateTimeZone
{
return $this -> timezone ;
}
/**
* Delegates exception management to the custom exception handler,
* or throws the exception if no custom handler is set.
*
* @param array $record
* @phpstan-param Record $record
*/
protected function handleException ( Throwable $e , array $record ): void
{
if (!$this -> exceptionHandler ) {
throw $e ;
}
($this -> exceptionHandler )( $e , $record );
}
/**
* @return array<string, mixed>
*/
public function __serialize (): array
{
return [
'name' => $this -> name ,
'handlers' => $this -> handlers ,
'processors' => $this -> processors ,
'microsecondTimestamps' => $this -> microsecondTimestamps ,
'timezone' => $this -> timezone ,
'exceptionHandler' => $this -> exceptionHandler ,
'logDepth' => $this -> logDepth ,
'detectCycles' => $this -> detectCycles ,
];
}
/**
* @param array<string, mixed> $data
*/
public function __unserialize (array $data ): void
{
foreach (['name' , 'handlers' , 'processors' , 'microsecondTimestamps' , 'timezone' , 'exceptionHandler' , 'logDepth' , 'detectCycles' ] as $property ) {
if (isset($data [ $property ])) {
$this -> $property = $data [ $property ];
}
}
if (\PHP_VERSION_ID >= 80100 ) {
// Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
/** @var \WeakMap<\Fiber, int> $fiberLogDepth */
$fiberLogDepth = new \WeakMap ();
$this -> fiberLogDepth = $fiberLogDepth ;
}
}
}