Skip to content

Commit

Permalink
Added ability to add additional information to the logs via processors.
Browse files Browse the repository at this point in the history
Added backtrace processor to include backtraces in the logs.
Added requestid processor to include a unique id per request in the logs.
  • Loading branch information
Stefan Kleff committed Oct 10, 2012
1 parent 19f2be8 commit ae3c072
Show file tree
Hide file tree
Showing 8 changed files with 463 additions and 7 deletions.
119 changes: 112 additions & 7 deletions library/Zend/Log/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,27 @@ class Logger implements LoggerInterface
*/
protected $writers;

/**
* Processors
*
* @var SplPriorityQueue
*/
protected $processors;

/**
* Writer plugins
*
* @var WriterPluginManager
*/
protected $writerPlugins;

/**
* Processor plugins
*
* @var ProcessorPluginManager
*/
protected $processorPlugins;

/**
* Registered error handler
*
Expand All @@ -89,6 +103,7 @@ class Logger implements LoggerInterface
public function __construct()
{
$this->writers = new SplPriorityQueue();
$this->processors = new SplPriorityQueue();
}

/**
Expand Down Expand Up @@ -206,6 +221,90 @@ public function setWriters(SplPriorityQueue $writers)
return $this;
}


/**
* Get processor plugin manager
*
* @return ProcessorPluginManager
*/
public function getProcessorPluginManager()
{
if (null === $this->processorPlugins) {
$this->setProcessorPluginManager(new ProcessorPluginManager());
}
return $this->processorPlugins;
}

/**
* Set processor plugin manager
*
* @param string|ProcessorPluginManager $plugins
* @return Logger
* @throws Exception\InvalidArgumentException
*/
public function setProcessorPluginManager($plugins)
{
if (is_string($plugins)) {
$plugins = new $plugins;
}
if (!$plugins instanceof ProcessorPluginManager) {
throw new Exception\InvalidArgumentException(sprintf(
'processor plugin manager must extend %s\ProcessorPluginManager; received %s',
__NAMESPACE__,
is_object($plugins) ? get_class($plugins) : gettype($plugins)
));
}

$this->processorPlugins = $plugins;
return $this;
}

/**
* Get processor instance
*
* @param string $name
* @param array|null $options
* @return Processor\ProcessorInterface
*/
public function processorPlugin($name, array $options = null)
{
return $this->getProcessorPluginManager()->get($name, $options);
}

/**
* Add a processor to a logger
*
* @param string|Processor\ProcessorInterface $processor
* @param int $priority
* @param array|null $options
* @return Logger
* @throws Exception\InvalidArgumentException
*/
public function addProcessor($processor, $priority = 1, array $options = null)
{
if (is_string($processor)) {
$processor = $this->processorPlugin($processor, $options);
} elseif (!$processor instanceof Processor\ProcessorInterface) {
throw new Exception\InvalidArgumentException(sprintf(
'Processor must implement Zend\Log\ProcessorInterface; received "%s"',
is_object($processor) ? get_class($processor) : gettype($processor)
));
}
$this->processors->insert($processor, $priority);

return $this;
}

/**
* Get processors
*
* @return SplPriorityQueue
*/
public function getProcessors()
{
return $this->processors;
}

/**
* Add a message as a log entry
*
Expand Down Expand Up @@ -250,14 +349,20 @@ public function log($priority, $message, $extra = array())
$message = var_export($message, true);
}

$event = array(
'timestamp' => $timestamp,
'priority' => (int) $priority,
'priorityName' => $this->priorities[$priority],
'message' => (string) $message,
'extra' => $extra
);

foreach($this->processors->toArray() as $processor) {
$event = $processor->process($event);
}

foreach ($this->writers->toArray() as $writer) {
$writer->write(array(
'timestamp' => $timestamp,
'priority' => (int) $priority,
'priorityName' => $this->priorities[$priority],
'message' => (string) $message,
'extra' => $extra
));
$writer->write($event);
}

return $this;
Expand Down
84 changes: 84 additions & 0 deletions library/Zend/Log/Processor/Backtrace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Log
*/

namespace Zend\Log\Processor;

