Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
LogCapturingSpi
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 8
110
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLogs
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 clearLogs
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLogger
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 capture
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createLogger
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 getInnerSpi
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setLoggerForTest
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Logger;
4
5use Psr\Log\AbstractLogger;
6use Psr\Log\LoggerInterface;
7
8/**
9 * Wrap another Spi and keep a copy of all log messages.
10 *
11 * This is developed for use by PHPUnit bootstrapping, to collect logs
12 * generated during a given unit test, and print them after a failing test.
13 *
14 * @internal For use in MediaWiki core only
15 * @ingroup Debug
16 */
17class LogCapturingSpi implements Spi {
18    /** @var array<string,LoggerInterface> */
19    private array $singletons;
20    private Spi $inner;
21    /** @var array[] */
22    private array $logs = [];
23
24    public function __construct( Spi $inner ) {
25        $this->inner = $inner;
26    }
27
28    /**
29     * @return array[]
30     */
31    public function getLogs(): array {
32        return $this->logs;
33    }
34
35    public function clearLogs(): void {
36        $this->logs = [];
37    }
38
39    /** @inheritDoc */
40    public function getLogger( $channel ) {
41        if ( !isset( $this->singletons[$channel] ) ) {
42            $this->singletons[$channel] = $this->createLogger( $channel );
43        }
44        return $this->singletons[$channel];
45    }
46
47    public function capture( array $log ): void {
48        $this->logs[] = $log;
49    }
50
51    private function createLogger( string $channel ): LoggerInterface {
52        $inner = $this->inner->getLogger( $channel );
53        return new class( $channel, $inner, $this ) extends AbstractLogger {
54            private string $channel;
55            private LoggerInterface $logger;
56            private LogCapturingSpi $parent;
57
58            public function __construct( string $channel, LoggerInterface $logger, LogCapturingSpi $parent ) {
59                $this->channel = $channel;
60                $this->logger = $logger;
61                $this->parent = $parent;
62            }
63
64            /** @inheritDoc */
65            public function log( $level, $message, array $context = [] ): void {
66                $this->parent->capture( [
67                    'channel' => $this->channel,
68                    'level' => $level,
69                    'message' => $message,
70                    'context' => $context
71                ] );
72                $this->logger->log( $level, $message, $context );
73            }
74        };
75    }
76
77    /**
78     * @internal For use by MediaWikiIntegrationTestCase
79     */
80    public function getInnerSpi(): Spi {
81        return $this->inner;
82    }
83
84    /**
85     * @internal For use by MediaWikiIntegrationTestCase
86     */
87    public function setLoggerForTest( string $channel, ?LoggerInterface $logger = null ): ?LoggerInterface {
88        $ret = $this->singletons[$channel] ?? null;
89        if ( $logger ) {
90            $this->singletons[$channel] = $logger;
91        } else {
92            unset( $this->singletons[$channel] );
93        }
94        return $ret;
95    }
96}