Skip to content

Commit

Permalink
CIVIPLUS-487: Add community/feature-request#12 - Allow named logging …
Browse files Browse the repository at this point in the history
…channels commit

Include in CiviCRM 5.38

PR: civicrm#20079

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.
  • Loading branch information
totten authored and erawat committed Sep 10, 2021
1 parent b147ed2 commit 3c757cc
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
12 changes: 9 additions & 3 deletions Civi.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,16 @@ public static function lockManager() {
}

/**
* @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);
}

/**
Expand Down
3 changes: 3 additions & 0 deletions Civi/Core/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ public function createContainer() {
->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',
Expand Down
46 changes: 46 additions & 0 deletions Civi/Core/LogManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
/*
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC. All rights reserved. |
| |
| This work is published under the GNU AGPLv3 license with some |
| permitted exceptions and without any warranty. For full license |
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/

namespace Civi\Core;

/**
* The LogManager will provide instances of "LoggerInterface".
*
* @package Civi\Core
*/
class LogManager {

const DEFAULT_LOGGER = 'psr_log';

private $channels = [];

/**
* Find or create a logger.
*
* This implementation will look for a service "log.{NAME}". If none is defined,
* then it will fallback to the "psr_log" service.
*
* @param string $channel
* Symbolic name of the intended log.
* This should correlate to a service "log.{NAME}".
*
* @return \Psr\Log\LoggerInterface
*/
public function getLog($channel = 'default') {
if (!isset($this->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];
}

}

0 comments on commit 3c757cc

Please sign in to comment.