Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 anikendra 1
<?php
2
/**
3
 * Logging.
4
 *
5
 * Log messages to text files.
6
 *
7
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
9
 *
10
 * Licensed under The MIT License
11
 * For full copyright and license information, please see the LICENSE.txt
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
15
 * @link          http://cakephp.org CakePHP(tm) Project
16
 * @package       Cake.Log
17
 * @since         CakePHP(tm) v 0.2.9
18
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
19
 */
20
 
21
App::uses('LogEngineCollection', 'Log');
22
 
23
/**
24
 * Logs messages to configured Log adapters. One or more adapters
25
 * can be configured using CakeLogs's methods. If you don't
26
 * configure any adapters, and write to the logs a default
27
 * FileLog will be autoconfigured for you.
28
 *
29
 * ### Configuring Log adapters
30
 *
31
 * You can configure log adapters in your applications `bootstrap.php` file.
32
 * A sample configuration would look like:
33
 *
34
 * {{{
35
 * CakeLog::config('my_log', array('engine' => 'File'));
36
 * }}}
37
 *
38
 * See the documentation on CakeLog::config() for more detail.
39
 *
40
 * ### Writing to the log
41
 *
42
 * You write to the logs using CakeLog::write(). See its documentation for more
43
 * information.
44
 *
45
 * ### Logging Levels
46
 *
47
 * By default CakeLog supports all the log levels defined in
48
 * RFC 5424. When logging messages you can either use the named methods,
49
 * or the correct constants with `write()`:
50
 *
51
 * {{{
52
 * CakeLog::error('Something horrible happened');
53
 * CakeLog::write(LOG_ERR, 'Something horrible happened');
54
 * }}}
55
 *
56
 * If you require custom logging levels, you can use CakeLog::levels() to
57
 * append additional logging levels.
58
 *
59
 * ### Logging scopes
60
 *
61
 * When logging messages and configuring log adapters, you can specify
62
 * 'scopes' that the logger will handle. You can think of scopes as subsystems
63
 * in your application that may require different logging setups. For
64
 * example in an e-commerce application you may want to handle logged errors
65
 * in the cart and ordering subsystems differently than the rest of the
66
 * application. By using scopes you can control logging for each part
67
 * of your application and still keep standard log levels.
68
 *
69
 *
70
 * See CakeLog::config() and CakeLog::write() for more information
71
 * on scopes
72
 *
73
 * @package       Cake.Log
74
 */
75
class CakeLog {
76
 
77
/**
78
 * LogEngineCollection class
79
 *
80
 * @var LogEngineCollection
81
 */
82
	protected static $_Collection;
83
 
84
/**
85
 * Default log levels as detailed in RFC 5424
86
 * http://tools.ietf.org/html/rfc5424
87
 *
88
 * @var array
89
 */
90
	protected static $_defaultLevels = array(
91
		'emergency' => LOG_EMERG,
92
		'alert' => LOG_ALERT,
93
		'critical' => LOG_CRIT,
94
		'error' => LOG_ERR,
95
		'warning' => LOG_WARNING,
96
		'notice' => LOG_NOTICE,
97
		'info' => LOG_INFO,
98
		'debug' => LOG_DEBUG,
99
	);
100
 
101
/**
102
 * Active log levels for this instance.
103
 *
104
 * @var array
105
 */
106
	protected static $_levels;
107
 
108
/**
109
 * Mapped log levels
110
 *
111
 * @var array
112
 */
113
	protected static $_levelMap;
114
 
115
/**
116
 * initialize ObjectCollection
117
 *
118
 * @return void
119
 */
120
	protected static function _init() {
121
		self::$_levels = self::defaultLevels();
122
		self::$_Collection = new LogEngineCollection();
123
	}
124
 
125
/**
126
 * Configure and add a new logging stream to CakeLog
127
 * You can use add loggers from app/Log/Engine use app.loggername, or any
128
 * plugin/Log/Engine using plugin.loggername.
129
 *
130
 * ### Usage:
131
 *
132
 * {{{
133
 * CakeLog::config('second_file', array(
134
 *     'engine' => 'File',
135
 *     'path' => '/var/logs/my_app/'
136
 * ));
137
 * }}}
138
 *
139
 * Will configure a FileLog instance to use the specified path.
140
 * All options that are not `engine` are passed onto the logging adapter,
141
 * and handled there. Any class can be configured as a logging
142
 * adapter as long as it implements the methods in CakeLogInterface.
143
 *
144
 * ### Logging levels
145
 *
146
 * When configuring loggers, you can set which levels a logger will handle.
147
 * This allows you to disable debug messages in production for example:
148
 *
149
 * {{{
150
 * CakeLog::config('default', array(
151
 *     'engine' => 'File',
152
 *     'path' => LOGS,
153
 *     'levels' => array('error', 'critical', 'alert', 'emergency')
154
 * ));
155
 * }}}
156
 *
157
 * The above logger would only log error messages or higher. Any
158
 * other log messages would be discarded.
159
 *
160
 * ### Logging scopes
161
 *
162
 * When configuring loggers you can define the active scopes the logger
163
 * is for. If defined only the listed scopes will be handled by the
164
 * logger. If you don't define any scopes an adapter will catch
165
 * all scopes that match the handled levels.
166
 *
167
 * {{{
168
 * CakeLog::config('payments', array(
169
 *     'engine' => 'File',
170
 *     'types' => array('info', 'error', 'warning'),
171
 *     'scopes' => array('payment', 'order')
172
 * ));
173
 * }}}
174
 *
175
 * The above logger will only capture log entries made in the
176
 * `payment` and `order` scopes. All other scopes including the
177
 * undefined scope will be ignored. Its important to remember that
178
 * when using scopes you must also define the `types` of log messages
179
 * that a logger will handle. Failing to do so will result in the logger
180
 * catching all log messages even if the scope is incorrect.
181
 *
182
 * @param string $key The keyname for this logger, used to remove the
183
 *    logger later.
184
 * @param array $config Array of configuration information for the logger
185
 * @return boolean success of configuration.
186
 * @throws CakeLogException
187
 */
188
	public static function config($key, $config) {
189
		if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $key)) {
190
			throw new CakeLogException(__d('cake_dev', 'Invalid key name'));
191
		}
