From c213eb51ec4b39dfc581c31025318e42cdaccb7a Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 15 Apr 2021 18:49:27 -0700 Subject: [PATCH] community/feature-request#12 - Allow named logging channels Overview ---------------------------------------- Make it easier to route log messages based on their topic (e.g. CiviContribute-related logs vs CiviMail-related logs). Before ------ `Civi::log()` always returns the same instance of `LoggerInterface`, with no clear way to differentiate logs of different business subsystems. After ----- `Civi::log(...)` allows you to optionally request a `LoggerInterface` for a specific theme, e.g. ```php Civi::log('mail')->error('Failed to connect to SMTP server'); Civi::log('ipn')->warning('Transaction rejected by payment processor'); ``` Technical Details ----------------- A few things going on here: * Extensions may start using their own logs (`Civi::log('myext')`) without any special effort. * It is possible to replace or customize specific logs by defining a service `log.CHANNEL_NAME`. * The `psr_log_manager` is a service. An extension like https://lab.civicrm.org/extensions/monolog/ can replace the `psr_log_manager` and use the channel-name in its own way. There is a limitation here in that the list of channels is open-ended. It will be impossible to (eg) detect that a log-user has made a typo in the channel-name. However, this seems like the better trade-off if the alternative is that extensions face races during installation/uninstallation. --- Civi.php | 12 ++++++++--- Civi/Core/Container.php | 3 +++ Civi/Core/LogManager.php | 46 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 Civi/Core/LogManager.php diff --git a/Civi.php b/Civi.php index f916756883..a018bb54d9 100644 --- a/Civi.php +++ b/Civi.php @@ -82,10 +82,16 @@ class Civi { } /** - * @return \CRM_Core_Error_Log + * Find or create a logger. + * + * @param string $channel + * Symbolic name (or channel) of the intended log. + * This should correlate to a service "log.{NAME}". + * + * @return \Psr\Log\LoggerInterface */ - public static function log() { - return Civi\Core\Container::singleton()->get('psr_log'); + public static function log($channel = 'default') { + return \Civi\Core\Container::singleton()->get('psr_log_manager')->getLog($channel); } /** diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index 39749a81bb..c4f8ca72ab 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -150,6 +150,9 @@ class Container { ->setFactory('CRM_Cxn_BAO_Cxn::createRegistrationClient')->setPublic(TRUE); $container->setDefinition('psr_log', new Definition('CRM_Core_Error_Log', []))->setPublic(TRUE); + $container->setDefinition('psr_log_manager', new Definition('Civi\Core\LogManager', []))->setPublic(TRUE); + // With the default log-manager, you may overload a channel by defining a service, e.g. + // $container->setDefinition('log.ipn', new Definition('CRM_Core_Error_Log', []))->setPublic(TRUE); $basicCaches = [ 'js_strings' => 'js_strings', diff --git a/Civi/Core/LogManager.php b/Civi/Core/LogManager.php new file mode 100644 index 0000000000..2c181a09e0 --- /dev/null +++ b/Civi/Core/LogManager.php @@ -0,0 +1,46 @@ +channels[$channel])) { + $c = \Civi::container(); + $svc = "log." . $channel; + $this->channels[$channel] = $c->has($svc) ? $c->get($svc) : $c->get(self::DEFAULT_LOGGER); + } + return $this->channels[$channel]; + } + +} -- 2.25.1