Skip to content

Commit

Permalink
Remove dependency on Configure for logging.
Browse files Browse the repository at this point in the history
Not using Configure to setup logging has a couple benefits.

* Using Configure creates magic at a distance. Setting things in one
  class creates effects in another.
* Loggers at bootstrap and loggers created at runtime are handled
  consistently.
* Dropped loggers don't magically re-create themselves once Log has been
  reset.
* It is still simple to create loggers using configuration files, or
  inject instances directly.

With this change we are still able to lazily load loggers once Log is
used.
  • Loading branch information
markstory committed Aug 14, 2013
1 parent 9778b62 commit d6c030d
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 105 deletions.
19 changes: 8 additions & 11 deletions App/Config/logging.php
Expand Up @@ -14,25 +14,22 @@
*/
namespace App\Config;

use Cake\Core\Configure;
use Cake\Log\Log;

/**
* Defines the default error type when using the log() function. Used for
* differentiating error logging and debugging. Currently PHP supports LOG_DEBUG.
*/
define('LOG_ERROR', LOG_ERR);
$logConfig = [];

/**
* Configures default file logging options
*/
Configure::write('Log.debug', [
$logConfig['debug'] = [
'engine' => 'Cake\Log\Engine\FileLog',
'levels' => ['notice', 'info', 'debug'],
'file' => 'debug',
]);

Configure::write('Log.error', [
];
$logConfig['error'] = [
'engine' => 'Cake\Log\Engine\FileLog',
'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
'file' => 'error',
]);
];

Log::config($logConfig);
86 changes: 51 additions & 35 deletions lib/Cake/Log/Log.php
Expand Up @@ -13,8 +13,6 @@
*/
namespace Cake\Log;

use Cake\Core\App;
use Cake\Core\Configure;
use Cake\Error;
use Cake\Log\Engine\BaseLog;

