diff --git a/libraries/src/Log/Log.php b/libraries/src/Log/Log.php index 18c743645ba4c..037a6a8100f91 100644 --- a/libraries/src/Log/Log.php +++ b/libraries/src/Log/Log.php @@ -127,6 +127,14 @@ class Log */ protected $lookup = array(); + /** + * The registry of available loggers + * + * @var LoggerRegistry + * @since __DEPLOY_VERSION__ + */ + protected $loggerRegistry; + /** * Constructor. * @@ -134,6 +142,7 @@ class Log */ protected function __construct() { + $this->loggerRegistry = new LoggerRegistry; } /** @@ -189,6 +198,28 @@ public static function addLogger(array $options, $priorities = self::ALL, $categ static::$instance->addLoggerInternal($options, $priorities, $categories, $exclude); } + /** + * Register a logger to the registry + * + * @param string $key The service key to be registered + * @param string $class The class name of the logger + * @param boolean $replace Flag indicating the service key may replace an existing definition + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function registerLogger(string $key, string $class, bool $replace = false) + { + // Automatically instantiate the singleton object if not already done. + if (empty(static::$instance)) + { + static::setInstance(new static); + } + + static::$instance->loggerRegistry->register($key, $class, $replace); + } + /** * Add a logger to the Log instance. Loggers route log entries to the correct files/systems to be logged. * This method allows you to extend Log completely. @@ -306,11 +337,27 @@ protected function addLogEntry(LogEntry $entry) // Attempt to instantiate the logger object if it doesn't already exist. if (empty($this->loggers[$signature])) { - $class = __NAMESPACE__ . '\\Logger\\' . ucfirst($this->configurations[$signature]['logger']) . 'Logger'; - - if (!class_exists($class)) + if ($this->loggerRegistry->hasLogger($this->configurations[$signature]['logger'])) + { + $class = $this->loggerRegistry->getLoggerClass($this->configurations[$signature]['logger']); + } + else { - throw new \RuntimeException('Unable to create a Logger instance: ' . $class); + @trigger_error( + sprintf( + 'Attempting to automatically resolve loggers to the %s namespace is deprecated as of 4.0 and will be removed in 5.0.' + . ' Use the logger registry instead.', + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); + + $class = __NAMESPACE__ . '\\Logger\\' . ucfirst($this->configurations[$signature]['logger']) . 'Logger'; + + if (!class_exists($class)) + { + throw new \RuntimeException('Unable to create a Logger instance: ' . $class); + } } $this->loggers[$signature] = new $class($this->configurations[$signature]); diff --git a/libraries/src/Log/LoggerRegistry.php b/libraries/src/Log/LoggerRegistry.php new file mode 100644 index 0000000000000..66bf8a442a1d8 --- /dev/null +++ b/libraries/src/Log/LoggerRegistry.php @@ -0,0 +1,97 @@ + Logger\CallbackLogger::class, + 'database' => Logger\DatabaseLogger::class, + 'echo' => Logger\EchoLogger::class, + 'formattedtext' => Logger\FormattedtextLogger::class, + 'messagequeue' => Logger\MessagequeueLogger::class, + 'syslog' => Logger\SyslogLogger::class, + 'w3c' => Logger\W3cLogger::class, + ]; + + /** + * Get the logger class for a given key + * + * @param string $key The key to look up + * + * @return string + * + * @since __DEPLOY_VERSION__ + * @throws \InvalidArgumentException + */ + public function getLoggerClass(string $key): string + { + if (!$this->hasLogger($key)) + { + throw new \InvalidArgumentException("The '$key' key is not registered."); + } + + return $this->loggerMap[$key]; + } + + /** + * Check if the registry has a logger for the given key + * + * @param string $key The key to look up + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + public function hasLogger(string $key): bool + { + return isset($this->loggerMap[$key]); + } + + /** + * Register a logger + * + * @param string $key The service key to be registered + * @param string $class The class name of the logger + * @param boolean $replace Flag indicating the service key may replace an existing definition + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(string $key, string $class, bool $replace = false) + { + // If the key exists already and we aren't instructed to replace existing services, bail early + if (isset($this->loggerMap[$key]) && !$replace) + { + throw new \RuntimeException("The '$key' key is already registered."); + } + + // The class must exist + if (!class_exists($class)) + { + throw new \RuntimeException("The '$class' class for key '$key' does not exist."); + } + + $this->loggerMap[$key] = $class; + } +}