192
		if (empty($config['engine'])) {
193
			throw new CakeLogException(__d('cake_dev', 'Missing logger class name'));
194
		}
195
		if (empty(self::$_Collection)) {
196
			self::_init();
197
		}
198
		self::$_Collection->load($key, $config);
199
		return true;
200
	}
201
 
202
/**
203
 * Returns the keynames of the currently active streams
204
 *
205
 * @return array Array of configured log streams.
206
 */
207
	public static function configured() {
208
		if (empty(self::$_Collection)) {
209
			self::_init();
210
		}
211
		return self::$_Collection->loaded();
212
	}
213
 
214
/**
215
 * Gets/sets log levels
216
 *
217
 * Call this method without arguments, eg: `CakeLog::levels()` to obtain current
218
 * level configuration.
219
 *
220
 * To append additional level 'user0' and 'user1' to to default log levels:
221
 *
222
 * {{{
223
 * CakeLog::levels(array('user0, 'user1'));
224
 * // or
225
 * CakeLog::levels(array('user0, 'user1'), true);
226
 * }}}
227
 *
228
 * will result in:
229
 *
230
 * {{{
231
 * array(
232
 *     0 => 'emergency',
233
 *     1 => 'alert',
234
 *     ...
235
 *     8 => 'user0',
236
 *     9 => 'user1',
237
 * );
238
 * }}}
239
 *
240
 * To set/replace existing configuration, pass an array with the second argument
241
 * set to false.
242
 *
243
 * {{{
244
 * CakeLog::levels(array('user0, 'user1'), false);
245
 * }}}
246
 *
247
 * will result in:
248
 *
249
 * {{{
250
 * array(
251
 *      0 => 'user0',
252
 *      1 => 'user1',
253
 * );
254
 * }}}
255
 *
256
 * @param array $levels array
257
 * @param boolean $append true to append, false to replace
258
 * @return array Active log levels
259
 */
260
	public static function levels($levels = array(), $append = true) {
261
		if (empty(self::$_Collection)) {
262
			self::_init();
263
		}
264
		if (empty($levels)) {
265
			return self::$_levels;
266
		}
267
		$levels = array_values($levels);
268
		if ($append) {
269
			self::$_levels = array_merge(self::$_levels, $levels);
270
		} else {
271
			self::$_levels = $levels;
272
		}
273
		self::$_levelMap = array_flip(self::$_levels);
274
		return self::$_levels;
275
	}
276
 
277
/**
278
 * Reset log levels to the original value
279
 *
280
 * @return array Default log levels
281
 */
282
	public static function defaultLevels() {
283
		self::$_levelMap = self::$_defaultLevels;
284
		self::$_levels = array_flip(self::$_levelMap);
285
		return self::$_levels;
286
	}
287
 
