Jump to content

Manual:MonologSpi.php

From mediawiki.org

MediaWiki\Logger\MonologSpi is a service provider interface for use with $wgMWLoggerDefaultSpi that creates Monolog loggers. MonologSpi enables Structured logging, which means you can record an arbitrary array of data with your log events instead of just a string.

Details

[edit]

Monolog allows a large amount of flexibility in configuring the destination, format and contents of log events. The basic building blocks of a Monolog configuration are:

$wgMWLoggerDefaultSpi = [
	'class' => \MediaWiki\Logger\MonologSpi::class,
	'args' => [ [
		'loggers' => [
			'@default' => [ /* Template for any log channel without explicit config */ ],
			'some-special-log-channel' => [ /*...*/ ],
		],
		'processors' => [ /*...*/ ],
		'handlers' => [ /*...*/ ],
		'formatters' => [ /*...*/ ],
	] ],
];
Loggers
A logger is a named logging channel. The name of the channel is used to determine what configuration to apply to messages sent to that channel.
Since MediaWiki 1.33, if no logger @default is defined, it is defined with the handler @default; if there is no handler @default it is defined as a stream handler to php://stderr with minimum level ERROR (T196906).
Since MediaWiki 1.35.1, a logger configured as [] or false is silenced (T196906).
Processors
A processor adds or modifies contextual information of a log event.
  • Including the Monolog\Processor\PsrLogMessageProcessor handler is recommended to make Monolog expand PSR-3 {name} placeholders in the message body.
  • The MediaWiki provided MediaWiki\Logger\Monolog\WikiProcessor processor will add 'host' => wfHostname(), 'wiki' => wfWikiID(), 'mwversion' => $wgVersion, 'reqId' => \WebRequest::getRequestId() and if running from CLI 'cli_argv' => implode( ' ', $_SERVER['argv'] ) to the log event.
Handlers
Each logger should have one or more handlers attached to it.
  • Monolog\Handler\StreamHandler writes log events to a file or PHP stream.
  • MediaWiki's MediaWiki\Logger\Monolog\LegacyHandler can take the same file or UDP endpoint syntax as used by $wgDebugLogGroups.
Formatters
The formatters normalize and format incoming records for the handlers. If not specified in the config, a default formatter will be selected by the handler.
  • MediaWiki\Logger\Monolog\LegacyFormatter mimics the legacy log message formatting of wfDebug, wfDebugLog, wfLogDBError and wfErrorLog global functions by delegating the formatting to MediaWiki\Logger\LegacyLogger.

Usage

[edit]

Minimal example

[edit]

This configuration logs everything to a single file, /var/log/mediawiki/log. The file should be writable by MediaWiki (e. g. sudo mkdir -p /var/log/mediawiki && sudo chown www-data /var/log/mediawiki). Each log entry corresponds to a single line, and the structured data is appended to the message.

$wgMWLoggerDefaultSpi = [
    'class' => '\\MediaWiki\\Logger\\MonologSpi',
    'args' => [ [
        'loggers' => [
            '@default' => [
                'processors' => [ 'wiki', 'psr' ],
                'handlers' => [ 'stream' ]
            ],
        ],
        'processors' => [
            'wiki' => [ 'class' => '\\MediaWiki\\Logger\\Monolog\\WikiProcessor' ],
            'psr' => [ 'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor' ],
        ],
        'handlers' => [
            'stream' => [
                'class' => '\\Monolog\\Handler\\StreamHandler',
                'args' => [ '/var/log/mediawiki/log' ],
                'formatter' => 'line'
            ],
        ],
        'formatters' => [
            'line' => [ 'class' => '\\Monolog\\Formatter\\LineFormatter' ],
        ]
    ] ]
];

Example from the MediaWiki\Logger\MonologSpi PHP doc comments