Expand All @@ -30,7 +28,7 @@
* A sample configuration would look like:
*
* {{{
* Configure::write('Log.my_log', ['engine' => 'FileLog']);
* Log::config('my_log', ['engine' => 'FileLog']);
* }}}
*
* You can define the engine as any fully namespaced classname or use a short hand
Expand All @@ -40,7 +38,7 @@
* Log adapters are required to implement `Cake\Log\LogInterface`, and there is a
* built-in base class (`Cake\Log\Engine\BaseLog`) that can be used for custom loggers.
*
* Outside of the `engine` key, all other configuration values will be passed to the
* Outside of the `engine` key, all other configuration values will be passed to the
* logging adapter's constructor as an array.
*
* ### Logging levels
Expand All @@ -49,7 +47,7 @@
* This allows you to disable debug messages in production for example:
*
* {{{
* Configure::write('default', [
* Log::config('default', [
* 'engine' => 'File',
* 'path' => LOGS,
* 'levels' => ['error', 'critical', 'alert', 'emergency']
Expand All @@ -62,12 +60,12 @@
* ### Logging scopes
*
* When configuring loggers you can define the active scopes the logger
* is for. If defined, only the listed scopes will be handled by the
* logger. If you don't define any scopes an adapter will catch
* is for. If defined, only the listed scopes will be handled by the
* logger. If you don't define any scopes an adapter will catch
* all scopes that match the handled levels.
*
* {{{
* Configure::write('payments', [
* Log::config('payments', [
* 'engine' => 'File',
* 'scopes' => ['payment', 'order']
* ]);
Expand All @@ -77,13 +75,6 @@
* `payment` and `order` scopes. All other scopes including the
* undefined scope will be ignored.
*
* ### Loading loggers at runtime
*
* After an application's bootstrap phase is complete, or after
* any log messages are written you cannot use Configure to create
* new loggers, without using Log::reset() first. Instead you should
* use Log::engine() to insert constructed loggers, when dynamically
* adding loggers at runtime.
*
* ### Writing to the log
*
Expand All @@ -109,11 +100,23 @@
* in the cart and ordering subsystems differently than the rest of the
* application. By using scopes you can control logging for each part
* of your application and also use standard log levels.
*
* @package Cake.Log
*/
class Log {

/**
* Internal flag for tracking whether or not configuration has been changed.
*
* @var boolean
*/
protected static $_dirtyConfig = false;

/**
* An array of configured loggers.
*
* @var array
*/
protected static $_config = [];

/**
* LogEngineRegistry class
*
Expand Down Expand Up @@ -162,8 +165,11 @@ class Log {
protected static function _init() {
if (empty(static::$_registry)) {
static::$_registry = new LogEngineRegistry();
}
if (static::$_dirtyConfig) {
static::_loadConfig();
}
static::$_dirtyConfig = false;
}

/**
Expand All @@ -173,8 +179,7 @@ protected static function _init() {
* @return void
*/
protected static function _loadConfig() {
$loggers = Configure::read('Log');
foreach ((array)$loggers as $name => $properties) {
foreach (static::$_config as $name => $properties) {
if (isset($properties['engine'])) {
$properties['className'] = $properties['engine'];
}
Expand All @@ -188,11 +193,14 @@ protected static function _loadConfig() {
* Log class.
*
* Resets the configured logging adapters, as well as any custom logging levels.
* This will also clear the configuration data.
*
* @return void
*/
public static function reset() {
static::$_registry = null;
static::$_config = [];
static::$_dirtyConfig = true;
}

/**
Expand All @@ -218,15 +226,29 @@ public static function levels() {
}

/**
* @deprecated Use Configure::write() to configure logging.
* @see App/Config/logging.php
* Set configuration information for loggers.
*
* This method can be used to define loggers for an application
* during the bootstrapping process. You can use this method to add new loggers
* at runtime as well. New loggers will be constructed upon the next write.
*
* To change a logger's configuration at runtime, first drop the logger and then
* reconfigure it.
*
* Loggers will not be constructed until the first log message is written.
*
* @param string|array $key The name of the logger, or an array of multiple logger configs.
* @param array $config An array of name => config data for loggers.
* @return void
* @see App/Config/logging.php
*/
public static function config($key, $config) {
trigger_error(
__d('cake_dev', 'You must use Configure::write() to define logging configuration. Or use engine() to inject new adapter.'),
E_USER_WARNING
);
public static function config($key, $config = null) {
static::$_dirtyConfig = true;
if ($config !== null && is_string($key)) {
static::$_config[$key] = (array) $config;
return;
}
static::$_config = array_merge(static::$_config, $key);
}

/**
Expand Down Expand Up @@ -278,19 +300,13 @@ public static function disable($streamName) {
}

/**
* Get/Set a logging engine.
* Get a logging engine.
*
* @see BaseLog
* @param string $name Key name of a configured adapter to get/set
* @param LogInterface $engine The logging instance to inject/add to Log.
* @param string $name Key name of a configured adapter to get.
* @return $mixed instance of BaseLog or false if not found
*/
public static function engine($name, $engine = null) {
public static function engine($name) {
static::_init();
if ($engine) {
static::$_registry->add($name, $engine);
return;
}
if (static::$_registry->{$name}) {
return static::$_registry->{$name};
}
Expand Down
41 changes: 13 additions & 28 deletions lib/Cake/Log/LogEngineRegistry.php
Expand Up @@ -24,7 +24,6 @@
*/
class LogEngineRegistry extends ObjectRegistry {


/**
* Resolve a logger classname.
*
Expand All @@ -34,6 +33,9 @@ class LogEngineRegistry extends ObjectRegistry {
* @return string|false Either the correct classname or false.
*/
protected function _resolveClassName($class) {
if (is_object($class)) {
return $class;
}
return App::classname($class, 'Log/Engine', 'Log');
}

Expand All @@ -54,45 +56,28 @@ protected function _throwMissingClassError($class, $plugin) {
* Create the logger instance.
*
* Part of the template method for Cake\Utility\ObjectRegistry::load()
* @param string $class The classname that is missing.
* @param string|LogInterface $class The classname or object to make.
* @param array $settings An array of settings to use for the logger.
* @return LogEngine The constructed logger class.
*/
protected function _create($class, $settings) {
$instance = new $class($settings);
$this->_checkInstance($instance);
return $instance;
}

/**
* Check an instance to see if it implements the LogInterface.
*
* @param mixed $instance The instance to check.
* @return void
* @throws Cake\Error\Exception when an object doesn't implement
* @throws Cake\Error\Exception when an object doesn't implement
* the correct interface.
*/
protected function _checkInstance($instance) {
protected function _create($class, $settings) {
if (is_object($class)) {
$instance = $class;
}
if (!isset($instance)) {
$instance = new $class($settings);
}
if ($instance instanceof LogInterface) {
return;
return $instance;
}
throw new Error\Exception(__d(
'cake_dev',
'Loggers must implement Cake\Log\LogInterface.'
));
}

/**
* Add a logger into a given name.
*
* @param string $name The name of the logger.
* @param Cake\Log\LogInterface $instance A logger implementing LogInterface.
*/
public function add($name, $instance) {
$this->_checkInstance($instance);
$this->_loaded[$name] = $instance;
}

/**
* Remove a single logger from the registry.
*
Expand Down

0 comments on commit d6c030d

Please sign in to comment.