288
/**
289
 * Removes a stream from the active streams. Once a stream has been removed
290
 * it will no longer have messages sent to it.
291
 *
292
 * @param string $streamName Key name of a configured stream to remove.
293
 * @return void
294
 */
295
	public static function drop($streamName) {
296
		if (empty(self::$_Collection)) {
297
			self::_init();
298
		}
299
		self::$_Collection->unload($streamName);
300
	}
301
 
302
/**
303
 * Checks whether $streamName is enabled
304
 *
305
 * @param string $streamName to check
306
 * @return boolean
307
 * @throws CakeLogException
308
 */
309
	public static function enabled($streamName) {
310
		if (empty(self::$_Collection)) {
311
			self::_init();
312
		}
313
		if (!isset(self::$_Collection->{$streamName})) {
314
			throw new CakeLogException(__d('cake_dev', 'Stream %s not found', $streamName));
315
		}
316
		return self::$_Collection->enabled($streamName);
317
	}
318
 
319
/**
320
 * Enable stream. Streams that were previously disabled
321
 * can be re-enabled with this method.
322
 *
323
 * @param string $streamName to enable
324
 * @return void
325
 * @throws CakeLogException
326
 */
327
	public static function enable($streamName) {
328
		if (empty(self::$_Collection)) {
329
			self::_init();
330
		}
331
		if (!isset(self::$_Collection->{$streamName})) {
332
			throw new CakeLogException(__d('cake_dev', 'Stream %s not found', $streamName));
333
		}
334
		self::$_Collection->enable($streamName);
335
	}
336
 
337
/**
338
 * Disable stream. Disabling a stream will
339
 * prevent that log stream from receiving any messages until
340
 * its re-enabled.
341
 *
342
 * @param string $streamName to disable
343
 * @return void
344
 * @throws CakeLogException
345
 */
346
	public static function disable($streamName) {
347
		if (empty(self::$_Collection)) {
348
			self::_init();
349
		}
350
		if (!isset(self::$_Collection->{$streamName})) {
351
			throw new CakeLogException(__d('cake_dev', 'Stream %s not found', $streamName));
352
		}
353
		self::$_Collection->disable($streamName);
354
	}
355
 
356
/**
357
 * Gets the logging engine from the active streams.
358
 *
359
 * @see BaseLog
360
 * @param string $streamName Key name of a configured stream to get.
361
 * @return mixed instance of BaseLog or false if not found
362
 */
363
	public static function stream($streamName) {
364
		if (empty(self::$_Collection)) {
365
			self::_init();
366
		}
367
		if (!empty(self::$_Collection->{$streamName})) {
368
			return self::$_Collection->{$streamName};
369
		}
370
		return false;
371
	}
372
 
373
/**
374
 * Configures the automatic/default stream a FileLog.
375
 *
376
 * @return void
377
 */
378
	protected static function _autoConfig() {
379
		self::$_Collection->load('default', array(
380
			'engine' => 'File',
381
			'path' => LOGS,
382
		));
383
	}
384
 
385
/**
386
 * Writes the given message and type to all of the configured log adapters.
387
 * Configured adapters are passed both the $type and $message variables. $type
388
 * is one of the following strings/values.
389
 *
390
 * ### Types:
391
 *
392
 * -  LOG_EMERG => 'emergency',
393
 * -  LOG_ALERT => 'alert',
394
 * -  LOG_CRIT => 'critical',
395
 * - `LOG_ERR` => 'error',
396
 * - `LOG_WARNING` => 'warning',
397
 * - `LOG_NOTICE` => 'notice',
398
 * - `LOG_INFO` => 'info',
399
 * - `LOG_DEBUG` => 'debug',
400
 *
401
 * ### Usage:
402
 *
403
 * Write a message to the 'warning' log:
404
 *
405
 * `CakeLog::write('warning', 'Stuff is broken here');`
406
 *
407
 * @param integer|string $type Type of message being written. When value is an integer
408
 *    or a string matching the recognized levels, then it will
409
 *    be treated log levels. Otherwise it's treated as scope.
410
 * @param string $message Message content to log
411
 * @param string|array $scope The scope(s) a log message is being created in.
412
 *    See CakeLog::config() for more information on logging scopes.
413
 * @return boolean Success
414
 */
