Jump to content

Requests for comment/Structured logging: Difference between revisions

From mediawiki.org
Content deleted Content added
Added links to RFC review discussions
m Reverted edits by Lacey doty (talk) to last version by Clump
Tags: Rollback Mobile edit Mobile web edit Advanced mobile edit
 
(21 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{RFC
{{RFC
| created = 2013-12-03
| created = 2013-12-03
| authors = [[User:BDavis_(WMF)|Bryan Davis]], [[User:Ori.livneh|Ori Livneh]], [[User:Aaron_Schulz|Aaron Schulz]]
| authors = [[User:BDavis (WMF)|Bryan Davis]], [[User:Ori.livneh|Ori Livneh]], [[User:Aaron Schulz|Aaron Schulz]]
| draft = complete
| status = implemented
| extrastatus = This RfC was never formally approved, but the [[#Implementation|gerrit changes to implement PSR-3 support]] have been merged --[[User:BDavis (WMF)|BDavis (WMF)]] ([[User talk:BDavis (WMF)|talk]]) 15:44, 10 April 2015 (UTC)
| implementation = https://gerrit.wikimedia.org/r/#/c/112699/
}}
}}


Line 129: Line 129:


=== API ===
=== API ===
The developer facing API is the [https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md PSR-3 logging interface standard] with the possibility for MediaWIki specific extensions.
The developer facing API is the [https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md PSR-3 logging interface standard].


<source lang="php">
<syntaxhighlight lang="php">
<?php
class MWLogger implements \Psr\Log\LoggerInterface {


namespace Psr\Log;
/**
* Logs with an arbitrary level.
*
* @param string|int $level
* @param string $message
* @param array $context
*/
public function log( $level, $message, array $context = array() );


/**
* Describes a logger instance
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface LoggerInterface
{
/**
/**
* System is unusable.
* System is unusable.
Line 148: Line 158:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function emergency( $message, array $context = array() );
public function emergency($message, array $context = array());


/**
/**
Line 159: Line 170:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function alert( $message, array $context = array() );
public function alert($message, array $context = array());


/**
/**
Line 169: Line 181:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function critical( $message, array $context = array( ) );
public function critical($message, array $context = array());


/**
/**
Line 178: Line 191:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function error( $message, array $context = array( ) );
public function error($message, array $context = array());


/**
/**
Line 189: Line 203:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function warning( $message, array $context = array() );
public function warning($message, array $context = array());


/**
/**
Line 197: Line 212:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function notice( $message, array $context = array() );
public function notice($message, array $context = array());


/**
/**
Line 207: Line 223:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function info( $message, array $context = array() );
public function info($message, array $context = array());


/**
/**
Line 215: Line 232:
* @param string $message
* @param string $message
* @param array $context
* @param array $context
* @return null
*/
*/
public function debug( $message, array $context = array() );
public function debug($message, array $context = array());


/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
*/
public function log($level, $message, array $context = array());
}
}
</syntaxhighlight>
</source>


'''MediaWiki\Logger\LoggerFactory''' provides static methods for registering PSR-3 providers and getting PSR-3 Logger instances from the current provider:
MWLogger also provides two static methods:


<source lang="php">
<syntaxhighlight lang="php">
/**
/**
* Get a named logger instance from the currently configured logger factory.
* Get a named logger instance from the currently configured logger factory.
*
*
* @param string $channel Logger channel (name)
* @param string $channel Logger channel (name)
* @return MWLogger
* @return Psr\Log\LoggerInterface
*/
*/
public static function getInstance( $channel );
public static function getInstance( $channel );


/**
/**
* Register a service provider to create new MWLogger instances.
* Register a service provider to create new \Psr\Log\LoggerInterface
* instances.
*
*
* @param MWLoggerSpi $provider Provider to register
* @param \MediaWiki\Logger\Spi $provider Provider to register
*/
*/
public static function registerProvider( MWLoggerSpi $provider );
public static function registerProvider( Spi $provider );
</syntaxhighlight>
</source>


The <code>MWLogger::getInstance()</code> method is the means by which most code would acquire an MWLogger instance. It will in turn delegate the creation of MWLoggers to a class implementing the <code>MWLoggerSpi<code> interface:
The <code>MediaWiki\Logger\LoggerFactory::getInstance()</code> method is the means by which most code would acquire an Psr\Log\LoggerInterface instance. It will in turn delegate the creation of Psr\Log\LoggerInterface to a class implementing the <code>MediaWiki\Logger\Spi</code> interface:


<source lang="php">
<syntaxhighlight lang="php">
namespace MediaWiki\Logger;
interface MWLoggerSpi {
interface Spi {


/**
/**
Line 249: Line 278:
*
*
* @param string $channel Logging channel
* @param string $channel Logging channel
* @return MWLogger Logger instance
* @return Psr\Log\LoggerInterface Logger instance
*/
*/
public function getLogger( $channel );
public function getLogger( $channel );


}
}
</syntaxhighlight>
</source>


This service provider interface will allow the backend logging library to implemented in multiple ways. The <code>$wgMWLoggerDefaultSpi</code> global provides the class name of the default <code>MWLoggerSpi</code> implementation. This can be altered via the normal means. Alternately <code>MWLogger::registerProvider()</code> can be invoked early in the application setup to inject an alternate SPI implementation.
This service provider interface will allow the backend logging library to implemented in multiple ways. The <code>$wgMWLoggerDefaultSpi</code> global provides the class name of the default <code>MediaWiki\Logger\Spi</code> implementation. This can be altered via the normal means. Alternately <code>MediaWiki\Logger\LoggerFactory::registerProvider()</code> can be invoked early in the application setup to inject an alternate SPI implementation.

See {{gerrit|112699}} for a full proof of concept implementation including a <code>MWLoggerMonologSpi</code> class that creates <code>MWLogger</code> instances backed by the [https://github.com/Seldaek/monolog monolog] logging library. Additional SPI implementations may follow if desired by the community.

The proof of concept code also demonstrates the use of a <code>$wgUseMWLoggerForLegacyFunctions</code> feature flag that configures the legacy global logging methods to emit logging events via <code>MWLogger</code>.


=== Managing third-party libraries ===
=== Managing third-party libraries ===
The use of [https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md PSR-3] and [https://github.com/Seldaek/monolog monolog] introduces the need to manage third-party code dependencies for MediaWiki core. Although there are some third-party components in includes/libs, to my knowledge this is the first large scale use of external PHP code by MediaWiki core.
The use of [http://www.php-fig.org/psr/psr-3 PSR-3] and [https://github.com/Seldaek/monolog monolog] introduces the need to manage third-party code dependencies for MediaWiki core. Although there are some third-party components in includes/libs, to my knowledge this is the first large scale use of external PHP code by MediaWiki core.


In a more perfect world, MediaWiki would already be a system that assembled a collection of libraries using a well defined dependency management system. This has actually been envisioned in at least two RFCs ([[../MediaWiki libraries/]] and [[../Third-party components/]]).
In a more perfect world, MediaWiki would already be a system that assembled a collection of libraries using a well defined dependency management system. This has actually been envisioned in at least two RFCs ([[../MediaWiki libraries/]] and [[../Third-party components/]]).


Several possible solutions were examined and ultimately the use of [https://getcomposer.org/ Composer] as a dependency management system was chosen. The use of [http://www.php-fig.org/psr/psr-3 PSR-3] is mandatory so this library was added to the "require" section of <code>composer.json</code> in the mediawiki/core.git repository. The use of [https://github.com/Seldaek/monolog monolog] is optional, so it was added to the "suggest" section. Since this <code>composer.json</code> file is in the root of the MediaWiki core project, it does to some extent conflict with the [[../Extension management with Composer/]] RFC. Additional work is being done to mitigate this problem for users who were already making use of <code>composer.json</code> ([[phab:T67188]]).
The proof of concept implementation hews close to the approach proposed in [[../MediaWiki_libraries/]] with the addition of [https://getcomposer.org/ Composer] as a dependency management system.

A new <code>libs</code> directory is used to isolate the Composer managed code from the rest of MediaWiki core. Within the <code>libs</code> directory a <code>composer.json</code> file defines the exact versions of external code to import:
<source lang="javascript">
{
"name": "wikimedia/mediawiki-core"
,"require": {
"php": ">=5.3.2"
,"psr/log": "1.0.0"
,"monolog/monolog": "1.7.0"
}
,"preferred-install": "dist"
,"prefer-stable": true
,"config": {
"vendor-dir": "."
}
}
</source>


The [[../Composer managed libraries for use on WMF cluster/]] RFC was written and subsequently approved to deal with the process of staging and deploying Composer managed content in the WMF production environment. Installations of MediaWiki via git clones are expected to manage libraries themselves by using the <code>mediawiki/vendor.git</code> repo, using Composer directly, or creating a <code>mediawiki/vendor.git</code> work-alike for their particular deployment. Releases will be expected to include the required libraries in the official tarball.
The <code>vendor-dir</code> is set to <code>"."</code>, meaning the directory that contains the <code>composer.json</code> file. <code>composer install</code> is run once to import the initial libraries, generate a <code>composer.lock</code> file recording the origin of those dependencies and create the <code>autoload.php</code> file that will be used to import the libraries. This entire collection of files is then committed as a patch to gerrit to become an integral part of the MediaWiki core repository along with a change to the <code>includes/AutoLoader.php</code> script to require the lib/autoload.php class autoloader script generated by Composer.


== Implementation ==
When new versions of the currently imported libraries are desired or additional libraries are needed for additional MediaWiki core components, Composer can be used to safely manage the change.
An original proof of concept implementation was submitted as {{gerrit|112699}}. The approach of using Composer to manage external dependencies was given a '''+1''' by Tim. The monolithic patch was then split into four smaller patches for closer review and approval:
# Edit composer.json to add/update library dependencies.
# Run <code>composer update</code> inside the <code>libs</code> directory.
# (Optionally) Remove tests, documentation, non-PHP 5.3 compatible files.
# Add and commit changes as a gerrit patch.
# Review and merge.


; {{gerrit|119939}} Add Composer managed libraries {{done}}
Since this <code>composer.json</code> file is not in the root of the MediaWiki core project, it should not conflict with the [[../Extension management with Composer/]] RFC.
: Require Psr\Log and suggest Monolog libraries to MW-Core via <code>composer.json</code>.
; {{gerrit|119940}} Add a PSR-3 based logging interface {{done}}
: The MWLogger class is actually a thin wrapper around any PSR-3 LoggerInterface implementation. Named MWLogger instances can be obtained from the MWLogger::getInstance() static method. MWLogger expects a class implementing the MWLoggerSpi interface to act as a factory for new MWLogger instances. A concrete MWLoggerSpi implementation using the Monolog library is also provided.
; {{gerrit|119941}} Enable MWLogger logging for legacy logging methods {{done}}
: Introduces the <code>MWLoggerLegacyLogger</code> logger to mimic legacy logging behavior as a PSR-3 compliant logger component and sets it as the default <code>$wgMWLoggerDefaultSpi</code> implementation. wfDebug, wfDebugLog and wfLogDBError are changed to use <code>MWLogger</code>.
; {{gerrit|119942}} Enable MWLogger logging for wfLogProfilingData {{done}}
: Output structured profiling report data from wfLogProfilingData.
; {{gerrit|184830}} Replace MWLogger with MWLoggerFactory
: Design change to replace MWLogger with direct use of PSR-3 interfaces in MediaWiki. {{done}}
; {{gerrit|198674}} Move MWLogger classes to MediaWiki\Logger namespace
: Move the MWLogger PSR-3 logging related classes into the MediaWiki\Logger namespace. Create shim classes to ease migration of existing MWLoggerFactory usage to the namespaced classes. {{done}}


== See Also ==
== See Also ==
Line 305: Line 320:
:* [[../Third-party components/]]
:* [[../Third-party components/]]
:*[[../MediaWiki libraries/]]
:*[[../MediaWiki libraries/]]
:*[[../Composer managed libraries for use on WMF cluster/]]


; RFC Review
; RFC Review

Latest revision as of 06:12, 10 October 2020

Request for comment (RFC)
Structured logging
Component General
Creation date
Author(s) Bryan Davis, Ori Livneh, Aaron Schulz
Document status implemented
This RfC was never formally approved, but the gerrit changes to implement PSR-3 support have been merged --BDavis (WMF) (talk) 15:44, 10 April 2015 (UTC)reply

This is a request for comment about adding Structured logging to MediaWiki. It specifies a data model for MediaWiki log messages and an interface for generating log messages that conform to the model.

By "data model" we simply mean an agreed-upon set of fields containing metadata that describes the context in which the log message was generated. The model specifies the name of each field and the value it can hold. Log messages generated via the interface that we propose below would conform to this model, allowing them to be serialized to a machine-readable format.A standard for machine-readable metadata common to all log messages would make it possible to query, collate, and summarize operational data in ways that are currently very difficult to achieve.

We think that the ability to cross-reference logs and query by context will make troubleshooting bugs easier. We also think that ongoing analysis of aggregated log data would reveal which files, interfaces, and code paths are especially prone to bugs or poor performance, and that this information would help us make MediaWiki more reliable and performant.

Problems with the current interface

[edit | edit source]

Most operational logging in MediaWiki is done via wfDebugLog calls. Messages logged via wfDebugLog specify a topic name (or a log bucket). This name usually identifies the name of the component that is emitting the log message. Some parts of the code which generate different kinds of log messages have compound topic names that describe the type of log message being logged, usually in terms of severity ("memcached-serious", for example). The ad hoc overloading of the log group property to encode severity is a good example of existing usage that is twisting the interface to overcome its limitations. This is a good indication that the current interface is inadequate.

Because there is no established standard for encoding severity, the density of logging calls in MediaWiki code varies greatly. Access to the production logs is limited, and many developers will only ever review logs generated on their development instance and consequently fail to appreciate the cost of excessively verbose logging at scale. The instrumentation of code is often pitched to its initial development rather than its ongoing maintenance.

To keep chatty code from drowning out important log data, the logging setup on the Wikimedia production cluster does not automatically transmit all logging topics to the log processor. A developer must first manually enroll the log bucket by adding it to the $wgDebugLogGroups configuration var. The problem with this approach is that the absence of log data from a particular component is typically noticed when it is needed the most: that is, when the component is suspected of misbehaving in ways that are difficult to reproduce or reason about. Thus log buckets are usually enabled to help solve a particular bug, and they are commonly left enabled long after the motivation for enabling them has ceased to be relevant. The overall effect is that Wikimedia's logs are curated on the basis of historic interest rather than abiding relevance.

Design principles

[edit | edit source]

Filtering logs by severity and grouping logs by attributes only works if log messages are uniform in structure and content.

What we would need:

  • tools for wider audience
  • aggregation
  • de-duplication
  • cross system correlation
  • alerting
  • reporting

This is not a wholly new idea. Let's look at what's out there and see if we can find a solution or at least borrow the best bits.

Current logging

[edit | edit source]
wfDebug( $text, $logonly = false )
Logs developer provided free-form text + optional global prefix string
Possibly has time-elapsed since start of request and real memory usage inserted between prefix and message
Delegates to wfErrorLog()
wfDebugMem( $exact = false )
Uses wfDebug() to log "Memory usage: N (kilo)?bytes"
wfDebugLog( $logGroup, $text, $public = true)
Logs either to a custom log sink defined in $wgDebugLogGroups or via wfDebug()
Default
Prepends "[$logGroup] " to message
Custom sink
May log only a fraction of occurrences via mt_rand() sampling
Prepends wfTimestamp( TS_DB ) wfWikiID() wfHostname(): to message
Delegates to wfErrorLog() to actually write to sink
wfLogDBError( $text )
Enabled/disabled with $wgDBerrorLog sink location
Logs "$date\t$host\t$wiki\$text" via wfErrorLog() to $wgDBerrorLog sink
Date format is 'D M j G:i:s T Y' with possible custom timezone specified by $wgDBerrorLogTZ
wfErrorLog( $text, $file )
Writes $text to either a local file or a UDP packet depending on the value of $file
UDP
If $file ends with a string following the host name/IP it will be used as a prefix to $text
The final message with optional prefix added will be trimmed to 65507 bytes and a trailing newline may be added
FILE
$text will be appended to file unless the resulting file size would be >= 0x7fffffff bytes (~2G)
wfLogProfilingData()
Delegates to wfErrorLog() using $wgDebugLogFile sink
Creates a tab delimited log message including timestamp, elapsed request time, requesting IPs, and request URL followed by a newline and the profiler output.
Date is from gmdate( 'YmdHis' )
Recent changes logging
Transport and serialization format may be specified via $wgRCFeeds
Various implementations in includes/rcfeeds/, including IRC, UDP & Redis.

Proposal

[edit | edit source]

Serialization Format

[edit | edit source]

Rather than dive down a rabbit hole of trying to find a universal spec for log file formats let's just keep things simple. PHP loves dictionaries (well they call them arrays but whatever; key=value collections) and has a pretty fast json formatter. So the simplest thing that will work reasonably well would be to keep log events internally as PHP arrays and serialize them as json objects. This will be relatively easy to recreate on other internally developed applications as well with the possible exception of apps written in low level languages such as C that don't have ready made key=value data structures.

Data collected

[edit | edit source]

Here's a list of the data points that we should definitely have:

timestamp
Local system time that event occurred either as UNIX epoch timestamp or ISO 8601 formatted string
date( 'c' )
host
FQDN of system where event occurred
php_uname( 'n' )
source
Name of application generating events; correlates to APP-NAME of RFC 5424
'Mediawiki'
pid
Unix process id, thread id, thread name or other process identifier
getmypid()
severity
Message severity (RFC 5424 levels)
'WARN'
channel
Log channel. Often the function/module/class creating message (similar to wgDebugLogGroups groups)
get_class( $this )
message
Message body
"Help! I'm trapped in a logger factory!"

Additionally we suggest adding a semi-structured "context" component to logs. This would be a collection of key=value pairs that the developers determine to be useful for debugging. There should be two different methods available to add such data. The first is as an optional argument to the logging method itself and the second is a global collection patterned after the Log4J Mapped Diagnostic Context (MDC).

The local collection is useful for obvious reasons such as attaching class/method state data to the log output and deferring stringification of resources in the event that runtime configuration is ignoring messages of the provided level.

file
Source file triggering message
line
Source line triggering message
errcode
Numeric or string identifier for the error
exception
Live exception object to be stringified by the log event emitter
args
key=value map of method arguments

The global collection is very useful for attaching global application state data to all log messages that may be emitted. Examples of data that could be included:

vhost
Apache vhost processing request
$_SERVER['HTTP_HOST']
ip
Requesting ip address
$_SERVER['REMOTE_ADDR']
user
Authenticated user identity
req
Request ID; UUID or similar token that can be used to correlate all log messages connected to a given request

The developer facing API is the PSR-3 logging interface standard.

<?php

namespace Psr\Log;

/**
 * Describes a logger instance
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data, the only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function emergency($message, array $context = array());

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function alert($message, array $context = array());

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function critical($message, array $context = array());

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function error($message, array $context = array());

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function warning($message, array $context = array());

    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function notice($message, array $context = array());

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function info($message, array $context = array());

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function debug($message, array $context = array());

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param string $message
     * @param array $context
     * @return null
     */
    public function log($level, $message, array $context = array());
}

MediaWiki\Logger\LoggerFactory provides static methods for registering PSR-3 providers and getting PSR-3 Logger instances from the current provider:

    /**
     * Get a named logger instance from the currently configured logger factory.
     *
     * @param string $channel Logger channel (name)
     * @return Psr\Log\LoggerInterface
     */
    public static function getInstance( $channel );

    /**
     * Register a service provider to create new \Psr\Log\LoggerInterface
     * instances.
     *
     * @param \MediaWiki\Logger\Spi $provider Provider to register
     */
    public static function registerProvider( Spi $provider );

The MediaWiki\Logger\LoggerFactory::getInstance() method is the means by which most code would acquire an Psr\Log\LoggerInterface instance. It will in turn delegate the creation of Psr\Log\LoggerInterface to a class implementing the MediaWiki\Logger\Spi interface:

namespace MediaWiki\Logger;
interface Spi {

    /**
     * Get a logger instance.
     *
     * @param string $channel Logging channel
     * @return Psr\Log\LoggerInterface Logger instance
     */
    public function getLogger( $channel );

}

This service provider interface will allow the backend logging library to implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the class name of the default MediaWiki\Logger\Spi implementation. This can be altered via the normal means. Alternately MediaWiki\Logger\LoggerFactory::registerProvider() can be invoked early in the application setup to inject an alternate SPI implementation.

Managing third-party libraries

[edit | edit source]

The use of PSR-3 and monolog introduces the need to manage third-party code dependencies for MediaWiki core. Although there are some third-party components in includes/libs, to my knowledge this is the first large scale use of external PHP code by MediaWiki core.

In a more perfect world, MediaWiki would already be a system that assembled a collection of libraries using a well defined dependency management system. This has actually been envisioned in at least two RFCs (MediaWiki libraries and Third-party components).

Several possible solutions were examined and ultimately the use of Composer as a dependency management system was chosen. The use of PSR-3 is mandatory so this library was added to the "require" section of composer.json in the mediawiki/core.git repository. The use of monolog is optional, so it was added to the "suggest" section. Since this composer.json file is in the root of the MediaWiki core project, it does to some extent conflict with the Extension management with Composer RFC. Additional work is being done to mitigate this problem for users who were already making use of composer.json (phab:T67188).

The Composer managed libraries for use on WMF cluster RFC was written and subsequently approved to deal with the process of staging and deploying Composer managed content in the WMF production environment. Installations of MediaWiki via git clones are expected to manage libraries themselves by using the mediawiki/vendor.git repo, using Composer directly, or creating a mediawiki/vendor.git work-alike for their particular deployment. Releases will be expected to include the required libraries in the official tarball.

Implementation

[edit | edit source]

An original proof of concept implementation was submitted as Gerrit change 112699. The approach of using Composer to manage external dependencies was given a +1 by Tim. The monolithic patch was then split into four smaller patches for closer review and approval:

Gerrit change 119939 Add Composer managed libraries Yes Done
Require Psr\Log and suggest Monolog libraries to MW-Core via composer.json.
Gerrit change 119940 Add a PSR-3 based logging interface Yes Done
The MWLogger class is actually a thin wrapper around any PSR-3 LoggerInterface implementation. Named MWLogger instances can be obtained from the MWLogger::getInstance() static method. MWLogger expects a class implementing the MWLoggerSpi interface to act as a factory for new MWLogger instances. A concrete MWLoggerSpi implementation using the Monolog library is also provided.
Gerrit change 119941 Enable MWLogger logging for legacy logging methods Yes Done
Introduces the MWLoggerLegacyLogger logger to mimic legacy logging behavior as a PSR-3 compliant logger component and sets it as the default $wgMWLoggerDefaultSpi implementation. wfDebug, wfDebugLog and wfLogDBError are changed to use MWLogger.
Gerrit change 119942 Enable MWLogger logging for wfLogProfilingData Yes Done
Output structured profiling report data from wfLogProfilingData.
Gerrit change 184830 Replace MWLogger with MWLoggerFactory
Design change to replace MWLogger with direct use of PSR-3 interfaces in MediaWiki. Yes Done
Gerrit change 198674 Move MWLogger classes to MediaWiki\Logger namespace
Move the MWLogger PSR-3 logging related classes into the MediaWiki\Logger namespace. Create shim classes to ease migration of existing MWLoggerFactory usage to the namespaced classes. Yes Done

See Also

[edit | edit source]
Relevant bugs
  • bug 14601 [Use wfDebugLog instead of wfDebug by default]
  • bug 49757 [Better monitoring and error reporting of Errors and Exceptions]
Related RFCs
RFC Review
Logging standards
Additional commentary on logging