/**
* @category Zend
* @package Zend_Log
* @subpackage Processor
*/
class Backtrace implements ProcessorInterface
{
/**
* Maximum stack level of backtrace (PHP > 5.4.0)
* @var int
*/
protected $traceLimit = 10;

/**
* Classes within this namespace in the stack are ignored
* @var string
*/
protected $ignoredNamespace = 'Zend\\Log';

/**
* Adds the origin of the log() call to the event extras
*
* @param array $event event data
* @return array event data
*/
public function process(array $event)
{
$trace = $this->getBacktrace();

array_shift($trace); // ignore $this->getBacktrace();
array_shift($trace); // ignore $this->process()

$i = 0;
while (isset($trace[$i]['class']) && false !== strpos($trace[$i]['class'], $this->ignoredNamespace)) {
$i++;
}

$origin = array(
'file' => isset($trace[$i-1]['file']) ? $trace[$i-1]['file'] : null,
'line' => isset($trace[$i-1]['line']) ? $trace[$i-1]['line'] : null,
'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
);

if(!isset($event['extra'])) {
$event['extra'] = $origin;
} else {
$event['extra'] = array_merge($origin, $event['extra']);
}

return $event;
}

/**
* Provide backtrace as slim as posible
*
* @return array:
*/
protected function getBacktrace()
{
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $this->traceLimit);
}

if (version_compare(PHP_VERSION, '5.3.6') >= 0) {
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}

return debug_backtrace();
}

}
27 changes: 27 additions & 0 deletions library/Zend/Log/Processor/ProcessorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Log
*/

namespace Zend\Log\Processor;

/**
* @category Zend
* @package Zend_Log
*/
interface ProcessorInterface
{
/**
* Processes a log message before it is given to the writers
*
* @param array $event
* @return WriterInterface
*/
public function process(array $event);

}
61 changes: 61 additions & 0 deletions library/Zend/Log/Processor/RequestId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Log
*/

namespace Zend\Log\Processor;

/**
* @category Zend
* @package Zend_Log
* @subpackage Processor
*/
class RequestId implements ProcessorInterface
{

/**
* Adds a identfier for the request to the log.
* This enables to filter the log for messages belonging to a specific request
*
* @param array $event event data
* @return array event data
*/
public function process(array $event)
{
if(!isset($event['extra'])) {
$event['extra'] = array();
}

$event['extra']['requestId'] = $this->getIdentifier();
return $event;
}

/**
* Provide unique identifier for a request
*
* @return array:
*/
protected function getIdentifier()
{
$requestTime = (version_compare(PHP_VERSION, '5.4.0') >= 0) ? $_SERVER['REQUEST_TIME_FLOAT'] : $_SERVER['REQUEST_TIME'];
$remoteAddr = $this->isCli() ? 'local' : $_SERVER['REMOTE_ADDR'];

return md5($requestTime . $remoteAddr);
}

/**
* Check if PHP is run from command line
*
* @return boolean true if php is run from command line
*/
protected function isCli()
{
return php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']);
}

}
60 changes: 60 additions & 0 deletions library/Zend/Log/ProcessorPluginManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Log
*/

namespace Zend\Log;

use Zend\ServiceManager\AbstractPluginManager;

/**
* @category Zend
* @package Zend_Log
*/
class ProcessorPluginManager extends AbstractPluginManager
{
/**
* Default set of writers
*
* @var array
*/
protected $invokableClasses = array(
'backtrace' => 'Zend\Log\Processor\Backtrace',
'requestid' => 'Zend\Log\Processor\RequestId',
);

/**
* Allow many writers of the same type
*
* @var bool
*/
protected $shareByDefault = false;

/**
* Validate the plugin
*
* Checks that the processor loaded is an instance of Processor\ProcessorInterface.
*
* @param mixed $plugin
* @return void
* @throws Exception\InvalidArgumentException if invalid
*/
public function validatePlugin($plugin)
{
if ($plugin instanceof Processor\ProcessorInterface) {
// we're okay
return;
}

throw new Exception\InvalidArgumentException(sprintf(
'Plugin of type %s is invalid; must implement %s\Processor\ProcessorInterface',
(is_object($plugin) ? get_class($plugin) : gettype($plugin)),
__NAMESPACE__
));
}
}
Loading

0 comments on commit ae3c072

Please sign in to comment.