415
	public static function write($type, $message, $scope = array()) {
416
		if (empty(self::$_Collection)) {
417
			self::_init();
418
		}
419
 
420
		if (is_int($type) && isset(self::$_levels[$type])) {
421
			$type = self::$_levels[$type];
422
		}
423
		if (is_string($type) && empty($scope) && !in_array($type, self::$_levels)) {
424
			$scope = $type;
425
		}
426
		$logged = false;
427
		foreach (self::$_Collection->enabled() as $streamName) {
428
			$logger = self::$_Collection->{$streamName};
429
			$types = $scopes = $config = array();
430
			if (method_exists($logger, 'config')) {
431
				$config = $logger->config();
432
			}
433
			if (isset($config['types'])) {
434
				$types = $config['types'];
435
			}
436
			if (isset($config['scopes'])) {
437
				$scopes = $config['scopes'];
438
			}
439
			$inScope = (count(array_intersect((array)$scope, $scopes)) > 0);
440
			$correctLevel = in_array($type, $types);
441
 
442
			if (
443
				// No config is a catch all (bc mode)
444
				(empty($types) && empty($scopes)) ||
445
				// BC layer for mixing scope & level
446
				(in_array($type, $scopes)) ||
447
				// no scopes, but has level
448
				(empty($scopes) && $correctLevel) ||
449
				// exact scope + level
450
				($correctLevel && $inScope)
451
			) {
452
				$logger->write($type, $message);
453
				$logged = true;
454
			}
455
		}
456
		if (!$logged) {
457
			self::_autoConfig();
458
			self::stream('default')->write($type, $message);
459
		}
460
		return true;
461
	}
462
 
463
/**
464
 * Convenience method to log emergency messages
465
 *
466
 * @param string $message log message
467
 * @param string|array $scope The scope(s) a log message is being created in.
468
 *    See CakeLog::config() for more information on logging scopes.
469
 * @return boolean Success
470
 */
471
	public static function emergency($message, $scope = array()) {
472
		return self::write(self::$_levelMap['emergency'], $message, $scope);
473
	}
474
 
475
/**
476
 * Convenience method to log alert messages
477
 *
478
 * @param string $message log message
479
 * @param string|array $scope The scope(s) a log message is being created in.
480
 *    See CakeLog::config() for more information on logging scopes.
481
 * @return boolean Success
482
 */
483
	public static function alert($message, $scope = array()) {
484
		return self::write(self::$_levelMap['alert'], $message, $scope);
485
	}
486
 
487
/**
488
 * Convenience method to log critical messages
489
 *
490
 * @param string $message log message
491
 * @param string|array $scope The scope(s) a log message is being created in.
492
 *    See CakeLog::config() for more information on logging scopes.
493
 * @return boolean Success
494
 */
495
	public static function critical($message, $scope = array()) {
496
		return self::write(self::$_levelMap['critical'], $message, $scope);
497
	}
498
 
499
/**
500
 * Convenience method to log error messages
501
 *
502
 * @param string $message log message
503
 * @param string|array $scope The scope(s) a log message is being created in.
504
 *    See CakeLog::config() for more information on logging scopes.
505
 * @return boolean Success
506
 */
507
	public static function error($message, $scope = array()) {
508
		return self::write(self::$_levelMap['error'], $message, $scope);
509
	}
510
 
511
/**
512
 * Convenience method to log warning messages
513
 *
514
 * @param string $message log message
515
 * @param string|array $scope The scope(s) a log message is being created in.
516
 *    See CakeLog::config() for more information on logging scopes.
517
 * @return boolean Success
518
 */
519
	public static function warning($message, $scope = array()) {
520
		return self::write(self::$_levelMap['warning'], $message, $scope);
521
	}
522
 
523
/**
524
 * Convenience method to log notice messages
525
 *
526
 * @param string $message log message
527
 * @param string|array $scope The scope(s) a log message is being created in.
528
 *    See CakeLog::config() for more information on logging scopes.
529
 * @return boolean Success
530
 */
531
	public static function notice($message, $scope = array()) {
532
		return self::write(self::$_levelMap['notice'], $message, $scope);
533
	}
534
 
535
/**
536
 * Convenience method to log debug messages
537
 *
538
 * @param string $message log message
539
 * @param string|array $scope The scope(s) a log message is being created in.
540
 *    See CakeLog::config() for more information on logging scopes.
541
 * @return boolean Success
542
 */
543
	public static function debug($message, $scope = array()) {
544
		return self::write(self::$_levelMap['debug'], $message, $scope);
545
	}
546
 
547
/**
548
 * Convenience method to log info messages
549
 *
550
 * @param string $message log message
551
 * @param string|array $scope The scope(s) a log message is being created in.
552
 *    See CakeLog::config() for more information on logging scopes.
553
 * @return boolean Success
554
 */
555
	public static function info($message, $scope = array()) {
556
		return self::write(self::$_levelMap['info'], $message, $scope);
557
	}
558
 
559
}