wiki.techinc.nl/includes/debug/logger/LogCapturingSpi.php
Timo Tijhof e0ed6df864 phpunit: Add setNullLogger() and make tests default to LegacySpi
== Motivation

Mute a log channel, for which the Logger object is injected by
service wiring, for a service that is overridden by default,
such as 'DBLoadBalancerFactory'. For that, calling setLogger()
mid-test would be too late.

== Changes

* Add a test-only method to LegacyLogger that makes it possible
  to change its `minimumLevel` attribute, thus making it turn
  itself into a NullLogger if raised to infinity. This is the
  same principle we use already for disabled log channels when
  using MediaWiki normally (see LegacyLogger::__construct).

* Previously, the developer's LocalSettings.php was loaded
  which includes the Spi configuration. This meant other Spi's
  could be configured which means we might not be dealing with
  a LegacyLogger object.

  Similar to what we do with ObjectCache and JobQueue already,
  make the default Spi in tests the same as the normal MW default.

* Add setNullLogger() which makes use of these two.

Bug: T248195
Change-Id: Ieade3585812de47342259afa765e230fff06f526
2020-04-07 22:00:13 +00:00

103 lines
2.4 KiB
PHP

<?php
namespace MediaWiki\Logger;
use Psr\Log\AbstractLogger;
use Psr\Log\LoggerInterface;
/**
* Wraps another spi to capture all logs generated. This can be
* used, for example, to collect all logs generated during a
* unit test and report them when the test fails.
*/
class LogCapturingSpi implements Spi {
/** @var LoggerInterface[] */
private $singletons;
/** @var Spi */
private $inner;
/** @var array */
private $logs = [];
public function __construct( Spi $inner ) {
$this->inner = $inner;
}
/**
* @return array
*/
public function getLogs() {
return $this->logs;
}
/**
* @param string $channel
* @return LoggerInterface
*/
public function getLogger( $channel ) {
if ( !isset( $this->singletons[$channel] ) ) {
$this->singletons[$channel] = $this->createLogger( $channel );
}
return $this->singletons[$channel];
}
/**
* @param array $log
*/
public function capture( $log ) {
$this->logs[] = $log;
}
/**
* @param string $channel
* @return LoggerInterface
*/
private function createLogger( $channel ) {
$inner = $this->inner->getLogger( $channel );
return new class( $channel, $inner, $this ) extends AbstractLogger {
/** @var string */
private $channel;
/** @var LoggerInterface */
private $logger;
/** @var LogCapturingSpi */
private $parent;
// phpcs:ignore MediaWiki.Usage.NestedFunctions.NestedFunction
public function __construct( $channel, LoggerInterface $logger, LogCapturingSpi $parent ) {
$this->channel = $channel;
$this->logger = $logger;
$this->parent = $parent;
}
// phpcs:ignore MediaWiki.Usage.NestedFunctions.NestedFunction
public function log( $level, $message, array $context = [] ) {
$this->parent->capture( [
'channel' => $this->channel,
'level' => $level,
'message' => $message,
'context' => $context
] );
$this->logger->log( $level, $message, $context );
}
};
}
/**
* @internal For use by MediaWikiIntegrationTestCase
* @return Spi
*/
public function getInnerSpi() : Spi {
return $this->inner;
}
/**
* @internal For use by MediaWikiIntegrationTestCase
* @param string $channel
* @param LoggerInterface|null $logger
* @return LoggerInterface|null
*/
public function setLoggerForTest( $channel, LoggerInterface $logger = null ) {
$ret = $this->singletons[$channel] ?? null;
$this->singletons[$channel] = $logger;
return $ret;
}
}