MediaWiki master
MonologSpi.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Logger;
22
23use DateTimeZone;
25use Monolog\Formatter\FormatterInterface;
26use Monolog\Handler\FormattableHandlerInterface;
27use Monolog\Handler\HandlerInterface;
28use Monolog\Handler\PsrHandler;
29use Monolog\Handler\StreamHandler;
30use Monolog\Logger;
31use Psr\Log\LoggerInterface;
32use Wikimedia\ObjectFactory\ObjectFactory;
33
123class MonologSpi implements Spi {
124
128 protected $singletons;
129
134 protected array $config = [];
135
139 public function __construct( array $config ) {
140 $this->mergeConfig( $config );
141 }
142
149 public function mergeConfig( array $config ) {
150 foreach ( $config as $key => $value ) {
151 if ( isset( $this->config[$key] ) ) {
152 $this->config[$key] = array_merge( $this->config[$key], $value );
153 } else {
154 $this->config[$key] = $value;
155 }
156 }
157 if ( !isset( $this->config['loggers']['@default'] ) ) {
158 $this->config['loggers']['@default'] = [
159 'handlers' => [ '@default' ],
160 ];
161 $this->config['handlers']['@default'] ??= [
162 'class' => StreamHandler::class,
163 'args' => [ 'php://stderr', Logger::ERROR ],
164 ];
165 }
166 $this->reset();
167 }
168
175 public function reset() {
176 $this->singletons = [
177 'loggers' => [],
178 'handlers' => [],
179 'formatters' => [],
180 'processors' => [],
181 ];
182 }
183
194 public function getLogger( $channel ) {
195 if ( !isset( $this->singletons['loggers'][$channel] ) ) {
196 // Fallback to using the '@default' configuration if an explicit
197 // configuration for the requested channel isn't found.
198 $spec = $this->config['loggers'][$channel] ?? $this->config['loggers']['@default'];
199
200 $monolog = $this->createLogger( $channel, $spec );
201 $this->singletons['loggers'][$channel] = $monolog;
202 }
203
204 return $this->singletons['loggers'][$channel];
205 }
206
213 protected function createLogger( $channel, $spec ): LoggerInterface {
215
216 $handlers = [];
217 if ( isset( $spec['handlers'] ) && $spec['handlers'] ) {
218 foreach ( $spec['handlers'] as $handler ) {
219 $handlers[] = $this->getHandler( $handler );
220 }
221 }
222
223 $processors = [];
224 if ( isset( $spec['processors'] ) ) {
225 foreach ( $spec['processors'] as $processor ) {
226 $processors[] = $this->getProcessor( $processor );
227 }
228 }
229
230 // Use UTC for logs instead of Monolog's default, which asks the
231 // PHP runtime, which MediaWiki sets to $wgLocaltimezone (T99581)
232 $obj = new Logger( $channel, $handlers, $processors, new DateTimeZone( 'UTC' ) );
233
234 if ( $wgShowDebug || $wgDebugToolbar ) {
235 $legacyLogger = new LegacyLogger( $channel );
236 $legacyPsrHandler = new PsrHandler( $legacyLogger );
237 $obj->pushHandler( $legacyPsrHandler );
238 }
239
240 if ( isset( $spec['calls'] ) ) {
241 foreach ( $spec['calls'] as $method => $margs ) {
242 $obj->$method( ...$margs );
243 }
244 }
245
246 return $obj;
247 }
248
254 public function getProcessor( $name ) {
255 if ( !isset( $this->singletons['processors'][$name] ) ) {
256 $spec = $this->config['processors'][$name];
258 $processor = ObjectFactory::getObjectFromSpec( $spec );
259 $this->singletons['processors'][$name] = $processor;
260 }
261 return $this->singletons['processors'][$name];
262 }
263
269 public function getHandler( $name ) {
270 if ( !isset( $this->singletons['handlers'][$name] ) ) {
271 $spec = $this->config['handlers'][$name];
273 $handler = ObjectFactory::getObjectFromSpec( $spec );
274 if (
275 isset( $spec['formatter'] ) &&
276 $handler instanceof FormattableHandlerInterface
277 ) {
278 $handler->setFormatter(
279 $this->getFormatter( $spec['formatter'] )
280 );
281 }
282 if ( isset( $spec['buffer'] ) && $spec['buffer'] ) {
283 $handler = new BufferHandler( $handler );
284 }
285 $this->singletons['handlers'][$name] = $handler;
286 }
287 return $this->singletons['handlers'][$name];
288 }
289
295 public function getFormatter( $name ) {
296 if ( !isset( $this->singletons['formatters'][$name] ) ) {
297 $spec = $this->config['formatters'][$name];
299 $formatter = ObjectFactory::getObjectFromSpec( $spec );
300 $this->singletons['formatters'][$name] = $formatter;
301 }
302 return $this->singletons['formatters'][$name];
303 }
304}
LoggerFactory service provider that creates loggers implemented by Monolog.
getHandler( $name)
Create or return cached handler.
getProcessor( $name)
Create or return cached processor.
mergeConfig(array $config)
Merge additional configuration data into the configuration.
reset()
Reset internal caches.
getLogger( $channel)
Get a logger instance.
createLogger( $channel, $spec)
Create a logger.
array array< string, array< string, array > > $config
Configuration for creating new loggers.
getFormatter( $name)
Create or return cached formatter.
Helper class for the index.php entry point.
$wgShowDebug
Config variable stub for the ShowDebug setting, for use by phpdoc and IDEs.
$wgDebugToolbar
Config variable stub for the DebugToolbar setting, for use by phpdoc and IDEs.
Service provider interface to create \Psr\Log\LoggerInterface objects.
Definition Spi.php:64