3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
21 namespace MediaWiki\Logger
;
27 * LoggerFactory service provider that creates loggers implemented by
30 * Configured using an array of configuration data with the keys 'loggers',
31 * 'processors', 'handlers' and 'formatters'.
33 * The ['loggers']['@default'] configuration will be used to create loggers
34 * for any channel that isn't explicitly named in the 'loggers' configuration
37 * Configuration will most typically be provided in the $wgMWLoggerDefaultSpi
38 * global configuration variable used by LoggerFactory to construct its
39 * default SPI provider:
41 * $wgMWLoggerDefaultSpi = array(
42 * 'class' => '\\MediaWiki\\Logger\\MonologSpi',
43 * 'args' => array( array(
45 * '@default' => array(
46 * 'processors' => array( 'wiki', 'psr', 'pid', 'uid', 'web' ),
47 * 'handlers' => array( 'stream' ),
50 * 'processors' => array( 'wiki', 'psr', 'pid' ),
51 * 'handlers' => array( 'stream' ),
54 * 'processors' => array(
56 * 'class' => '\\MediaWiki\\Logger\\Monolog\\WikiProcessor',
59 * 'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor',
62 * 'class' => '\\Monolog\\Processor\\ProcessIdProcessor',
65 * 'class' => '\\Monolog\\Processor\\UidProcessor',
68 * 'class' => '\\Monolog\\Processor\\WebProcessor',
71 * 'handlers' => array(
73 * 'class' => '\\Monolog\\Handler\\StreamHandler',
74 * 'args' => array( 'path/to/your.log' ),
75 * 'formatter' => 'line',
78 * 'class' => '\\Monolog\\Handler\\RedisHandler',
79 * 'args' => array( function() {
80 * $redis = new Redis();
81 * $redis->connect( '127.0.0.1', 6379 );
86 * 'formatter' => 'logstash',
89 * 'class' => '\\MediaWiki\\Logger\\Monolog\\LegacyHandler',
91 * 'udp://127.0.0.1:8420/mediawiki
93 * 'formatter' => 'line',
96 * 'formatters' => array(
98 * 'class' => '\\Monolog\\Formatter\\LineFormatter',
100 * 'logstash' => array(
101 * 'class' => '\\Monolog\\Formatter\\LogstashFormatter',
102 * 'args' => array( 'mediawiki', php_uname( 'n' ), null, '', 1 ),
109 * @see https://github.com/Seldaek/monolog
111 * @author Bryan Davis <bd808@wikimedia.org>
112 * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
114 class MonologSpi
implements Spi
{
117 * @var array $singletons
119 protected $singletons;
122 * Configuration for creating new loggers.
129 * @param array $config Configuration data.
131 public function __construct( array $config ) {
132 $this->config
= $config;
138 * Reset internal caches.
140 * This is public for use in unit tests. Under normal operation there should
141 * be no need to flush the caches.
143 public function reset() {
144 $this->singletons
= array(
145 'loggers' => array(),
146 'handlers' => array(),
147 'formatters' => array(),
148 'processors' => array(),
154 * Get a logger instance.
156 * Creates and caches a logger instance based on configuration found in the
157 * $wgMWLoggerMonologSpiConfig global. Subsequent request for the same channel
158 * name will return the cached instance.
160 * @param string $channel Logging channel
161 * @return \Psr\Log\LoggerInterface Logger instance
163 public function getLogger( $channel ) {
164 if ( !isset( $this->singletons
['loggers'][$channel] ) ) {
165 // Fallback to using the '@default' configuration if an explict
166 // configuration for the requested channel isn't found.
167 $spec = isset( $this->config
['loggers'][$channel] ) ?
168 $this->config
['loggers'][$channel] :
169 $this->config
['loggers']['@default'];
171 $monolog = $this->createLogger( $channel, $spec );
172 $this->singletons
['loggers'][$channel] = $monolog;
175 return $this->singletons
['loggers'][$channel];
181 * @param string $channel Logger channel
182 * @param array $spec Configuration
183 * @return \Monolog\Logger
185 protected function createLogger( $channel, $spec ) {
186 $obj = new Logger( $channel );
188 if ( isset( $spec['processors'] ) ) {
189 foreach ( $spec['processors'] as $processor ) {
190 $obj->pushProcessor( $this->getProcessor( $processor ) );
194 if ( isset( $spec['handlers'] ) ) {
195 foreach ( $spec['handlers'] as $handler ) {
196 $obj->pushHandler( $this->getHandler( $handler ) );
204 * Create or return cached processor.
205 * @param string $name Processor name
208 public function getProcessor( $name ) {
209 if ( !isset( $this->singletons
['processors'][$name] ) ) {
210 $spec = $this->config
['processors'][$name];
211 $processor = ObjectFactory
::getObjectFromSpec( $spec );
212 $this->singletons
['processors'][$name] = $processor;
214 return $this->singletons
['processors'][$name];
219 * Create or return cached handler.
220 * @param string $name Processor name
221 * @return \Monolog\Handler\HandlerInterface
223 public function getHandler( $name ) {
224 if ( !isset( $this->singletons
['handlers'][$name] ) ) {
225 $spec = $this->config
['handlers'][$name];
226 $handler = ObjectFactory
::getObjectFromSpec( $spec );
227 if ( isset( $spec['formatter'] ) ) {
228 $handler->setFormatter(
229 $this->getFormatter( $spec['formatter'] )
232 $this->singletons
['handlers'][$name] = $handler;
234 return $this->singletons
['handlers'][$name];
239 * Create or return cached formatter.
240 * @param string $name Formatter name
241 * @return \Monolog\Formatter\FormatterInterface
243 public function getFormatter( $name ) {
244 if ( !isset( $this->singletons
['formatters'][$name] ) ) {
245 $spec = $this->config
['formatters'][$name];
246 $formatter = ObjectFactory
::getObjectFromSpec( $spec );
247 $this->singletons
['formatters'][$name] = $formatter;
249 return $this->singletons
['formatters'][$name];