diff --git a/src/Formatter/Base.php b/src/Formatter/Base.php index a495dfd3..a7fd4acf 100644 --- a/src/Formatter/Base.php +++ b/src/Formatter/Base.php @@ -32,10 +32,18 @@ class Base implements FormatterInterface * Class constructor * * @see http://php.net/manual/en/function.date.php - * @param null|string $dateTimeFormat Format for DateTime objects + * @param null|string|array|Traversable $dateTimeFormat Format for DateTime objects */ public function __construct($dateTimeFormat = null) { + if ($dateTimeFormat instanceof Traversable) { + $dateTimeFormat = iterator_to_array($dateTimeFormat); + } + + if (is_array($dateTimeFormat)) { + $dateTimeFormat = isset($dateTimeFormat['dateTimeFormat'])? $dateTimeFormat['dateTimeFormat'] : null; + } + if (null !== $dateTimeFormat) { $this->dateTimeFormat = $dateTimeFormat; } diff --git a/src/Formatter/ChromePhp.php b/src/Formatter/ChromePhp.php new file mode 100644 index 00000000..158f5b09 --- /dev/null +++ b/src/Formatter/ChromePhp.php @@ -0,0 +1,51 @@ +setDateTimeFormat($dateTimeFormat); } diff --git a/src/Formatter/FirePhp.php b/src/Formatter/FirePhp.php index 0a21cde1..51b1e3d3 100644 --- a/src/Formatter/FirePhp.php +++ b/src/Formatter/FirePhp.php @@ -20,12 +20,20 @@ class FirePhp implements FormatterInterface /** * Formats the given event data into a single line to be written by the writer. * - * @param array $event The event data which should be formatted. - * @return string + * @param array $event The event data which should be formatted. + * @return array line message and optionally label if 'extra' data exists. */ public function format($event) { - return $event['message']; + $label = null; + if ( !empty($event['extra']) ) { + $line = $event['extra']; + $label = $event['message']; + } else { + $line = $event['message']; + } + + return array($line, $label); } /** @@ -41,7 +49,7 @@ public function getDateTimeFormat() /** * This method is implemented for FormatterInterface but not used. * - * @param string $dateTimeFormat + * @param string $dateTimeFormat * @return FormatterInterface */ public function setDateTimeFormat($dateTimeFormat) diff --git a/src/Formatter/Simple.php b/src/Formatter/Simple.php index e7a3ec37..5392ad9e 100644 --- a/src/Formatter/Simple.php +++ b/src/Formatter/Simple.php @@ -10,6 +10,7 @@ namespace Zend\Log\Formatter; +use Traversable; use Zend\Log\Exception; /** @@ -38,6 +39,15 @@ class Simple extends Base */ public function __construct($format = null, $dateTimeFormat = null) { + if ($format instanceof Traversable) { + $format = iterator_to_array($format); + } + + if (is_array($format)) { + $dateTimeFormat = isset($format['dateTimeFormat'])? $format['dateTimeFormat'] : null; + $format = isset($format['format'])? $format['format'] : null; + } + if (isset($format) && !is_string($format)) { throw new Exception\InvalidArgumentException('Format must be a string'); } diff --git a/src/Formatter/Xml.php b/src/Formatter/Xml.php index c28d849e..27bed191 100644 --- a/src/Formatter/Xml.php +++ b/src/Formatter/Xml.php @@ -190,7 +190,7 @@ public function format($event) } elseif ($key == "extra" && empty($value)) { continue; } - $elt->appendChild(new DOMElement($key, (string)$value)); + $elt->appendChild(new DOMElement($key, (string) $value)); } } diff --git a/src/Logger.php b/src/Logger.php index 696d568b..5c9427a0 100644 --- a/src/Logger.php +++ b/src/Logger.php @@ -59,6 +59,13 @@ class Logger implements LoggerInterface */ protected $writers; + /** + * Processors + * + * @var SplPriorityQueue + */ + protected $processors; + /** * Writer plugins * @@ -66,6 +73,13 @@ class Logger implements LoggerInterface */ protected $writerPlugins; + /** + * Processor plugins + * + * @var ProcessorPluginManager + */ + protected $processorPlugins; + /** * Registered error handler * @@ -83,12 +97,50 @@ class Logger implements LoggerInterface /** * Constructor * - * @todo support configuration (writers, dateTimeFormat, and writer plugin manager) + * Set options for an logger. Accepted options are: + * - writers: array of writers to add to this logger + * - exceptionhandler: if true register this logger as exceptionhandler + * - errorhandler: if true register this logger as errorhandler + * + * @param array|\Traversable $options * @return Logger + * @throws Exception\InvalidArgumentException */ - public function __construct() + public function __construct(array $options = null) { $this->writers = new SplPriorityQueue(); + + if ($options instanceof Traversable) { + $options = ArrayUtils::iteratorToArray($options); + } + + if (is_array($options)) { + + if(isset($options['writers']) && is_array($options['writers'])) { + foreach($options['writers'] as $writer) { + + if(!isset($writer['name'])) { + throw new Exception\InvalidArgumentException('Options must contain a name for the writer'); + } + + $priority = (isset($writer['priority'])) ? $writer['priority'] : null; + $writerOptions = (isset($writer['options'])) ? $writer['options'] : null; + + $this->addWriter($writer['name'], $priority, $writerOptions); + } + } + + if(isset($options['exceptionhandler']) && $options['exceptionhandler'] === true) { + self::registerExceptionHandler($this); + } + + if(isset($options['errorhandler']) && $options['errorhandler'] === true) { + self::registerErrorHandler($this); + } + + } + + $this->processors = new SplPriorityQueue(); } /** @@ -206,6 +258,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 * @@ -250,14 +386,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; @@ -354,7 +496,7 @@ public function debug($message, $extra = array()) public static function registerErrorHandler(Logger $logger) { // Only register once per instance - if (self::$registeredErrorHandler) { + if (static::$registeredErrorHandler) { return false; } @@ -377,7 +519,7 @@ public static function registerErrorHandler(Logger $logger) E_USER_DEPRECATED => self::DEBUG ); - set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) use ($errorHandlerMap, $logger) { + set_error_handler(function ($errno, $errstr, $errfile, $errline, $errcontext) use ($errorHandlerMap, $logger) { $errorLevel = error_reporting(); if ($errorLevel & $errno) { @@ -394,7 +536,7 @@ public static function registerErrorHandler(Logger $logger) )); } }); - self::$registeredErrorHandler = true; + static::$registeredErrorHandler = true; return true; } @@ -405,7 +547,7 @@ public static function registerErrorHandler(Logger $logger) public static function unregisterErrorHandler() { restore_error_handler(); - self::$registeredErrorHandler = false; + static::$registeredErrorHandler = false; } /** @@ -419,7 +561,7 @@ public static function unregisterErrorHandler() public static function registerExceptionHandler(Logger $logger) { // Only register once per instance - if (self::$registeredExceptionHandler) { + if (static::$registeredExceptionHandler) { return false; } @@ -438,7 +580,7 @@ public static function registerExceptionHandler(Logger $logger) } $logger->log(Logger::ERR, $exception->getMessage(), $extra); }); - self::$registeredExceptionHandler = true; + static::$registeredExceptionHandler = true; return true; } @@ -448,6 +590,6 @@ public static function registerExceptionHandler(Logger $logger) public static function unregisterExceptionHandler() { restore_exception_handler(); - self::$registeredExceptionHandler = false; + static::$registeredExceptionHandler = false; } } diff --git a/src/LoggerAwareTrait.php b/src/LoggerAwareTrait.php new file mode 100644 index 00000000..33cbfe43 --- /dev/null +++ b/src/LoggerAwareTrait.php @@ -0,0 +1,38 @@ +logger = $logger; + + return $this; + } +} diff --git a/src/LoggerServiceFactory.php b/src/LoggerServiceFactory.php new file mode 100644 index 00000000..e2e151a1 --- /dev/null +++ b/src/LoggerServiceFactory.php @@ -0,0 +1,32 @@ +get('Config'); + $logConfig = isset($config['log']) ? $config['log'] : array(); + $logger = new Logger($logConfig); + return $logger; + } +} diff --git a/src/Processor/Backtrace.php b/src/Processor/Backtrace.php new file mode 100644 index 00000000..9c566127 --- /dev/null +++ b/src/Processor/Backtrace.php @@ -0,0 +1,85 @@ + 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, + ); + + $extra = $origin; + if (isset($event['extra'])) { + $extra = array_merge($origin, $event['extra']); + } + $event['extra'] = $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(); + } +} diff --git a/src/Processor/ProcessorInterface.php b/src/Processor/ProcessorInterface.php new file mode 100644 index 00000000..27de2ac6 --- /dev/null +++ b/src/Processor/ProcessorInterface.php @@ -0,0 +1,27 @@ +getIdentifier(); + return $event; + } + + /** + * Provide unique identifier for a request + * + * @return string + */ + protected function getIdentifier() + { + if ($this->identifier) { + return $this->identifier; + } + + $requestTime = (version_compare(PHP_VERSION, '5.4.0') >= 0) + ? $_SERVER['REQUEST_TIME_FLOAT'] + : $_SERVER['REQUEST_TIME']; + + if (Console::isConsole()) { + $this->identifier = md5($requestTime); + return $this->identifier; + } + + if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $this->identifier = md5($requestTime . $_SERVER['HTTP_X_FORWARDED_FOR']); + return $this->identifier; + } + + $this->identifier = md5($requestTime . $_SERVER['REMOTE_ADDR']); + return $this->identifier; + } +} diff --git a/src/ProcessorPluginManager.php b/src/ProcessorPluginManager.php new file mode 100644 index 00000000..86b1cf9c --- /dev/null +++ b/src/ProcessorPluginManager.php @@ -0,0 +1,60 @@ + '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__ + )); + } +} diff --git a/src/Writer/AbstractWriter.php b/src/Writer/AbstractWriter.php index d1fa2db4..6ac12133 100644 --- a/src/Writer/AbstractWriter.php +++ b/src/Writer/AbstractWriter.php @@ -10,9 +10,10 @@ namespace Zend\Log\Writer; +use Traversable; use Zend\Log\Exception; use Zend\Log\Filter; -use Zend\Log\Formatter\FormatterInterface as Formatter; +use Zend\Log\Formatter; use Zend\Stdlib\ErrorHandler; /** @@ -29,6 +30,13 @@ abstract class AbstractWriter implements WriterInterface */ protected $filterPlugins; + /** + * Formatter plugins + * + * @var FormatterPluginManager + */ + protected $formatterPlugins; + /** * Filter chain * @@ -57,6 +65,59 @@ abstract class AbstractWriter implements WriterInterface */ protected $errorsToExceptionsConversionLevel = E_WARNING; + /** + * Constructor + * + * Set options for an writer. Accepted options are: + * - filters: array of filters to add to this filter + * - formatter: formatter for this writer + * + * @param array|\Traversable $options + * @return Logger + * @throws Exception\InvalidArgumentException + */ + public function __construct($options = null) + { + if ($options instanceof Traversable) { + $options = iterator_to_array($options); + } + + if (is_array($options)) { + + if(isset($options['filters'])) { + $filters = $options['filters']; + if(is_string($filters) || $filters instanceof Filter\FilterInterface) { + $this->addFilter($filters); + } elseif(is_array($filters)) { + foreach($filters as $filter) { + if(is_string($filter) || $filter instanceof Filter\FilterInterface) { + $this->addFilter($filter); + } elseif(is_array($filter)) { + if(!isset($filter['name'])) { + throw new Exception\InvalidArgumentException('Options must contain a name for the filter'); + } + $filterOptions = (isset($filter['options'])) ? $filter['options'] : null; + $this->addFilter($filter['name'], $filterOptions); + } + } + } + } + + if(isset($options['formatter'])) { + $formatter = $options['formatter']; + if(is_string($formatter) || $formatter instanceof Formatter\FormatterInterface) { + $this->setFormatter($formatter); + } elseif(is_array($formatter)) { + if(!isset($formatter['name'])) { + throw new Exception\InvalidArgumentException('Options must contain a name for the formatter'); + } + $formatterOptions = (isset($formatter['options'])) ? $formatter['options'] : null; + $this->setFormatter($formatter['name'], $formatterOptions); + } + } + } + } + /** * Add a filter specific to this writer. * @@ -77,7 +138,8 @@ public function addFilter($filter, array $options = null) if (!$filter instanceof Filter\FilterInterface) { throw new Exception\InvalidArgumentException(sprintf( - 'Writer must implement Zend\Log\Filter\FilterInterface; received "%s"', + 'Writer must implement %s\Filter\FilterInterface; received "%s"', + __NAMESPACE__, is_object($filter) ? get_class($filter) : gettype($filter) )); } @@ -135,6 +197,56 @@ public function filterPlugin($name, array $options = null) return $this->getFilterPluginManager()->get($name, $options); } + /** + * Get formatter plugin manager + * + * @return FormatterPluginManager + */ + public function getFormatterPluginManager() + { + if (null === $this->formatterPlugins) { + $this->setFormatterPluginManager(new FormatterPluginManager()); + } + return $this->formatterPlugins; + } + + /** + * Set formatter plugin manager + * + * @param string|FormatterPluginManager $plugins + * @return self + * @throws Exception\InvalidArgumentException + */ + public function setFormatterPluginManager($plugins) + { + if (is_string($plugins)) { + $plugins = new $plugins; + } + if (!$plugins instanceof FormatterPluginManager) { + throw new Exception\InvalidArgumentException(sprintf( + 'Writer plugin manager must extend %s\FormatterPluginManager; received %s', + __NAMESPACE__, + is_object($plugins) ? get_class($plugins) : gettype($plugins) + )); + } + + $this->formatterPlugins = $plugins; + return $this; + } + + + /** + * Get formatter instance + * + * @param string $name + * @param array|null $options + * @return Formatter\FormatterInterface + */ + public function formatterPlugin($name, array $options = null) + { + return $this->getFormatterPluginManager()->get($name, $options); + } + /** * Log a message to this writer. * @@ -178,11 +290,24 @@ public function write(array $event) /** * Set a new formatter for this writer * - * @param Formatter $formatter + * @param string|Formatter\FormatterInterface $formatter * @return self + * @throws Exception\InvalidArgumentException */ - public function setFormatter(Formatter $formatter) + public function setFormatter($formatter, array $options = null) { + if (is_string($formatter)) { + $formatter = $this->formatterPlugin($formatter, $options); + } + + if (!$formatter instanceof Formatter\FormatterInterface) { + throw new Exception\InvalidArgumentException(sprintf( + 'Formatter must implement %s\Formatter\FormatterInterface; received "%s"', + __NAMESPACE__, + is_object($formatter) ? get_class($formatter) : gettype($formatter) + )); + } + $this->formatter = $formatter; return $this; } diff --git a/src/Writer/ChromePhp.php b/src/Writer/ChromePhp.php new file mode 100644 index 00000000..6aa4dbd2 --- /dev/null +++ b/src/Writer/ChromePhp.php @@ -0,0 +1,120 @@ +chromephp = $instance === null ? $this->getChromePhp() : $instance; + $this->formatter = new ChromePhpFormatter(); + } + + /** + * Write a message to the log. + * + * @param array $event event data + * @return void + */ + protected function doWrite(array $event) + { + $line = $this->formatter->format($event); + + switch ($event['priority']) { + case Logger::EMERG: + case Logger::ALERT: + case Logger::CRIT: + case Logger::ERR: + $this->chromephp->error($line); + break; + case Logger::WARN: + $this->chromephp->warn($line); + break; + case Logger::NOTICE: + case Logger::INFO: + $this->chromephp->info($line); + break; + case Logger::DEBUG: + $this->chromephp->trace($line); + break; + default: + $this->chromephp->log($line); + break; + } + } + + /** + * Gets the ChromePhpInterface instance that is used for logging. + * + * @return ChromePhpInterface + */ + public function getChromePhp() + { + // Remember: class names in strings are absolute; thus the class_exists + // here references the canonical name for the ChromePhp class + if (!$this->chromephp instanceof ChromePhpInterface + && class_exists('ChromePhp') + ) { + $this->setChromePhp(new ChromePhpBridge()); + } + return $this->chromephp; + } + + /** + * Sets the ChromePhpInterface instance that is used for logging. + * + * @param ChromePhpInterface $instance The instance to set. + * @return ChromePhp + */ + public function setChromePhp(ChromePhpInterface $instance) + { + $this->chromephp = $instance; + return $this; + } +} diff --git a/src/Writer/ChromePhp/ChromePhpBridge.php b/src/Writer/ChromePhp/ChromePhpBridge.php new file mode 100644 index 00000000..d6a97655 --- /dev/null +++ b/src/Writer/ChromePhp/ChromePhpBridge.php @@ -0,0 +1,71 @@ +writer = $writer; + + if ($writer instanceof Traversable) { + $writer = ArrayUtils::iteratorToArray($writer); + } + + if (is_array($writer)) { + $filterOrPriority = isset($writer['priority']) ? $writer['priority'] : null; + $bufferSize = isset($writer['bufferSize']) ? $writer['bufferSize'] : null; + $writer = isset($writer['writer']) ? $writer['writer'] : null; + } + + if (null === $filterOrPriority) { + $filterOrPriority = new PriorityFilter(Logger::WARN); + } elseif (!$filterOrPriority instanceof FilterInterface) { + $filterOrPriority = new PriorityFilter($filterOrPriority); + } + + if (is_array($writer) && isset($writer['name'])) { + $this->setWriter($writer['name'], $writer['options']); + } else { + $this->setWriter($writer); + } + $this->addFilter($filterOrPriority); + $this->bufferSize = $bufferSize; + } + + /** + * Set a new formatter for this writer + * + * @param string|Formatter\FormatterInterface $formatter + * @return self + * @throws Exception\InvalidArgumentException + */ + public function setWriter($writer, array $options = null) + { + if (is_string($writer)) { + $writer = $this->writerPlugin($writer, $options); + } + + if (!$writer instanceof WriterInterface) { + throw new Exception\InvalidArgumentException(sprintf( + 'Formatter must implement %s\Formatter\FormatterInterface; received "%s"', + __NAMESPACE__, + is_object($writer) ? get_class($writer) : gettype($writer) + )); + } + + $this->writer = $writer; + return $this; + } + + /** + * Get writer plugin manager + * + * @return WriterPluginManager + */ + public function getWriterPluginManager() + { + if (null === $this->writerPlugins) { + $this->setWriterPluginManager(new WriterPluginManager()); + } + return $this->writerPlugins; + } + + /** + * Set writer plugin manager + * + * @param string|WriterPluginManager $plugins + * @return Logger + * @throws Exception\InvalidArgumentException + */ + public function setWriterPluginManager($plugins) + { + if (is_string($plugins)) { + $plugins = new $plugins; + } + if (!$plugins instanceof WriterPluginManager) { + throw new Exception\InvalidArgumentException(sprintf( + 'Writer plugin manager must extend %s\WriterPluginManager; received %s', + __NAMESPACE__, + is_object($plugins) ? get_class($plugins) : gettype($plugins) + )); + } + + $this->writerPlugins = $plugins; + return $this; + } + + /** + * Get writer instance + * + * @param string $name + * @param array|null $options + * @return Writer\WriterInterface + */ + public function writerPlugin($name, array $options = null) + { + return $this->getWriterPluginManager()->get($name, $options); + } + + /** + * Log a message to this writer. + * + * @param array $event log data event + * @return void + */ + public function write(array $event) + { + $this->doWrite($event); + } + + /** + * Check if buffered data should be flushed + * + * @param array $event event data + * @return boolean true if buffered data should be flushed + */ + protected function isActivated(array $event) + { + foreach ($this->filters as $filter) { + if (!$filter->filter($event)) { + return false; + } + } + return true; + } + + /** + * Write message to buffer or delegate event data to the wrapped writer + * + * @param array $event event data + * @return void + */ + protected function doWrite(array $event) + { + if (!$this->buffering) { + $this->writer->write($event); + return; + } + + $this->buffer[] = $event; + + if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) { + array_shift($this->buffer); + } + + if (!$this->isActivated($event)) { + return; + } + + $this->buffering = false; + + foreach ($this->buffer as $bufferedEvent) { + $this->writer->write($bufferedEvent); + } + } + + /** + * Resets the state of the handler. + * Stops forwarding records to the wrapped writer + */ + public function reset() + { + $this->buffering = true; + } + + /** + * Stub in accordance to parent method signature. + * Fomatters must be set on the wrapped writer. + * + * @param string|Formatter\FormatterInterface $formatter + * @return WriterInterface + */ + public function setFormatter($formatter) + { + return $this->writer; + } + + /** + * Record shutdown + * + * @return void + */ + public function shutdown() + { + $this->writer->shutdown(); + $this->buffer = null; + } +} diff --git a/src/Writer/FirePhp.php b/src/Writer/FirePhp.php index c4c73e5d..ffa8c9b7 100644 --- a/src/Writer/FirePhp.php +++ b/src/Writer/FirePhp.php @@ -10,10 +10,12 @@ namespace Zend\Log\Writer; +use Traversable; use FirePHP as FirePHPService; use Zend\Log\Formatter\FirePhp as FirePhpFormatter; use Zend\Log\Logger; use Zend\Log\Exception; +use FirePhp\FirePhpInterface; /** * @category Zend @@ -32,11 +34,25 @@ class FirePhp extends AbstractWriter /** * Initializes a new instance of this class. * - * @param null|FirePhp\FirePhpInterface $instance An instance of FirePhpInterface + * @param null|FirePhp\FirePhpInterface|array|Traversable $instance An instance of FirePhpInterface * that should be used for logging */ - public function __construct(FirePhp\FirePhpInterface $instance = null) + public function __construct($instance = null) { + if ($instance instanceof Traversable) { + $instance = iterator_to_array($instance); + } + + if (is_array($instance)) { + parent::__construct($instance); + $instance = isset($instance['instance']) ? $instance['instance'] : null; + } + + if ($instance instanceof FirePhpInterface) { + throw new Exception\InvalidArgumentException('You must pass a valid FirePhp\FirePhpInterface'); + } + + $this->firephp = $instance; $this->formatter = new FirePhpFormatter(); } @@ -44,7 +60,7 @@ public function __construct(FirePhp\FirePhpInterface $instance = null) /** * Write a message to the log. * - * @param array $event event data + * @param array $event event data * @return void */ protected function doWrite(array $event) @@ -55,27 +71,27 @@ protected function doWrite(array $event) return; } - $line = $this->formatter->format($event); + list($line, $label) = $this->formatter->format($event); switch ($event['priority']) { case Logger::EMERG: case Logger::ALERT: case Logger::CRIT: case Logger::ERR: - $firephp->error($line); + $firephp->error($line, $label); break; case Logger::WARN: - $firephp->warn($line); + $firephp->warn($line, $label); break; case Logger::NOTICE: case Logger::INFO: - $firephp->info($line); + $firephp->info($line, $label); break; case Logger::DEBUG: $firephp->trace($line); break; default: - $firephp->log($line); + $firephp->log($line, $label); break; } } @@ -117,6 +133,7 @@ public function getFirePhp() public function setFirePhp(FirePhp\FirePhpInterface $instance) { $this->firephp = $instance; + return $this; } } diff --git a/src/Writer/FormatterPluginManager.php b/src/Writer/FormatterPluginManager.php new file mode 100644 index 00000000..243a2ef4 --- /dev/null +++ b/src/Writer/FormatterPluginManager.php @@ -0,0 +1,66 @@ + 'Zend\Log\Formatter\Base', + 'simple' => 'Zend\Log\Formatter\Simple', + 'xml' => 'Zend\Log\Formatter\Xml', + 'db' => 'Zend\Log\Formatter\Db', + 'errorhandler' => 'Zend\Log\Formatter\ErrorHandler', + 'exceptionhandler' => 'Zend\Log\Formatter\ExceptionHandler', + ); + + /** + * Allow many filters of the same type + * + * @var bool + */ + protected $shareByDefault = false; + + /** + * Validate the plugin + * + * Checks that the formatter loaded is an instance of Formatter\FormatterInterface. + * + * @param mixed $plugin + * @return void + * @throws Exception\InvalidArgumentException if invalid + */ + public function validatePlugin($plugin) + { + if ($plugin instanceof Formatter\FormatterInterface) { + // we're okay + return; + } + + throw new Exception\InvalidArgumentException(sprintf( + 'Plugin of type %s is invalid; must implement %s\Formatter\FormatterInterface', + (is_object($plugin) ? get_class($plugin) : gettype($plugin)), + __NAMESPACE__ + )); + } +} diff --git a/src/Writer/Mail.php b/src/Writer/Mail.php index becc6184..98d0582a 100644 --- a/src/Writer/Mail.php +++ b/src/Writer/Mail.php @@ -85,6 +85,7 @@ public function __construct($mail, Transport\TransportInterface $transport = nul } if (is_array($mail)) { + parent::__construct($mail); $transport = isset($mail['transport']) ? $mail['transport'] : null; $mail = isset($mail['mail']) ? $mail['mail'] : null; } @@ -110,7 +111,9 @@ public function __construct($mail, Transport\TransportInterface $transport = nul } $this->setTransport($transport); - $this->formatter = new SimpleFormatter(); + if($this->formatter === null) { + $this->formatter = new SimpleFormatter(); + } } /** diff --git a/src/Writer/MongoDB.php b/src/Writer/MongoDB.php index c6fbe40d..bfaad10b 100644 --- a/src/Writer/MongoDB.php +++ b/src/Writer/MongoDB.php @@ -15,8 +15,7 @@ use Mongo; use MongoDate; use Traversable; -use Zend\Log\Exception\InvalidArgumentException; -use Zend\Log\Exception\RuntimeException; +use Zend\Log\Exception; use Zend\Log\Formatter\FormatterInterface; use Zend\Stdlib\ArrayUtils; @@ -52,27 +51,30 @@ class MongoDB extends AbstractWriter * @param array $saveOptions * @throws Exception\InvalidArgumentException */ - public function __construct($mongo, $database, $collection, array $saveOptions = array()) + public function __construct($mongo, $database = null, $collection = null, array $saveOptions = array()) { if ($mongo instanceof Traversable) { // Configuration may be multi-dimensional due to save options $mongo = ArrayUtils::iteratorToArray($mongo); } if (is_array($mongo)) { + parent::__construct($mongo); $saveOptions = isset($mongo['save_options']) ? $mongo['save_options'] : null; $collection = isset($mongo['collection']) ? $mongo['collection'] : null; - if (null === $collection) { - throw new Exception\InvalidArgumentException( + $database = isset($mongo['database']) ? $mongo['database'] : null; + $mongo = isset($mongo['mongo']) ? $mongo['mongo'] : null; + } + + if (null === $collection) { + throw new Exception\InvalidArgumentException( 'The collection parameter cannot be empty' - ); - } - $database = isset($mongo['database']) ? $mongo['database'] : null; - if (null === $database) { - throw new Exception\InvalidArgumentException( + ); + } + + if (null === $database) { + throw new Exception\InvalidArgumentException( 'The database parameter cannot be empty' - ); - } - $mongo = isset($mongo['mongo']) ? $mongo['mongo'] : null; + ); } if (!($mongo instanceof Mongo)) { @@ -89,13 +91,12 @@ public function __construct($mongo, $database, $collection, array $saveOptions = /** * This writer does not support formatting. * - * @param Zend\Log\Formatter\FormatterInterface $formatter - * @return void - * @throws Zend\Log\Exception\InvalidArgumentException + * @param string|Zend\Log\Formatter\FormatterInterface $formatter + * @return WriterInterface */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter($formatter) { - throw new InvalidArgumentException(get_class() . ' does not support formatting'); + return $this; } /** diff --git a/src/Writer/Stream.php b/src/Writer/Stream.php index 96e71aa0..1da249d7 100644 --- a/src/Writer/Stream.php +++ b/src/Writer/Stream.php @@ -53,6 +53,7 @@ public function __construct($streamOrUrl, $mode = null, $logSeparator = null) } if (is_array($streamOrUrl)) { + parent::__construct($streamOrUrl); $mode = isset($streamOrUrl['mode']) ? $streamOrUrl['mode'] : null; $logSeparator = isset($streamOrUrl['log_separator']) ? $streamOrUrl['log_separator'] : null; $streamOrUrl = isset($streamOrUrl['stream']) ? $streamOrUrl['stream'] : null; @@ -96,7 +97,9 @@ public function __construct($streamOrUrl, $mode = null, $logSeparator = null) $this->setLogSeparator($logSeparator); } - $this->formatter = new SimpleFormatter(); + if($this->formatter === null) { + $this->formatter = new SimpleFormatter(); + } } /** diff --git a/src/Writer/Syslog.php b/src/Writer/Syslog.php index 2326a2ed..8fc09d0c 100644 --- a/src/Writer/Syslog.php +++ b/src/Writer/Syslog.php @@ -10,6 +10,7 @@ namespace Zend\Log\Writer; +use Traversable; use Zend\Log\Exception; use Zend\Log\Logger; use Zend\Log\Formatter\Simple as SimpleFormatter; @@ -87,23 +88,34 @@ class Syslog extends AbstractWriter * @param array $params Array of options; may include "application" and "facility" keys * @return Syslog */ - public function __construct(array $params = array()) + public function __construct($params = null) { - if (isset($params['application'])) { - $this->appName = $params['application']; + if ($params instanceof Traversable) { + $params = iterator_to_array($params); } $runInitializeSyslog = true; - if (isset($params['facility'])) { - $this->setFacility($params['facility']); - $runInitializeSyslog = false; + + if (is_array($params)) { + parent::__construct($params); + + if (isset($params['application'])) { + $this->appName = $params['application']; + } + + if (isset($params['facility'])) { + $this->setFacility($params['facility']); + $runInitializeSyslog = false; + } } if ($runInitializeSyslog) { $this->initializeSyslog(); } - $this->setFormatter(new SimpleFormatter('%message%')); + if($this->formatter === null) { + $this->setFormatter(new SimpleFormatter('%message%')); + } } /** @@ -149,8 +161,8 @@ protected function initializeValidFacilities() */ protected function initializeSyslog() { - self::$lastApplication = $this->appName; - self::$lastFacility = $this->facility; + static::$lastApplication = $this->appName; + static::$lastFacility = $this->facility; openlog($this->appName, LOG_PID, $this->facility); } @@ -231,8 +243,8 @@ protected function doWrite(array $event) $priority = $this->defaultPriority; } - if ($this->appName !== self::$lastApplication - || $this->facility !== self::$lastFacility + if ($this->appName !== static::$lastApplication + || $this->facility !== static::$lastFacility ) { $this->initializeSyslog(); } diff --git a/src/Writer/WriterInterface.php b/src/Writer/WriterInterface.php index 9073775a..e625f68c 100644 --- a/src/Writer/WriterInterface.php +++ b/src/Writer/WriterInterface.php @@ -22,7 +22,7 @@ interface WriterInterface /** * Add a log filter to the writer * - * @param int|Filter $filter + * @param int|string|Filter $filter * @return WriterInterface */ public function addFilter($filter); @@ -30,10 +30,10 @@ public function addFilter($filter); /** * Set a message formatter for the writer * - * @param Formatter $formatter + * @param string|Formatter $formatter * @return WriterInterface */ - public function setFormatter(Formatter $formatter); + public function setFormatter($formatter); /** * Write a log message diff --git a/src/Writer/ZendMonitor.php b/src/Writer/ZendMonitor.php index 3f5626c8..9a976d3b 100644 --- a/src/Writer/ZendMonitor.php +++ b/src/Writer/ZendMonitor.php @@ -36,8 +36,10 @@ class ZendMonitor extends AbstractWriter * * @return ZendMonitor */ - public function __construct() + public function __construct($options = null) { + parent::__construct($options); + if (!function_exists('monitor_custom_event')) { $this->isEnabled = false; } diff --git a/src/WriterPluginManager.php b/src/WriterPluginManager.php index 68ee6281..bd146dea 100644 --- a/src/WriterPluginManager.php +++ b/src/WriterPluginManager.php @@ -24,14 +24,16 @@ class WriterPluginManager extends AbstractPluginManager * @var array */ protected $invokableClasses = array( - 'db' => 'Zend\Log\Writer\Db', - 'firephp' => 'Zend\Log\Writer\FirePhp', - 'mail' => 'Zend\Log\Writer\Mail', - 'mock' => 'Zend\Log\Writer\Mock', - 'null' => 'Zend\Log\Writer\Null', - 'stream' => 'Zend\Log\Writer\Stream', - 'syslog' => 'Zend\Log\Writer\Syslog', - 'zendmonitor' => 'Zend\Log\Writer\ZendMonitor', + 'chromephp' => 'Zend\Log\Writer\ChromePhp', + 'db' => 'Zend\Log\Writer\Db', + 'fingerscrossed' => 'Zend\Log\Writer\FingersCrossed', + 'firephp' => 'Zend\Log\Writer\FirePhp', + 'mail' => 'Zend\Log\Writer\Mail', + 'mock' => 'Zend\Log\Writer\Mock', + 'null' => 'Zend\Log\Writer\Null', + 'stream' => 'Zend\Log\Writer\Stream', + 'syslog' => 'Zend\Log\Writer\Syslog', + 'zendmonitor' => 'Zend\Log\Writer\ZendMonitor', ); /** diff --git a/test/Filter/ValidatorTest.php b/test/Filter/ValidatorTest.php index c34174ab..9cd55cae 100644 --- a/test/Filter/ValidatorTest.php +++ b/test/Filter/ValidatorTest.php @@ -35,8 +35,8 @@ public function testValidatorFilter() public function testValidatorChain() { $validatorChain = new ValidatorChain(); - $validatorChain->addValidator(new DigitsFilter()); - $validatorChain->addValidator(new Int()); + $validatorChain->attach(new DigitsFilter()); + $validatorChain->attach(new Int()); $filter = new Validator($validatorChain); $this->assertTrue($filter->filter(array('message' => '123'))); $this->assertFalse($filter->filter(array('message' => 'test'))); diff --git a/test/Formatter/BaseTest.php b/test/Formatter/BaseTest.php index d5d5f8a5..a5e1396b 100644 --- a/test/Formatter/BaseTest.php +++ b/test/Formatter/BaseTest.php @@ -64,6 +64,17 @@ public function testSetDateTimeFormat($dateTimeFormat) $this->assertEquals($dateTimeFormat, $formatter->getDateTimeFormat()); } + /** + * @dataProvider provideDateTimeFormats + */ + public function testSetDateTimeFormatInConstructor($dateTimeFormat) + { + $options = array('dateTimeFormat' => $dateTimeFormat); + $formatter = new BaseFormatter($options); + + $this->assertEquals($dateTimeFormat, $formatter->getDateTimeFormat()); + } + public function testFormatAllTypes() { $datetime = new DateTime(); diff --git a/test/Formatter/FirePhpTest.php b/test/Formatter/FirePhpTest.php index 9fef4bf5..24165d31 100644 --- a/test/Formatter/FirePhpTest.php +++ b/test/Formatter/FirePhpTest.php @@ -33,14 +33,39 @@ */ class FirePhpTest extends \PHPUnit_Framework_TestCase { - public function testFormat() + public function testFormatWithExtraData() + { + $fields = array( 'message' => 'foo', + 'extra' => new \stdClass() ); + + $f = new FirePhp(); + list($line, $label) = $f->format($fields); + + $this->assertContains($fields['message'], $label); + $this->assertEquals($fields['extra'], $line); + } + + public function testFormatWithoutExtra() { $fields = array( 'message' => 'foo' ); $f = new FirePhp(); - $line = $f->format($fields); + list($line, $label) = $f->format($fields); + + $this->assertContains($fields['message'], $line); + $this->assertNull($label); + } + + public function testFormatWithEmptyExtra() + { + $fields = array( 'message' => 'foo', + 'extra' => array() ); + + $f = new FirePhp(); + list($line, $label) = $f->format($fields); $this->assertContains($fields['message'], $line); + $this->assertNull($label); } public function testSetDateTimeFormatDoesNothing() diff --git a/test/Formatter/SimpleTest.php b/test/Formatter/SimpleTest.php index 628912ee..d3bcc95e 100644 --- a/test/Formatter/SimpleTest.php +++ b/test/Formatter/SimpleTest.php @@ -28,6 +28,18 @@ public function testConstructorThrowsOnBadFormatString() new Simple(1); } + /** + * @dataProvider provideDateTimeFormats + */ + public function testConstructorWithOptions($dateTimeFormat) + { + $options = array('dateTimeFormat' => $dateTimeFormat, 'format' => '%timestamp%'); + $formatter = new Simple($options); + + $this->assertEquals($dateTimeFormat, $formatter->getDateTimeFormat()); + $this->assertAttributeEquals('%timestamp%', 'format', $formatter); + } + public function testDefaultFormat() { $date = new DateTime('2012-08-28T18:15:00Z'); diff --git a/test/LoggerAwareTraitTest.php b/test/LoggerAwareTraitTest.php new file mode 100644 index 00000000..55e9ad78 --- /dev/null +++ b/test/LoggerAwareTraitTest.php @@ -0,0 +1,33 @@ +getObjectForTrait('\Zend\Log\LoggerAwareTrait'); + + $this->assertAttributeEquals(null, 'logger', $object); + + $logger = new Logger; + + $object->setLogger($logger); + + $this->assertAttributeEquals($logger, 'logger', $object); + } +} diff --git a/test/LoggerTest.php b/test/LoggerTest.php index 9343c885..8b42173a 100644 --- a/test/LoggerTest.php +++ b/test/LoggerTest.php @@ -10,6 +10,8 @@ namespace ZendTest\Log; +use Zend\Log\Processor\Backtrace; + use Zend\Log\Logger; use Zend\Log\Writer\Mock as MockWriter; use Zend\Log\Filter\Mock as MockFilter; @@ -259,4 +261,69 @@ public function testRegisterErrorHandler() Logger::unregisterErrorHandler(); $this->assertEquals($writer->events[0]['message'], 'Undefined variable: test'); } + + public function testOptionsWithMock() + { + $options = array('writers' => array( + 'first_writer' => array( + 'name' => 'mock', + ) + )); + $logger = new Logger($options); + + $writers = $logger->getWriters()->toArray(); + $this->assertCount(1, $writers); + $this->assertInstanceOf('Zend\Log\Writer\Mock', $writers[0]); + } + + public function testOptionsWithWriterOptions() + { + $options = array('writers' => array( + array( + 'name' => 'stream', + 'options' => array( + 'stream' => 'php://output', + 'log_separator' => 'foo' + ), + ) + )); + $logger = new Logger($options); + + $writers = $logger->getWriters()->toArray(); + $this->assertCount(1, $writers); + $this->assertInstanceOf('Zend\Log\Writer\Stream', $writers[0]); + $this->assertEquals('foo', $writers[0]->getLogSeparator()); + } + + public function testAddProcessor() + { + $processor = new Backtrace(); + $this->logger->addProcessor($processor); + + $processors = $this->logger->getProcessors()->toArray(); + $this->assertEquals($processor, $processors[0]); + } + + public function testAddProcessorByName() + { + $this->logger->addProcessor('backtrace'); + + $processors = $this->logger->getProcessors()->toArray(); + $this->assertInstanceOf('Zend\Log\Processor\Backtrace', $processors[0]); + + $writer = new MockWriter; + $this->logger->addWriter($writer); + $this->logger->log(Logger::ERR, 'foo'); + } + + public function testProcessorOutputAdded() + { + $processor = new Backtrace(); + $this->logger->addProcessor($processor); + $writer = new MockWriter; + $this->logger->addWriter($writer); + + $this->logger->log(Logger::ERR, 'foo'); + $this->assertEquals(__FILE__, $writer->events[0]['extra']['file']); + } } diff --git a/test/Processor/BacktraceTest.php b/test/Processor/BacktraceTest.php new file mode 100644 index 00000000..5fbc9bae --- /dev/null +++ b/test/Processor/BacktraceTest.php @@ -0,0 +1,43 @@ + '', + 'priority' => 1, + 'priorityName' => 'ALERT', + 'message' => 'foo', + 'extra' => array() + ); + + $event = $processor->process($event); + + $this->assertArrayHasKey('file', $event['extra']); + $this->assertArrayHasKey('line', $event['extra']); + $this->assertArrayHasKey('class', $event['extra']); + $this->assertArrayHasKey('function', $event['extra']); + } +} diff --git a/test/Processor/RequestIdTest.php b/test/Processor/RequestIdTest.php new file mode 100644 index 00000000..4b0c8627 --- /dev/null +++ b/test/Processor/RequestIdTest.php @@ -0,0 +1,44 @@ + '', + 'priority' => 1, + 'priorityName' => 'ALERT', + 'message' => 'foo', + 'extra' => array() + ); + + $eventA = $processor->process($event); + $this->assertArrayHasKey('requestId', $eventA['extra']); + + $eventB = $processor->process($event); + $this->assertArrayHasKey('requestId', $eventB['extra']); + + $this->assertEquals($eventA['extra']['requestId'], $eventB['extra']['requestId']); + } +} diff --git a/test/TestAsset/MockChromePhp.php b/test/TestAsset/MockChromePhp.php new file mode 100644 index 00000000..814bedfe --- /dev/null +++ b/test/TestAsset/MockChromePhp.php @@ -0,0 +1,46 @@ +enabled = $enabled; + } + + public function getEnabled() + { + return $this->enabled; + } + + public function error($line) + { + $this->calls['error'][] = $line; + } + + public function warn($line) + { + $this->calls['warn'][] = $line; + } + + public function info($line) + { + $this->calls['info'][] = $line; + } + + public function trace($line) + { + $this->calls['trace'][] = $line; + } + + public function log($line) + { + $this->calls['log'][] = $line; + } +} diff --git a/test/Writer/AbstractTest.php b/test/Writer/AbstractTest.php index 68f9a42b..7cf3d686 100644 --- a/test/Writer/AbstractTest.php +++ b/test/Writer/AbstractTest.php @@ -30,14 +30,10 @@ protected function setUp() $this->_writer = new ConcreteWriter(); } - /** - * @group ZF-6085 - */ - public function testSetFormatter() + public function testSetSimpleFormatterByName() { - $this->_writer->setFormatter(new SimpleFormatter()); - $this->setExpectedException('PHPUnit_Framework_Error'); - $this->_writer->setFormatter(new \StdClass()); + $instance = $this->_writer->setFormatter('simple'); + $this->assertAttributeInstanceOf('Zend\Log\Formatter\Simple', 'formatter', $instance); } public function testAddFilter() @@ -81,4 +77,33 @@ public function testConvertErrorsToException() $this->setExpectedException('PHPUnit_Framework_Error_Warning'); $writer->write(array('message' => 'test')); } + + public function testConstructorWithOptions() + { + $options = array('filters' => array( + array( + 'name' => 'mock', + ), + array( + 'name' => 'priority', + 'options' => array( + 'priority' => 3, + ), + ), + ), + 'formatter' => array( + 'name' => 'base', + ), + ); + + $writer = new ConcreteWriter($options); + + $this->assertAttributeInstanceOf('Zend\Log\Formatter\Base', 'formatter', $writer); + + $filters = $this->readAttribute($writer, 'filters'); + $this->assertCount(2, $filters); + + $this->assertInstanceOf('Zend\Log\Filter\Priority', $filters[1]); + $this->assertEquals(3, $this->readAttribute($filters[1], 'priority')); + } } diff --git a/test/Writer/ChromePhpTest.php b/test/Writer/ChromePhpTest.php new file mode 100644 index 00000000..e1589e44 --- /dev/null +++ b/test/Writer/ChromePhpTest.php @@ -0,0 +1,100 @@ +chromephp = new MockChromePhp(); + + } + + public function testGetChromePhp() + { + $writer = new ChromePhp($this->chromephp); + $this->assertTrue($writer->getChromePhp() instanceof ChromePhpInterface); + } + + public function testSetChromePhp() + { + $writer = new ChromePhp($this->chromephp); + $chromephp2 = new MockChromePhp(); + + $writer->setChromePhp($chromephp2); + $this->assertTrue($writer->getChromePhp() instanceof ChromePhpInterface); + $this->assertEquals($chromephp2, $writer->getChromePhp()); + } + + public function testWrite() + { + $writer = new ChromePhp($this->chromephp); + $writer->write(array( + 'message' => 'my msg', + 'priority' => Logger::DEBUG + )); + $this->assertEquals('my msg', $this->chromephp->calls['trace'][0]); + } + + public function testWriteDisabled() + { + $chromephp = new MockChromePhp(false); + $writer = new ChromePhp($chromephp); + $writer->write(array( + 'message' => 'my msg', + 'priority' => Logger::DEBUG + )); + $this->assertTrue(empty($this->chromephp->calls)); + } + + public function testConstructWithOptions() + { + $formatter = new \Zend\Log\Formatter\Simple(); + $filter = new \Zend\Log\Filter\Mock(); + $writer = new ChromePhp(array( + 'filters' => $filter, + 'formatter' => $formatter, + 'instance' => $this->chromephp, + )); + $this->assertTrue($writer->getChromePhp() instanceof ChromePhpInterface); + $this->assertAttributeInstanceOf('Zend\Log\Formatter\ChromePhp', 'formatter', $writer); + + $filters = self::readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertEquals($filter, $filters[0]); + } +} diff --git a/test/Writer/DbTest.php b/test/Writer/DbTest.php index 8a2467a6..a013fc69 100644 --- a/test/Writer/DbTest.php +++ b/test/Writer/DbTest.php @@ -197,15 +197,6 @@ public function testShutdownRemovesReferenceToDatabaseInstance() $this->writer->write(array('message' => 'this should fail')); } - /** - * @group ZF-10089 - */ - public function testThrowStrictSetFormatter() - { - $this->setExpectedException('PHPUnit_Framework_Error'); - $this->writer->setFormatter(new \StdClass()); - } - public function testWriteDateTimeAsTimestamp() { $date = new DateTime(); @@ -237,4 +228,23 @@ public function testWriteDateTimeAsExtraValue() 'extra_request_time' => $date->format(FormatterInterface::DEFAULT_DATETIME_FORMAT) )), $this->db->calls['execute'][0]); } + + public function testConstructWithOptions() + { + $formatter = new \Zend\Log\Formatter\Simple(); + $filter = new \Zend\Log\Filter\Mock(); + $writer = new DbWriter(array( + 'filters' => $filter, + 'formatter' => $formatter, + 'table' => $this->tableName, + 'db' => $this->db, + + )); + $this->assertInstanceOf('Zend\Log\Writer\Db', $writer); + $this->assertAttributeEquals($this->tableName, 'tableName', $writer); + + $filters = self::readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertEquals($filter, $filters[0]); + } } diff --git a/test/Writer/FingersCrossedTest.php b/test/Writer/FingersCrossedTest.php new file mode 100644 index 00000000..cd5ca228 --- /dev/null +++ b/test/Writer/FingersCrossedTest.php @@ -0,0 +1,84 @@ +write(array('priority' => 3, 'message' => 'foo')); + + $this->assertSame(count($wrappedWriter->events), 0); + } + + public function testFlushing() + { + $wrappedWriter = new MockWriter(); + $writer = new FingersCrossedWriter($wrappedWriter, 2); + + $writer->write(array('priority' => 3, 'message' => 'foo')); + $writer->write(array('priority' => 1, 'message' => 'bar')); + + $this->assertSame(count($wrappedWriter->events), 2); + } + + public function testAfterFlushing() + { + $wrappedWriter = new MockWriter(); + $writer = new FingersCrossedWriter($wrappedWriter, 2); + + $writer->write(array('priority' => 3, 'message' => 'foo')); + $writer->write(array('priority' => 1, 'message' => 'bar')); + $writer->write(array('priority' => 3, 'message' => 'bar')); + + $this->assertSame(count($wrappedWriter->events), 3); + } + + public function setWriterByName() + { + $writer = new FingersCrossedWriter('mock'); + $this->assertAttributeInstanceOf('Zend\Log\Writer\Mock', 'writer', $writer); + } + + public function testConstructorOptions() + { + $options = array('writer' => 'mock', 'priority' => 3); + $writer = new FingersCrossedWriter($options); + $this->assertAttributeInstanceOf('Zend\Log\Writer\Mock', 'writer', $writer); + + $filters = $this->readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertInstanceOf('Zend\Log\Filter\Priority', $filters[0]); + $this->assertAttributeEquals(3, 'priority', $filters[0]); + } + + public function testFormattingIsNotSupported() + { + $options = array('writer' => 'mock', 'priority' => 3); + $writer = new FingersCrossedWriter($options); + + $writer->setFormatter($this->getMock('Zend\Log\Formatter\FormatterInterface')); + $this->assertAttributeEmpty('formatter', $writer); + } +} diff --git a/test/Writer/FirePhpTest.php b/test/Writer/FirePhpTest.php index 6225f058..1d585fb9 100644 --- a/test/Writer/FirePhpTest.php +++ b/test/Writer/FirePhpTest.php @@ -88,4 +88,21 @@ public function testWriteDisabled() )); $this->assertTrue(empty($this->firephp->calls)); } + + public function testConstructWithOptions() + { + $formatter = new \Zend\Log\Formatter\Simple(); + $filter = new \Zend\Log\Filter\Mock(); + $writer = new FirePhp(array( + 'filters' => $filter, + 'formatter' => $formatter, + 'instance' => $this->firephp, + )); + $this->assertTrue($writer->getFirePhp() instanceof FirePhpInterface); + $this->assertAttributeInstanceOf('Zend\Log\Formatter\FirePhp', 'formatter', $writer); + + $filters = self::readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertEquals($filter, $filters[0]); + } } diff --git a/test/Writer/MailTest.php b/test/Writer/MailTest.php index 5c734f99..de837931 100644 --- a/test/Writer/MailTest.php +++ b/test/Writer/MailTest.php @@ -83,4 +83,34 @@ public function testSetSubjectPrependText() $this->assertContains('an info message', $contents); $this->assertContains('Subject: test', $contents); } + + public function testConstructWithOptions() + { + $message = new MailMessage(); + $transport = new Transport\File(); + $options = new Transport\FileOptions(array( + 'path' => __DIR__, + 'callback' => function (Transport\File $transport) { + return MailTest::FILENAME; + }, + )); + $transport->setOptions($options); + + $formatter = new \Zend\Log\Formatter\Simple(); + $filter = new \Zend\Log\Filter\Mock(); + $writer = new MailWriter(array( + 'filters' => $filter, + 'formatter' => $formatter, + 'mail' => $message, + 'transport' => $transport, + )); + + $this->assertAttributeEquals($message, 'mail', $writer); + $this->assertAttributeEquals($transport, 'transport', $writer); + $this->assertAttributeEquals($formatter, 'formatter', $writer); + + $filters = self::readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertEquals($filter, $filters[0]); + } } diff --git a/test/Writer/MongoDBTest.php b/test/Writer/MongoDBTest.php index c5240354..0536d99f 100644 --- a/test/Writer/MongoDBTest.php +++ b/test/Writer/MongoDBTest.php @@ -48,14 +48,12 @@ public function setUp() ->will($this->returnValue($this->mongoCollection)); } - /** - * @expectedException Zend\Log\Exception\InvalidArgumentException - */ public function testFormattingIsNotSupported() { $writer = new MongoDBWriter($this->mongo, $this->database, $this->collection); $writer->setFormatter($this->getMock('Zend\Log\Formatter\FormatterInterface')); + $this->assertAttributeEmpty('formatter', $writer); } public function testWriteWithDefaultSaveOptions() diff --git a/test/Writer/StreamTest.php b/test/Writer/StreamTest.php index a315ee53..f2ff2f7e 100644 --- a/test/Writer/StreamTest.php +++ b/test/Writer/StreamTest.php @@ -146,4 +146,30 @@ public function testAllowsSpecifyingLogSeparatorWithinArrayPassedToConstructor() $writer = new StreamWriter($options); $this->assertEquals('::', $writer->getLogSeparator()); } + + public function testConstructWithOptions() + { + $formatter = new \Zend\Log\Formatter\Simple(); + $filter = new \Zend\Log\Filter\Mock(); + $writer = new StreamWriter(array( + 'filters' => $filter, + 'formatter' => $formatter, + 'stream' => 'php://memory', + 'mode' => 'w+', + 'log_separator' => '::', + + )); + $this->assertEquals('::', $writer->getLogSeparator()); + $this->assertAttributeEquals($formatter, 'formatter', $writer); + + $filters = self::readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertEquals($filter, $filters[0]); + } + + public function testDefaultFormatter() + { + $writer = new StreamWriter('php://memory'); + $this->assertAttributeInstanceOf('Zend\Log\Formatter\Simple', 'formatter', $writer); + } } diff --git a/test/Writer/SyslogTest.php b/test/Writer/SyslogTest.php index b1ff76da..6ce9d834 100644 --- a/test/Writer/SyslogTest.php +++ b/test/Writer/SyslogTest.php @@ -102,4 +102,27 @@ public function testPassApplicationNameViaConstructor() $writer = new CustomSyslogWriter(array('application' => 'test_app')); $this->assertEquals('test_app', $writer->getApplicationName()); } + + public function testConstructWithOptions() + { + $formatter = new \Zend\Log\Formatter\Simple(); + $filter = new \Zend\Log\Filter\Mock(); + $writer = new CustomSyslogWriter(array( + 'filters' => $filter, + 'formatter' => $formatter, + 'application' => 'test_app', + )); + $this->assertEquals('test_app', $writer->getApplicationName()); + $this->assertAttributeEquals($formatter, 'formatter', $writer); + + $filters = self::readAttribute($writer, 'filters'); + $this->assertCount(1, $filters); + $this->assertEquals($filter, $filters[0]); + } + + public function testDefaultFormatter() + { + $writer = new CustomSyslogWriter(array('application' => 'test_app')); + $this->assertAttributeInstanceOf('Zend\Log\Formatter\Simple', 'formatter', $writer); + } }