SpecialTrackingCategories: Read from the extension registry
[lhc/web/wiklou.git] / includes / debug / logger / monolog / Spi.php
1 <?php
2 /**
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.
7 *
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.
12 *
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
17 *
18 * @file
19 */
20
21 /**
22 * MWLogger service provider that creates loggers implemented by Monolog.
23 *
24 * Configured using an array of configuration data with the keys 'loggers',
25 * 'processors', 'handlers' and 'formatters'.
26 *
27 * The ['loggers']['@default'] configuration will be used to create loggers
28 * for any channel that isn't explicitly named in the 'loggers' configuration
29 * section.
30 *
31 * Configuration will most typically be provided in the $wgMWLoggerDefaultSpi
32 * global configuration variable used by MWLogger to construct its default SPI
33 * provider:
34 * @code
35 * $wgMWLoggerDefaultSpi = array(
36 * 'class' => 'MWLoggerMonologSpi',
37 * 'args' => array( array(
38 * 'loggers' => array(
39 * '@default' => array(
40 * 'processors' => array( 'wiki', 'psr', 'pid', 'uid', 'web' ),
41 * 'handlers' => array( 'stream' ),
42 * ),
43 * 'runJobs' => array(
44 * 'processors' => array( 'wiki', 'psr', 'pid' ),
45 * 'handlers' => array( 'stream' ),
46 * )
47 * ),
48 * 'processors' => array(
49 * 'wiki' => array(
50 * 'class' => 'MWLoggerMonologProcessor',
51 * ),
52 * 'psr' => array(
53 * 'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor',
54 * ),
55 * 'pid' => array(
56 * 'class' => '\\Monolog\\Processor\\ProcessIdProcessor',
57 * ),
58 * 'uid' => array(
59 * 'class' => '\\Monolog\\Processor\\UidProcessor',
60 * ),
61 * 'web' => array(
62 * 'class' => '\\Monolog\\Processor\\WebProcessor',
63 * ),
64 * ),
65 * 'handlers' => array(
66 * 'stream' => array(
67 * 'class' => '\\Monolog\\Handler\\StreamHandler',
68 * 'args' => array( 'path/to/your.log' ),
69 * 'formatter' => 'line',
70 * ),
71 * 'redis' => array(
72 * 'class' => '\\Monolog\\Handler\\RedisHandler',
73 * 'args' => array( function() {
74 * $redis = new Redis();
75 * $redis->connect( '127.0.0.1', 6379 );
76 * return $redis;
77 * },
78 * 'logstash'
79 * ),
80 * 'formatter' => 'logstash',
81 * ),
82 * 'udp2log' => array(
83 * 'class' => 'MWLoggerMonologHandler',
84 * 'args' => array(
85 * 'udp://127.0.0.1:8420/mediawiki
86 * ),
87 * 'formatter' => 'line',
88 * ),
89 * ),
90 * 'formatters' => array(
91 * 'line' => array(
92 * 'class' => '\\Monolog\\Formatter\\LineFormatter',
93 * ),
94 * 'logstash' => array(
95 * 'class' => '\\Monolog\\Formatter\\LogstashFormatter',
96 * 'args' => array( 'mediawiki', php_uname( 'n' ), null, '', 1 ),
97 * ),
98 * ),
99 * ) ),
100 * );
101 * @endcode
102 *
103 * @see https://github.com/Seldaek/monolog
104 * @since 1.25
105 * @author Bryan Davis <bd808@wikimedia.org>
106 * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
107 */
108 class MWLoggerMonologSpi implements MWLoggerSpi {
109
110 /**
111 * @var array $singletons
112 */
113 protected $singletons;
114
115 /**
116 * Configuration for creating new loggers.
117 * @var array $config
118 */
119 protected $config;
120
121
122 /**
123 * @param array $config Configuration data.
124 */
125 public function __construct( array $config ) {
126 $this->config = $config;
127 $this->reset();
128 }
129
130
131 /**
132 * Reset internal caches.
133 *
134 * This is public for use in unit tests. Under normal operation there should
135 * be no need to flush the caches.
136 */
137 public function reset() {
138 $this->singletons = array(
139 'loggers' => array(),
140 'handlers' => array(),
141 'formatters' => array(),
142 'processors' => array(),
143 );
144 }
145
146
147 /**
148 * Get a logger instance.
149 *
150 * Creates and caches a logger instance based on configuration found in the
151 * $wgMWLoggerMonologSpiConfig global. Subsequent request for the same channel
152 * name will return the cached instance.
153 *
154 * @param string $channel Logging channel
155 * @return MWLogger Logger instance
156 */
157 public function getLogger( $channel ) {
158 if ( !isset( $this->singletons['loggers'][$channel] ) ) {
159 // Fallback to using the '@default' configuration if an explict
160 // configuration for the requested channel isn't found.
161 $spec = isset( $this->config['loggers'][$channel] ) ?
162 $this->config['loggers'][$channel] :
163 $this->config['loggers']['@default'];
164
165 $monolog = $this->createLogger( $channel, $spec );
166 $this->singletons['loggers'][$channel] = new MWLogger( $monolog );
167 }
168
169 return $this->singletons['loggers'][$channel];
170 }
171
172
173 /**
174 * Create a logger.
175 * @param string $channel Logger channel
176 * @param array $spec Configuration
177 * @return \Monolog\Logger
178 */
179 protected function createLogger( $channel, $spec ) {
180 $obj = new \Monolog\Logger( $channel );
181
182 if ( isset( $spec['processors'] ) ) {
183 foreach ( $spec['processors'] as $processor ) {
184 $obj->pushProcessor( $this->getProcessor( $processor ) );
185 }
186 }
187
188 if ( isset( $spec['handlers'] ) ) {
189 foreach ( $spec['handlers'] as $handler ) {
190 $obj->pushHandler( $this->getHandler( $handler ) );
191 }
192 }
193 return $obj;
194 }
195
196
197 /**
198 * Create or return cached processor.
199 * @param string $name Processor name
200 * @return callable
201 */
202 public function getProcessor( $name ) {
203 if ( !isset( $this->singletons['processors'][$name] ) ) {
204 $spec = $this->config['processors'][$name];
205 $processor = ObjectFactory::getObjectFromSpec( $spec );
206 $this->singletons['processors'][$name] = $processor;
207 }
208 return $this->singletons['processors'][$name];
209 }
210
211
212 /**
213 * Create or return cached handler.
214 * @param string $name Processor name
215 * @return \Monolog\Handler\HandlerInterface
216 */
217 public function getHandler( $name ) {
218 if ( !isset( $this->singletons['handlers'][$name] ) ) {
219 $spec = $this->config['handlers'][$name];
220 $handler = ObjectFactory::getObjectFromSpec( $spec );
221 if ( isset( $spec['formatter'] ) ) {
222 $handler->setFormatter(
223 $this->getFormatter( $spec['formatter'] )
224 );
225 }
226 $this->singletons['handlers'][$name] = $handler;
227 }
228 return $this->singletons['handlers'][$name];
229 }
230
231
232 /**
233 * Create or return cached formatter.
234 * @param string $name Formatter name
235 * @return \Monolog\Formatter\FormatterInterface
236 */
237 public function getFormatter( $name ) {
238 if ( !isset( $this->singletons['formatters'][$name] ) ) {
239 $spec = $this->config['formatters'][$name];
240 $formatter = ObjectFactory::getObjectFromSpec( $spec );
241 $this->singletons['formatters'][$name] = $formatter;
242 }
243 return $this->singletons['formatters'][$name];
244 }
245 }