change to match syslog levels & customizable levels

This commit is contained in:
Rachman Chavik 2012-05-11 18:31:55 +07:00
parent 88fe559ec5
commit 8e8763d69d
6 changed files with 330 additions and 50 deletions

View file

@ -163,6 +163,6 @@ CakeLog::config('debug', array(
)); ));
CakeLog::config('error', array( CakeLog::config('error', array(
'engine' => 'FileLog', 'engine' => 'FileLog',
'types' => array('error', 'warning'), 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'error', 'file' => 'error',
)); ));

View file

@ -133,7 +133,7 @@
* Defines the default error type when using the log() function. Used for * Defines the default error type when using the log() function. Used for
* differentiating error logging and debugging. Currently PHP supports LOG_DEBUG. * differentiating error logging and debugging. Currently PHP supports LOG_DEBUG.
*/ */
define('LOG_ERROR', 2); define('LOG_ERROR', LOG_ERR);
/** /**
* Session configuration. * Session configuration.

View file

@ -103,6 +103,6 @@ CakeLog::config('debug', array(
)); ));
CakeLog::config('error', array( CakeLog::config('error', array(
'engine' => 'FileLog', 'engine' => 'FileLog',
'scopes' => array('error', 'warning'), 'scopes' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'error', 'file' => 'error',
)); ));

View file

@ -133,7 +133,7 @@
* Defines the default error type when using the log() function. Used for * Defines the default error type when using the log() function. Used for
* differentiating error logging and debugging. Currently PHP supports LOG_DEBUG. * differentiating error logging and debugging. Currently PHP supports LOG_DEBUG.
*/ */
define('LOG_ERROR', 2); define('LOG_ERROR', LOG_ERR);
/** /**
* Session configuration. * Session configuration.

View file

@ -24,24 +24,33 @@
* system. * system.
* *
*/ */
if (!defined('LOG_ERROR')) { if (!defined('LOG_EMERG')) {
define('LOG_ERROR', 2); define('LOG_EMERG', 0);
}
if (!defined('LOG_ALERT')) {
define('LOG_ALERT', 1);
}
if (!defined('LOG_CRIT')) {
define('LOG_CRIT', 2);
} }
if (!defined('LOG_ERR')) { if (!defined('LOG_ERR')) {
define('LOG_ERR', LOG_ERROR); define('LOG_ERR', 3);
}
if (!defined('LOG_ERROR')) {
define('LOG_ERROR', LOG_ERR);
} }
if (!defined('LOG_WARNING')) { if (!defined('LOG_WARNING')) {
define('LOG_WARNING', 3); define('LOG_WARNING', 4);
} }
if (!defined('LOG_NOTICE')) { if (!defined('LOG_NOTICE')) {
define('LOG_NOTICE', 4); define('LOG_NOTICE', 5);
}
if (!defined('LOG_DEBUG')) {
define('LOG_DEBUG', 5);
} }
if (!defined('LOG_INFO')) { if (!defined('LOG_INFO')) {
define('LOG_INFO', 6); define('LOG_INFO', 6);
} }
if (!defined('LOG_DEBUG')) {
define('LOG_DEBUG', 7);
}
App::uses('LogEngineCollection', 'Log'); App::uses('LogEngineCollection', 'Log');
@ -74,12 +83,38 @@ class CakeLog {
*/ */
protected static $_Collection; protected static $_Collection;
/**
* Default log levels as detailed in RFC 5424
* http://tools.ietf.org/html/rfc5424
*/
protected static $_defaultLevels = array(
LOG_EMERG => 'emergency',
LOG_ALERT => 'alert',
LOG_CRIT => 'critical',
LOG_ERR => 'error',
LOG_WARNING => 'warning',
LOG_NOTICE => 'notice',
LOG_INFO => 'info',
LOG_DEBUG => 'debug',
);
/**
* Active log levels for this instance.
*/
protected static $_levels;
/**
* Mapped log levels
*/
protected static $_levelMap;
/** /**
* initialize ObjectCollection * initialize ObjectCollection
* *
* @return void * @return void
*/ */
protected static function _init() { protected static function _init() {
self::$_levels = self::defaultLevels();
self::$_Collection = new LogEngineCollection(); self::$_Collection = new LogEngineCollection();
} }
@ -131,6 +166,70 @@ class CakeLog {
return self::$_Collection->attached(); return self::$_Collection->attached();
} }
/**
* Gets/sets log levels
*
* Call this method without arguments, eg: `CakeLog::levels()` to obtain current
* level configuration.
*
* To append additional level 'user0' and 'user1' to to default log levels:
*
* `CakeLog::levels(array('user0, 'user1'))` or
* `CakeLog::levels(array('user0, 'user1'), true)`
*
* will result in:
*
* array(
* 0 => 'emergency',
* 1 => 'alert',
* ...
* 8 => 'user0',
* 9 => 'user1',
* );
*
* To set/replace existing configuration, pass an array with the second argument
* set to false.
*
* `CakeLog::levels(array('user0, 'user1'), false);
*
* will result in:
* array(
* 0 => 'user0',
* 1 => 'user1',
* );
*
* @param mixed $levels array
* @param bool $append true to append, false to replace
* @return array active log levels
*/
public static function levels($levels = array(), $append = true) {
if (empty(self::$_Collection)) {
self::_init();
}
if (empty($levels)) {
return self::$_levels;
}
$levels = array_values($levels);
if ($append) {
self::$_levels = array_merge(self::$_levels, $levels);
} else {
self::$_levels = $levels;
}
self::$_levelMap = array_flip(self::$_levels);
return self::$_levels;
}
/**
* Reset log levels to the original value
*
* @return array default log levels
*/
public static function defaultLevels() {
self::$_levels = self::$_defaultLevels;
self::$_levelMap = array_flip(self::$_levels);
return self::$_levels;
}
/** /**
* Removes a stream from the active streams. Once a stream has been removed * Removes a stream from the active streams. Once a stream has been removed
* it will no longer have messages sent to it. * it will no longer have messages sent to it.
@ -221,7 +320,7 @@ class CakeLog {
protected static function _autoConfig() { protected static function _autoConfig() {
self::$_Collection->load('error', array( self::$_Collection->load('error', array(
'engine' => 'FileLog', 'engine' => 'FileLog',
'types' => array('error', 'warning'), 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'path' => LOGS, 'path' => LOGS,
)); ));
} }
@ -233,12 +332,14 @@ class CakeLog {
* *
* ### Types: * ### Types:
* *
* - LOG_EMERG => 'emergency',
* - LOG_ALERT => 'alert',
* - LOG_CRIT => 'critical',
* - `LOG_ERR` => 'error',
* - `LOG_WARNING` => 'warning', * - `LOG_WARNING` => 'warning',
* - `LOG_NOTICE` => 'notice', * - `LOG_NOTICE` => 'notice',
* - `LOG_INFO` => 'info', * - `LOG_INFO` => 'info',
* - `LOG_DEBUG` => 'debug', * - `LOG_DEBUG` => 'debug',
* - `LOG_ERR` => 'error',
* - `LOG_ERROR` => 'error'
* *
* ### Usage: * ### Usage:
* *
@ -257,19 +358,11 @@ class CakeLog {
if (empty(self::$_Collection)) { if (empty(self::$_Collection)) {
self::_init(); self::_init();
} }
$levels = array(
LOG_ERROR => 'error',
LOG_ERR => 'error',
LOG_WARNING => 'warning',
LOG_NOTICE => 'notice',
LOG_DEBUG => 'debug',
LOG_INFO => 'info',
);
if (is_int($type) && isset($levels[$type])) { if (is_int($type) && isset(self::$_levels[$type])) {
$type = $levels[$type]; $type = self::$_levels[$type];
} }
if (is_string($type) && empty($scope) && !in_array($type, $levels)) { if (is_string($type) && empty($scope) && !in_array($type, self::$_levels)) {
$scope = $type; $scope = $type;
} }
if (!self::$_Collection->attached()) { if (!self::$_Collection->attached()) {
@ -298,48 +391,91 @@ class CakeLog {
} }
/** /**
* Convenience method to log error messages * Convenience method to log emergency messages
* *
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success * @return boolean Success
*/ */
public static function error($message) { public static function emergency($message, $scope = array()) {
return self::write(LOG_ERROR, $message); return self::write(self::$_levelMap['emergency'], $message, $scope);
}
/**
* Convenience method to log alert messages
*
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success
*/
public static function alert($message, $scope = array()) {
return self::write(self::$_levelMap['alert'], $message, $scope);
}
/**
* Convenience method to log critical messages
*
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success
*/
public static function critical($message, $scope = array()) {
return self::write(self::$_levelMap['critical'], $message, $scope);
}
/**
* Convenience method to log error messages
*
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success
*/
public static function error($message, $scope = array()) {
return self::write(self::$_levelMap['error'], $message, $scope);
} }
/** /**
* Convenience method to log warning messages * Convenience method to log warning messages
* *
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success * @return boolean Success
*/ */
public static function warning($message) { public static function warning($message, $scope = array()) {
return self::write(LOG_WARNING, $message); return self::write(self::$_levelMap['warning'], $message, $scope);
} }
/** /**
* Convenience method to log notice messages * Convenience method to log notice messages
* *
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success * @return boolean Success
*/ */
public static function notice($message) { public static function notice($message, $scope = array()) {
return self::write(LOG_NOTICE, $message); return self::write(self::$_levelMap['notice'], $message, $scope);
} }
/** /**
* Convenience method to log debug messages * Convenience method to log debug messages
* *
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success * @return boolean Success
*/ */
public static function debug($message) { public static function debug($message, $scope = array()) {
return self::write(LOG_DEBUG, $message); return self::write(self::$_levelMap['debug'], $message, $scope);
} }
/** /**
* Convenience method to log info messages * Convenience method to log info messages
* *
* @param string $message log message
* @param mixed $scope string or array of scopes
* @return boolean Success * @return boolean Success
*/ */
public static function info($message) { public static function info($message, $scope = array()) {
return self::write(LOG_INFO, $message); return self::write(self::$_levelMap['info'], $message, $scope);
} }
} }