[edit]
$wgMWLoggerDefaultSpi = array(
    'class' => '\\MediaWiki\\Logger\\MonologSpi',
    'args' => array( array(
        'loggers' => array(
           '@default' => array(
               'processors' => array( 'wiki', 'psr', 'pid', 'uid', 'web' ),
               'handlers'   => array( 'stream' ),
           ),
           'runJobs' => array(
               'processors' => array( 'wiki', 'psr', 'pid' ),
               'handlers'   => array( 'stream' ),
           )
       ),
       'processors' => array(
           'wiki' => array(
               'class' => '\\MediaWiki\\Logger\\Monolog\\WikiProcessor',
           ),
           'psr' => array(
               'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor',
           ),
           'pid' => array(
               'class' => '\\Monolog\\Processor\\ProcessIdProcessor',
           ),
           'uid' => array(
               'class' => '\\Monolog\\Processor\\UidProcessor',
           ),
           'web' => array(
               'class' => '\\Monolog\\Processor\\WebProcessor',
           ),
       ),
       'handlers' => array(
           'stream' => array(
               'class'     => '\\Monolog\\Handler\\StreamHandler',
               'args'      => array( 'path/to/your.log' ),
               'formatter' => 'line',
           ),
       ),
       'formatters' => array(
           'line' => array(
               'class' => '\\Monolog\\Formatter\\LineFormatter',
            ),
       ),
    ) ),
);

Example from MediaWiki-Vagrant's "elk" role

[edit]

You can setup logging to an Elasticsearch, Logstash and Kibana (ELK) log aggregation stack in MediaWiki-Vagrant by enabling the elk role:

vagrant roles enable elk; vagrant provision

This role configures the wiki to log to local files and also to feed Logstash via an intermediate Redis queue.

$wgMWLoggerDefaultSpi = array(
    'class' => '\\MediaWiki\\Logger\\MonologSpi',
    'args' => array( array(
        'loggers' => array(
            '@default' => array(
                'processors' => array( 'wiki', 'psr', 'pid', 'uid', 'web' ),
                'handlers'   => array( 'default', 'redis' ),
            ),
            'wfDebug' => array(
                'handlers'   => array( 'default' ),
                'processors' => array( 'psr' ),
            ),
            'profileoutput' => array(
                'handlers'   => array( 'profiler' ),
                'processors' => array( 'psr' ),
            ),
        ),

        'processors' => array(
            'wiki' => array(
                'class' => '\\MediaWiki\\Logger\\Monolog\\WikiProcessor',
            ),
            'psr' => array(
                'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor',
            ),
            'pid' => array(
                'class' => '\\Monolog\\Processor\\ProcessIdProcessor',
            ),
            'uid' => array(
                'class' => '\\Monolog\\Processor\\UidProcessor',
            ),
            'web' => array(
                'class' => '\\Monolog\\Processor\\WebProcessor',
            ),
        ),

        'handlers' => array(
            'default' => array(
                'class' => '\\MediaWiki\\Logger\\Monolog\\LegacyHandler',
                'args' => array( '/vagrant/logs/monolog-'.date('Ymd').'.log' ),
                'formatter' => 'line',
            ),
            'redis' => array(
                'class' => '\\Monolog\\Handler\\RedisHandler',
                'args' => array(
                    function() {
                        $redis = new Redis();
                        $redis->connect( '127.0.0.1', 6379 );
                        return $redis;
                    },
                    'logstash'
                ),
                'formatter' => 'logstash',
            ),
            'profiler' => array(
                'class' => '\\MediaWiki\\Logger\\Monolog\\LegacyHandler',
                'args' => array( '/vagrant/logs/profiler-'.date('Ymd').'.log' ),
                'formatter' => 'profiler',
            ),
        ),

        'formatters' => array(
            'line' => array(
                'class' => '\\Monolog\\Formatter\\LineFormatter',
            ),
            'logstash' => array(
                'class' => '\\Monolog\\Formatter\\LogstashFormatter',
                'args'  => array( 'mediawiki', php_uname( 'n' ), null, '', 1 ),
            ),
            'profiler' => array(
                'class' => '\\Monolog\\Formatter\\LineFormatter',
                'args' => array( "%datetime% %message%\n\n", null, true, true ),
            ),
        ),
    ) ),
);