View file

@ -289,7 +289,7 @@ class CakeLogTest extends CakeTestCase {
)); ));
CakeLog::config('error', array( CakeLog::config('error', array(
'engine' => 'FileLog', 'engine' => 'FileLog',
'types' => array('error', 'warning'), 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'error', 'file' => 'error',
)); ));
} }
@ -430,6 +430,52 @@ class CakeLogTest extends CakeTestCase {
CakeLog::drop('shops'); CakeLog::drop('shops');
} }
/**
* test scoped logging with convenience methods
*/
public function testConvenienceScopedLogging() {
if (file_exists(LOGS . 'shops.log')) {
unlink(LOGS . 'shops.log');
}
if (file_exists(LOGS . 'error.log')) {
unlink(LOGS . 'error.log');
}
if (file_exists(LOGS . 'debug.log')) {
unlink(LOGS . 'debug.log');
}
$this->_resetLogConfig();
CakeLog::config('shops', array(
'engine' => 'FileLog',
'types' => array('info', 'notice', 'warning'),
'scopes' => array('transactions', 'orders'),
'file' => 'shops',
));
CakeLog::info('info message', 'transactions');
$this->assertFalse(file_exists(LOGS . 'error.log'));
$this->assertTrue(file_exists(LOGS . 'shops.log'));
$this->assertTrue(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs();
CakeLog::error('error message', 'orders');
$this->assertTrue(file_exists(LOGS . 'error.log'));
$this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->assertFalse(file_exists(LOGS . 'shops.log'));
$this->_deleteLogs();
CakeLog::warning('warning message', 'orders');
$this->assertTrue(file_exists(LOGS . 'error.log'));
$this->assertTrue(file_exists(LOGS . 'shops.log'));
$this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs();
CakeLog::drop('shops');
}
/** /**
* test convenience methods * test convenience methods
*/ */
@ -443,44 +489,142 @@ class CakeLogTest extends CakeTestCase {
)); ));
CakeLog::config('error', array( CakeLog::config('error', array(
'engine' => 'FileLog', 'engine' => 'FileLog',
'types' => array('error', 'warning'), 'types' => array('emergency', 'alert', 'critical', 'error', 'warning'),
'file' => 'error', 'file' => 'error',
)); ));
$testMessage = 'emergency message';
CakeLog::emergency($testMessage);
$contents = file_get_contents(LOGS . 'error.log');
$this->assertContains('Emergency: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs();
$testMessage = 'alert message';
CakeLog::alert($testMessage);
$contents = file_get_contents(LOGS . 'error.log');
$this->assertContains('Alert: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs();
$testMessage = 'critical message';
CakeLog::critical($testMessage);
$contents = file_get_contents(LOGS . 'error.log');
$this->assertContains('Critical: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs();
$testMessage = 'error message'; $testMessage = 'error message';
CakeLog::error($testMessage); CakeLog::error($testMessage);
$contents = file_get_contents(LOGS . 'error.log'); $contents = file_get_contents(LOGS . 'error.log');
$this->assertContains($testMessage, $contents); $this->assertContains('Error: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'debug.log')); $this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs(); $this->_deleteLogs();
$testMessage = 'warning message'; $testMessage = 'warning message';
CakeLog::warning($testMessage); CakeLog::warning($testMessage);
$contents = file_get_contents(LOGS . 'error.log'); $contents = file_get_contents(LOGS . 'error.log');
$this->assertContains($testMessage, $contents); $this->assertContains('Warning: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'debug.log')); $this->assertFalse(file_exists(LOGS . 'debug.log'));
$this->_deleteLogs(); $this->_deleteLogs();
$testMessage = 'notice message';
CakeLog::notice($testMessage);
$contents = file_get_contents(LOGS . 'debug.log');
$this->assertContains('Notice: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'error.log'));
$this->_deleteLogs();
$testMessage = 'info message'; $testMessage = 'info message';
CakeLog::info($testMessage); CakeLog::info($testMessage);
$contents = file_get_contents(LOGS . 'debug.log'); $contents = file_get_contents(LOGS . 'debug.log');
$this->assertContains($testMessage, $contents); $this->assertContains('Info: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'error.log')); $this->assertFalse(file_exists(LOGS . 'error.log'));
$this->_deleteLogs(); $this->_deleteLogs();
$testMessage = 'debug message'; $testMessage = 'debug message';
CakeLog::debug($testMessage); CakeLog::debug($testMessage);
$contents = file_get_contents(LOGS . 'debug.log'); $contents = file_get_contents(LOGS . 'debug.log');
$this->assertContains($testMessage, $contents); $this->assertContains('Debug: ' . $testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'error.log'));
$this->_deleteLogs();
$testMessage = 'notice message';
CakeLog::notice($testMessage);
$contents = file_get_contents(LOGS . 'debug.log');
$this->assertContains($testMessage, $contents);
$this->assertFalse(file_exists(LOGS . 'error.log')); $this->assertFalse(file_exists(LOGS . 'error.log'));
$this->_deleteLogs(); $this->_deleteLogs();
} }
/**
* test levels customization
*/
public function testLevelCustomization() {
$this->skipIf(DIRECTORY_SEPARATOR === '\\', 'Log level tests not supported on Windows.');
$levels = CakeLog::defaultLevels();
$this->assertNotEmpty($levels);
$result = array_keys($levels);
$this->assertEquals(array(0, 1, 2, 3, 4, 5, 6, 7), $result);
$levels = CakeLog::levels(array('foo', 'bar'));
CakeLog::defaultLevels();
$this->assertEquals('foo', $levels[8]);
$this->assertEquals('bar', $levels[9]);
$levels = CakeLog::levels(array(11 => 'spam', 'bar' => 'eggs'));
CakeLog::defaultLevels();
$this->assertEquals('spam', $levels[8]);
$this->assertEquals('eggs', $levels[9]);
$levels = CakeLog::levels(array(11 => 'spam', 'bar' => 'eggs'), false);
CakeLog::defaultLevels();
$this->assertEquals(array('spam', 'eggs'), $levels);
$levels = CakeLog::levels(array('ham', 9 => 'spam', '12' => 'fam'), false);
CakeLog::defaultLevels();
$this->assertEquals(array('ham', 'spam', 'fam'), $levels);
}
/**
* Test writing log files with custom levels
*/
public function testCustomLevelWrites() {
$this->_deleteLogs();
$this->_resetLogConfig();
$levels = CakeLog::levels(array('spam', 'eggs'));
$testMessage = 'error message';
CakeLog::write('error', $testMessage);
CakeLog::defaultLevels();
$this->assertTrue(file_exists(LOGS . 'error.log'));
$contents = file_get_contents(LOGS . 'error.log');
$this->assertContains('Error: ' . $testMessage, $contents);
CakeLog::config('spam', array(
'engine' => 'FileLog',
'file' => 'spam.log',
'types' => 'spam',
));
CakeLog::config('eggs', array(
'engine' => 'FileLog',
'file' => 'eggs.log',
'types' => array('spam', 'eggs'),
));
$testMessage = 'spam message';
CakeLog::write('spam', $testMessage);
CakeLog::defaultLevels();
$this->assertTrue(file_exists(LOGS . 'spam.log'));
$this->assertTrue(file_exists(LOGS . 'eggs.log'));
$contents = file_get_contents(LOGS . 'spam.log');
$this->assertContains('Spam: ' . $testMessage, $contents);
$testMessage = 'egg message';
CakeLog::write('eggs', $testMessage);
CakeLog::defaultLevels();
$contents = file_get_contents(LOGS . 'spam.log');
$this->assertNotContains('Eggs: ' . $testMessage, $contents);
$contents = file_get_contents(LOGS . 'eggs.log');
$this->assertContains('Eggs: ' . $testMessage, $contents);
CakeLog::drop('spam');
CakeLog::drop('eggs');
}
} }