diff --git a/README.md b/README.md
index d041e2d..9f622c0 100644
--- a/README.md
+++ b/README.md
@@ -6,4 +6,289 @@
[![Latest Stable Version](https://img.shields.io/github/v/release/phoole/logger)](https://packagist.org/packages/phoole/logger)
[![License](https://img.shields.io/github/license/phoole/logger)]()
-Simple & Slim PSR-3 Logger for PHP
+[PSR-3]: http://www.php-fig.org/psr/psr-3/ "PSR-3: Logger Interface"
+
+Simple & Slim [PSR-3][PSR-3] Logger for PHP. It helps to **'DELIVER CERTAIN MESSAGES TO SOMEWHERE'**
+
+Installation
+---
+Install via the `composer` utility.
+
+```
+composer require "phoole/logger"
+```
+
+or add the following lines to your `composer.json`
+
+```json
+{
+ "require": {
+ "phoole/logger": "1.*"
+ }
+}
+```
+
+Usage
+---
+
+Create the logger instance with a channel id,
+
+```php
+use Psr\Log\LogLevel;
+use Phoole\Logger\Logger;
+use Phoole\Logger\Entry\MemoryInfo;
+use Phoole\Logger\Handler\SyslogHandler;
+use Phoole\Logger\Handler\TerminalHandler;
+
+// with channel id
+$logger = new Logger('MyApp');
+
+// log every warning to syslog
+$logger->addHandler(
+ LogLevel::WARNING,
+ new SyslogHandler()
+);
+
+// log to terminal for MemoryInfo entry
+$logger->addHandler(
+ LogLevel::INFO,
+ new TerminalHandler(),
+ MemoryInfo::class // handle this log object only
+);
+
+// log a text message
+$logger->warning('a warning message');
+
+// log memory usage
+$logger->info(new MemoryInfo());
+```
+
+Concepts
+---
+
+- **Log entry**
+
+ *A log entry* is a message in the form of an object. It solves the problem
+ of **'WHAT TO BE SENT OUT'**. It has a message template, and some processors
+ to process its context.
+
+ For example, `Entry\MemoryInfo` is a predefined log entry with a message
+ template of `{memory_used}M memory used , peak usage is {memory_peak}M`
+ and one `Processor\MemoryProcessor` processor.
+
+ ```php
+ // with predefined template and processor
+ $logger->warning(new MemoryInfo());
+
+ // use new template
+ $logger->warning(new MemoryInfo('Peak memory usage is {memory_peak}M'));
+ ```
+
+ `Entry\LogEntry` is the log entry prototype used whenever text message is
+ to be logged
+
+ ```php
+ // using LogEntry
+ $logger->info('test only');
+ ```
+
+ To define your own log entry,
+
+ ```php
+ use Phoole\Logger\Entry\LogEntry;
+
+ class MyMessage extends LogEntry
+ {
+ // message template
+ protected $message = 'your {template}';
+ }
+
+ // add handler
+ $logger->addHandler(
+ 'warning', // level
+ function(LogEntry $entry) { // a handler
+ echo (string) $entry;
+ },
+ MyMessage::class // handle this type of message only
+ );
+
+ // output: 'your wow'
+ $logger->error(new MyMessage(), ['template' => 'wow']);
+ ```
+
+- **Processor**
+
+ *Processors* are associated with log entry classes. They solve the problem of
+ **'WHAT EXTRA INFO TO SENT OUT'**. They will inject information into entries'
+ context. Processors are `callable(LogEntryInterface $entry)`,
+
+ ```php
+ use Phoole\Logger\Processor\ProcessorAbstract;
+
+ // closure
+ $processor1 = function(LogEntry $entry) {
+ };
+
+ // invokable object
+ $processor2 = new class() {
+ public function __invoke(LogEntry $entry)
+ {
+ }
+ }
+
+ // extends
+ class Processor3 extends ProcessorAbstract
+ {
+ protected function updateContext(array $context): array
+ {
+ $context['bingo'] = 'wow';
+ return $context;
+ }
+ }
+ ```
+
+ Processors are attached to log entries either in the entry class definition
+ as follows,
+
+ ```php
+ class MyMessage extends LogEntry
+ {
+ // message template
+ protected $message = 'your {template}';
+
+ // define processors for this class
+ protected static function classProcessors(): array
+ {
+ return [
+ function(LogEntry $entry) {
+ $context = $entry->getContext();
+ $context['template'] = 'wow';
+ $entry->setContext($context);
+ },
+ new myProcessor(),
+ ];
+ }
+ }
+ ```
+
+ or during the handler attachment
+
+ ```php
+ use Phoole\Logger\Handler\SyslogHandler;
+
+ // will also add 'Processor1' and 'Processor2' to 'MyMessage' class
+ $logger->addHandler(
+ 'info',
+ new SyslogHandler(),
+ MyMessage::addProcessor(
+ new Processor1(),
+ new Processor2(),
+ ...
+ )
+ );
+ ```
+
+- **Handler**
+
+ *Handlers* solve the problem of **'WHERE TO SEND MESSAGE'**. They take a
+ log entry object and send it to somewhere.
+
+ Handlers takes the form of `callable(LogEntryInterface $entry)` as follows,
+
+ ```php
+ use Phoole\Logger\Handler\HandlerAbstract;
+
+ $handler1 = function(LogEntry $entry) {
+ echo (string) $entry;
+ }
+
+ $handler2 = new class() {
+ public function __invoke(LogEntry $entry)
+ {
+ }
+ }
+
+ class Handler3 extends HandlerAbstract
+ {
+ protected function write(LogEntryInterface $entry)
+ {
+ echo $this->>getFormatter()->format($entry);
+ }
+ }
+ ```
+
+ Handlers are added to the `$logger` with specific log level and type of
+ log message they are going to handle (default is `LogEntryInterface`).
+
+ ```php
+ $logger->addHandler(
+ LogLevel::WARNING,
+ new TerminalHandler(),
+ LogEntryInterface::class // this is the default anyway
+ );
+ ```
+
+- **Formatter**
+
+ *Formatters* solve the problem of **'HOW MESSAGE WILL BE PRESENTED''**.
+ Each handler of the type `Handler\HandlerAbstract` may have formatter
+ specified during its initiation.
+
+ ```php
+ use Phoole\Logger\Handler\TerminalHandler;
+ use Phoole\Logger\Formatter\AnsiFormatter;
+
+ // use ANSI Color formatter
+ $handler = new TerminalHandler(new AnsiFormatter());
+
+ // add handler handles 'ConsoleMessage' ONLY
+ $logger->addHandler('debug', $handler, ConsoleMessage::class);
+
+ // log to console
+ $logger->info(new ConsoleMessage('exited with error.'));
+
+ // this will goes handlers handling 'LogEntry'
+ $logger->info('exited with error');
+ ```
+
+APIs
+---
+
+- `LoggerInterface` related
+
+ See [PSR-3][PSR-3] for standard related APIs.
+
+- `Phoole\Logger\Logger` related
+
+ - `__construct(string $channel)`
+
+ Create the logger with a channel id.
+
+ - `addHandler(string $level, callable $handler, string $entryClass, int $priority = 50): $this`
+
+ Add one handler to specified channel with the priority.
+
+- `Phoole\Logger\Entry\LogEntry` related
+
+ - `static function addProcessor(callable ...$callables): string`
+
+ This method will returns called class name.
+
+Testing
+---
+
+```bash
+$ composer test
+```
+
+Dependencies
+---
+
+- PHP >= 7.2.0
+
+- phoole/base 1.*
+
+License
+---
+
+- [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 3f9c414..da3a081 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "phoole/logger",
"type": "library",
"license": "Apache-2.0",
- "version": "1.0.5",
+ "version": "1.1.0",
"description": "Simple & slim PSR-3 logger for PHP",
"keywords": [
"phoole",
diff --git a/src/Entry/LogEntry.php b/src/Entry/LogEntry.php
index bde5f24..18a5350 100644
--- a/src/Entry/LogEntry.php
+++ b/src/Entry/LogEntry.php
@@ -7,23 +7,27 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Entry;
+use Psr\Log\LogLevel;
use Psr\Log\InvalidArgumentException;
-use Phoole\Logger\Processor\ProcessorInterface;
+use Phoole\Logger\Processor\ProcessorAwareTrait;
/**
- * Log message
+ * Log message prototype
*
* @package Phoole\Logger
*/
class LogEntry implements LogEntryInterface
{
use LogLevelTrait;
+ use ProcessorAwareTrait;
/**
+ * message template
+ *
* @var string
*/
protected $message = 'log message';
@@ -31,7 +35,7 @@ class LogEntry implements LogEntryInterface
/**
* @var string
*/
- protected $level = 'info';
+ protected $level = LogLevel::INFO;
/**
* @var array
@@ -48,19 +52,26 @@ public function __construct(string $message = '', array $context = [])
$this->message = $message;
}
$this->context = $context;
- foreach ($this->getProcessors() as $processorClass) {
- /** @var ProcessorInterface $processor */
- $processor = new $processorClass();
- $processor->process($this);
- }
}
/**
* {@inheritDoc}
*/
- public function getProcessors(): array
+ public function getMessage(): string
+ {
+ return $this->message;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setLevel(string $level)
{
- return array();
+ if (!isset($this->convert[$level])) {
+ throw new InvalidArgumentException("unknown log level");
+ }
+ $this->level = $level;
+ return $this;
}
/**
@@ -74,20 +85,26 @@ public function getLevel(): string
/**
* {@inheritDoc}
*/
- public function setLevel(string $level)
+ public function setContext(array $context)
{
- if (!isset($this->convert[$level])) {
- throw new InvalidArgumentException("unknown log level");
- }
- $this->level = $level;
+ $this->context = $context;
return $this;
}
+ /**
+ * {@inheritDoc}
+ */
+ public function getContext(): array
+ {
+ return $this->context;
+ }
+
/**
* {@inheritDoc}
*/
public function __toString(): string
{
+ $this->process();
return $this->interpolate($this->getMessage(), $this->getContext());
}
@@ -110,29 +127,4 @@ protected function interpolate(string $message, array $context): string
}
return strtr($message, $replace);
}
-
- /**
- * {@inheritDoc}
- */
- public function getMessage(): string
- {
- return $this->message;
- }
-
- /**
- * {@inheritDoc}
- */
- public function getContext(): array
- {
- return $this->context;
- }
-
- /**
- * {@inheritDoc}
- */
- public function setContext(array $context)
- {
- $this->context = $context;
- return $this;
- }
}
\ No newline at end of file
diff --git a/src/Entry/LogEntryInterface.php b/src/Entry/LogEntryInterface.php
index 03e7801..66abc30 100644
--- a/src/Entry/LogEntryInterface.php
+++ b/src/Entry/LogEntryInterface.php
@@ -7,40 +7,27 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Entry;
use Psr\Log\InvalidArgumentException;
+use Phoole\Logger\Processor\ProcessorAwareInterface;
/**
* Log message
*
* @package Phoole\Logger
*/
-interface LogEntryInterface
+interface LogEntryInterface extends ProcessorAwareInterface
{
/**
- * Get the text message
+ * Get the text message template (raw message)
*
* @return string
*/
public function getMessage(): string;
- /**
- * Get the level
- *
- * @return string
- */
- public function getLevel(): string;
-
- /**
- * Get the context
- *
- * @return array
- */
- public function getContext(): array;
-
/**
* @param string $level
* @return $this
@@ -48,6 +35,13 @@ public function getContext(): array;
*/
public function setLevel(string $level);
+ /**
+ * Get the level
+ *
+ * @return string
+ */
+ public function getLevel(): string;
+
/**
* Set context
*
@@ -57,11 +51,11 @@ public function setLevel(string $level);
public function setContext(array $context);
/**
- * array of processor classname
+ * Get the context
*
- * @return string[]
+ * @return array
*/
- public function getProcessors(): array;
+ public function getContext(): array;
/**
* @return string
diff --git a/src/Entry/LogLevelTrait.php b/src/Entry/LogLevelTrait.php
index 18ea1fb..e87bf95 100644
--- a/src/Entry/LogLevelTrait.php
+++ b/src/Entry/LogLevelTrait.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Entry;
diff --git a/src/Entry/SystemLog.php b/src/Entry/MemoryInfo.php
similarity index 60%
rename from src/Entry/SystemLog.php
rename to src/Entry/MemoryInfo.php
index 07614f1..76ea1b1 100644
--- a/src/Entry/SystemLog.php
+++ b/src/Entry/MemoryInfo.php
@@ -7,27 +7,33 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Entry;
use Phoole\Logger\Processor\MemoryProcessor;
/**
- * Log system related message.
+ * A log entry with predefined message template to log memory usage
+ *
* ```php
+ * // initiate log with app id
* $log = new Logger('MyApp');
+ *
+ * // add handler to this MemoryInfo
* $log->addHandler(
- * new LogfileHandler('system.log'),
* LogLevel::INFO,
- * SystemLog::class
+ * new LogfileHandler('system.log'),
+ * MemoryInfo::class
* );
- * $log->info(new SystemLog());
+ *
+ * // use it
+ * $log->info(new MemoryInfo());
* ```
*
* @package Phoole\Logger
*/
-class SystemLog extends LogEntry
+class MemoryInfo extends LogEntry
{
/**
* default message template
@@ -39,10 +45,10 @@ class SystemLog extends LogEntry
/**
* {@inheritDoc}
*/
- public function getProcessors(): array
+ protected static function classProcessors(): array
{
- return array_merge(
- parent::getProcessors(), [MemoryProcessor::class]
- );
+ return [
+ new MemoryProcessor()
+ ];
}
}
\ No newline at end of file
diff --git a/src/Formatter/AnsiFormatter.php b/src/Formatter/AnsiFormatter.php
index c924172..9d45c5c 100644
--- a/src/Formatter/AnsiFormatter.php
+++ b/src/Formatter/AnsiFormatter.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Formatter;
diff --git a/src/Formatter/DefaultFormatter.php b/src/Formatter/DefaultFormatter.php
index 054bae5..6683c8f 100644
--- a/src/Formatter/DefaultFormatter.php
+++ b/src/Formatter/DefaultFormatter.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Formatter;
@@ -25,13 +25,15 @@ class DefaultFormatter implements FormatterInterface
*/
public function format(LogEntryInterface $entry): string
{
- $context = $entry->getContext();
$mesg = '';
+
+ // channel name
+ $context = $entry->getContext();
if (isset($context['__channel'])) {
$mesg .= '[' . strtoupper($context['__channel']) . '] ';
}
- $mesg .= $entry . $this->getEol();
- return $mesg;
+
+ return $mesg . \strtoupper($entry->getLevel()) . ': ' . $entry . $this->getEol();
}
/**
diff --git a/src/Formatter/FormatterAwareInterface.php b/src/Formatter/FormatterAwareInterface.php
index 1370d73..f1a9e05 100644
--- a/src/Formatter/FormatterAwareInterface.php
+++ b/src/Formatter/FormatterAwareInterface.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Formatter;
@@ -20,7 +20,7 @@ interface FormatterAwareInterface
{
/**
* @param FormatterInterface
- * @return void
+ * @return $this
*/
public function setFormatter(FormatterInterface $formatter);
diff --git a/src/Formatter/FormatterAwareTrait.php b/src/Formatter/FormatterAwareTrait.php
index a97dcaf..560bc7d 100644
--- a/src/Formatter/FormatterAwareTrait.php
+++ b/src/Formatter/FormatterAwareTrait.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Formatter;
@@ -38,5 +38,6 @@ public function getFormatter(): FormatterInterface
public function setFormatter(FormatterInterface $formatter)
{
$this->formatter = $formatter;
+ return $this;
}
}
\ No newline at end of file
diff --git a/src/Formatter/FormatterInterface.php b/src/Formatter/FormatterInterface.php
index 5bbc98e..82019e8 100644
--- a/src/Formatter/FormatterInterface.php
+++ b/src/Formatter/FormatterInterface.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Formatter;
diff --git a/src/Handler/EchoHandler.php b/src/Handler/EchoHandler.php
index 34fb750..52f902c 100644
--- a/src/Handler/EchoHandler.php
+++ b/src/Handler/EchoHandler.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
diff --git a/src/Handler/HandlerAbstract.php b/src/Handler/HandlerAbstract.php
index fe23387..6cf4cdc 100644
--- a/src/Handler/HandlerAbstract.php
+++ b/src/Handler/HandlerAbstract.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
@@ -22,7 +22,7 @@
*
* @package Phoole\Logger
*/
-abstract class HandlerAbstract implements HandlerInterface, FormatterAwareInterface
+abstract class HandlerAbstract implements FormatterAwareInterface
{
use FormatterAwareTrait;
@@ -43,31 +43,31 @@ public function __destruct()
}
/**
- * Close the handler
+ * @param LogEntryInterface $entry
*/
- protected function close()
+ public function __invoke(LogEntryInterface $entry)
{
+ if ($this->isHandling($entry)) {
+ $this->write($entry);
+ }
}
/**
- * {@inheritDoc}
+ * Close the handler if wanted
*/
- public function handle(LogEntryInterface $entry): LogEntryInterface
+ protected function close()
{
- if ($this->isHandling()) {
- $this->write($entry);
- }
- return $entry;
}
/**
* Is this handler handling this log ?
*
+ * @param LogEntryInterface $entry
* @return bool
*/
- protected function isHandling(): bool
+ protected function isHandling(LogEntryInterface $entry): bool
{
- return TRUE;
+ return $entry ? TRUE : TRUE;
}
/**
diff --git a/src/Handler/HandlerAwareInterface.php b/src/Handler/HandlerAwareInterface.php
index 0b33f49..aaa9455 100644
--- a/src/Handler/HandlerAwareInterface.php
+++ b/src/Handler/HandlerAwareInterface.php
@@ -7,12 +7,10 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
-use Traversable;
-use LogicException;
use Phoole\Logger\Entry\LogEntryInterface;
/**
@@ -25,25 +23,17 @@ interface HandlerAwareInterface
/**
* Add a handler
*
- * @param HandlerInterface $handler
- * @param string $level level to handle
- * @param string $entryClass the log entry class/interface to handle
- * @param int $priority handling priority
+ * @param string $level level to handle
+ * @param callable $handler
+ * @param string|object $entryClass the log entry class/interface to handle
+ * @param int $priority handling priority
* @return $this
- * @throws LogicException if entry class unknown etc.
+ * @throws \InvalidArgumentException if entry class or handler not right
*/
public function addHandler(
- HandlerInterface $handler,
string $level,
- string $entryClass = LogEntryInterface::class,
+ callable $handler,
+ $entryClass = LogEntryInterface::class,
int $priority = 50
);
-
- /**
- * Get handlers handling $level and $entry type
- *
- * @param LogEntryInterface $entry
- * @return Traversable
- */
- public function getHandlers(LogEntryInterface $entry): Traversable;
}
\ No newline at end of file
diff --git a/src/Handler/HandlerAwareTrait.php b/src/Handler/HandlerAwareTrait.php
index 9452727..f78ba04 100644
--- a/src/Handler/HandlerAwareTrait.php
+++ b/src/Handler/HandlerAwareTrait.php
@@ -7,14 +7,14 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
-use Traversable;
use Phoole\Logger\Entry\LogLevelTrait;
use Phoole\Base\Queue\UniquePriorityQueue;
use Phoole\Logger\Entry\LogEntryInterface;
+use Phoole\Logger\Processor\VerifyCallableTrait;
/**
* HandlerAwareTrait
@@ -25,45 +25,94 @@
trait HandlerAwareTrait
{
use LogLevelTrait;
+ use VerifyCallableTrait;
/**
* queue for the handlers
*
- * @var HandlerInterface[][]
+ * @var UniquePriorityQueue[][]
*/
protected $handlers = [];
+ /**
+ * @var array
+ */
+ protected $handlerCache = [];
+
/**
* {@inheritDoc}
*/
public function addHandler(
- HandlerInterface $handler,
string $level,
- string $entryClass = LogEntryInterface::class,
+ callable $handler,
+ $entryClass = LogEntryInterface::class,
int $priority = 50
) {
- if (!isset($this->handlers[$level][$entryClass])) {
- $this->handlers[$level][$entryClass] = new UniquePriorityQueue();
- }
- /** @var UniquePriorityQueue $q */
- $q = $this->handlers[$level][$entryClass];
+ // verify parameters
+ $requiredClass = self::verifyCallable($handler, LogEntryInterface::class);
+ $entryClass = $this->checkEntry($entryClass, $requiredClass);
+
+ // add handler
+ $q = $this->handlers[$level][$entryClass] ?? new UniquePriorityQueue();
$q->insert($handler, $priority);
+ $this->handlers[$level][$entryClass] = $q;
+
+ // clear cache
+ $this->handlerCache = [];
+
return $this;
}
/**
- * {@inheritDoc}
+ * Get handlers handling $level and $entry type
+ *
+ * @param LogEntryInterface $entry
+ * @return \Traversable
*/
- public function getHandlers(LogEntryInterface $entry): Traversable
+ protected function getHandlers(LogEntryInterface $entry): \Traversable
{
- $queue = new UniquePriorityQueue();
+ // check cache
$level = $entry->getLevel();
+ if (isset($this->handlerCache[$level][\get_class($entry)])) {
+ return $this->handlerCache[$level][\get_class($entry)];
+ }
+
+ // find matching handlers
+ $queue = $this->findHandlers($entry, $level);
+
+ // update cache
+ $this->handlerCache[$level][\get_class($entry)] = $queue;
+
+ return $queue;
+ }
+
+ /**
+ * @param string|object $entryClass
+ * @param string $requiredClass
+ * @return string
+ * @throws \InvalidArgumentException if not valid message entry
+ */
+ protected function checkEntry($entryClass, string $requiredClass): string
+ {
+ if (!\is_a($entryClass, $requiredClass, TRUE)) {
+ throw new \InvalidArgumentException("not a valid entry " . $requiredClass);
+ }
+ return \is_string($entryClass) ? $entryClass : \get_class($entryClass);
+ }
+
+ /**
+ * @param LogEntryInterface $entry
+ * @param string $level
+ * @return UniquePriorityQueue
+ */
+ protected function findHandlers(LogEntryInterface $entry, string $level): UniquePriorityQueue
+ {
+ $queue = new UniquePriorityQueue();
foreach ($this->handlers as $l => $qs) {
- // match level
if (!$this->matchLevel($level, $l)) {
continue;
}
- // match class
+
/** @var UniquePriorityQueue $q */
foreach ($qs as $class => $q) {
if (is_a($entry, $class)) {
diff --git a/src/Handler/HandlerInterface.php b/src/Handler/HandlerInterface.php
deleted file mode 100644
index 138d45f..0000000
--- a/src/Handler/HandlerInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-checkPath($path);
if (file_exists($path)) {
@@ -55,7 +52,7 @@ public function __construct(
* Check file path
*
* @param string $path
- * @throws LogicException if directory failure etc.
+ * @throws \LogicException if directory failure etc.
*/
protected function checkPath(string $path)
{
@@ -65,10 +62,10 @@ protected function checkPath(string $path)
mkdir($dir, 0777, TRUE);
}
if (!is_dir($dir) || !is_writable($dir)) {
- throw new Exception("unable to write to $path");
+ throw new \Exception("unable to write to $path");
}
- } catch (Throwable $e) {
- throw new LogicException($e->getMessage());
+ } catch (\Throwable $e) {
+ throw new \LogicException($e->getMessage());
}
}
diff --git a/src/Handler/StreamHandler.php b/src/Handler/StreamHandler.php
index 7c29d37..9323d44 100644
--- a/src/Handler/StreamHandler.php
+++ b/src/Handler/StreamHandler.php
@@ -7,11 +7,10 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
-use LogicException;
use Phoole\Logger\Entry\LogEntryInterface;
use Phoole\Logger\Formatter\FormatterInterface;
@@ -40,7 +39,7 @@ public function __construct($stream, ?FormatterInterface $formatter = NULL)
*
* @param string|resource $path
* @return resource
- * @throws LogicException if open failure
+ * @throws \LogicException if open failure
*/
protected function openStream($path)
{
@@ -53,7 +52,7 @@ protected function openStream($path)
if (is_resource($path)) {
return $path;
}
- throw new LogicException("failed to open stream");
+ throw new \LogicException("failed to open stream");
}
/**
@@ -63,6 +62,7 @@ protected function close()
{
if ($this->stream) {
fclose($this->stream);
+ $this->stream = FALSE;
}
}
diff --git a/src/Handler/SyslogHandler.php b/src/Handler/SyslogHandler.php
index 29bec85..d0de510 100644
--- a/src/Handler/SyslogHandler.php
+++ b/src/Handler/SyslogHandler.php
@@ -7,24 +7,13 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
-use LogicException;
use Psr\Log\LogLevel;
use Phoole\Logger\Entry\LogEntryInterface;
use Phoole\Logger\Formatter\FormatterInterface;
-use const LOG_PID;
-use const LOG_ERR;
-use const LOG_USER;
-use const LOG_CRIT;
-use const LOG_INFO;
-use const LOG_EMERG;
-use const LOG_ALERT;
-use const LOG_DEBUG;
-use const LOG_NOTICE;
-use const LOG_WARNING;
/**
* log to syslog on UNIX type system
@@ -54,14 +43,14 @@ class SyslogHandler extends HandlerAbstract
* @access protected
*/
protected $priorities = [
- LogLevel::DEBUG => LOG_DEBUG,
- LogLevel::INFO => LOG_INFO,
- LogLevel::NOTICE => LOG_NOTICE,
- LogLevel::WARNING => LOG_WARNING,
- LogLevel::ERROR => LOG_ERR,
- LogLevel::CRITICAL => LOG_CRIT,
- LogLevel::ALERT => LOG_ALERT,
- LogLevel::EMERGENCY => LOG_EMERG,
+ LogLevel::DEBUG => \LOG_DEBUG,
+ LogLevel::INFO => \LOG_INFO,
+ LogLevel::NOTICE => \LOG_NOTICE,
+ LogLevel::WARNING => \LOG_WARNING,
+ LogLevel::ERROR => \LOG_ERR,
+ LogLevel::CRITICAL => \LOG_CRIT,
+ LogLevel::ALERT => \LOG_ALERT,
+ LogLevel::EMERGENCY => \LOG_EMERG,
];
/**
@@ -70,8 +59,8 @@ class SyslogHandler extends HandlerAbstract
* @param FormatterInterface $formatter
*/
public function __construct(
- int $facility = LOG_USER,
- int $logOpts = LOG_PID,
+ int $facility = \LOG_USER,
+ int $logOpts = \LOG_PID,
?FormatterInterface $formatter = NULL
) {
$this->facility = $facility;
@@ -87,7 +76,7 @@ protected function write(LogEntryInterface $entry)
$context = $entry->getContext();
$ident = $context['__channel'] ?? 'LOG';
if (!openlog($ident, $this->logopts, $this->facility)) {
- throw new LogicException("openlog() failed");
+ throw new \LogicException("openlog() failed");
}
syslog(
$this->priorities[$entry->getLevel()],
diff --git a/src/Handler/TerminalHandler.php b/src/Handler/TerminalHandler.php
index fcddf61..a21ce0c 100644
--- a/src/Handler/TerminalHandler.php
+++ b/src/Handler/TerminalHandler.php
@@ -7,12 +7,12 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Handler;
-use LogicException;
use Phoole\Logger\Formatter\AnsiFormatter;
+use Phoole\Logger\Entry\LogEntryInterface;
use Phoole\Logger\Formatter\FormatterInterface;
/**
@@ -31,7 +31,7 @@ public function __construct(
?FormatterInterface $formatter = NULL
) {
if (!in_array($stream, ['php://stderr', 'php://stdout'])) {
- throw new LogicException("unknown stream");
+ throw new \LogicException("unknown stream");
}
parent::__construct($stream, $formatter ?? new AnsiFormatter());
}
@@ -39,7 +39,7 @@ public function __construct(
/**
* {@inheritDoc}
*/
- protected function isHandling(): bool
+ protected function isHandling(LogEntryInterface $entry): bool
{
return 'cli' === php_sapi_name();
}
diff --git a/src/Logger.php b/src/Logger.php
index ab4274a..f8e1548 100644
--- a/src/Logger.php
+++ b/src/Logger.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger;
@@ -15,7 +15,6 @@
use Psr\Log\LoggerInterface;
use Phoole\Logger\Entry\LogEntry;
use Phoole\Logger\Entry\LogEntryInterface;
-use Phoole\Logger\Handler\HandlerInterface;
use Phoole\Logger\Handler\HandlerAwareTrait;
use Phoole\Logger\Handler\HandlerAwareInterface;
@@ -35,6 +34,8 @@ class Logger implements LoggerInterface, HandlerAwareInterface
protected $channel;
/**
+ * Channel usually is APP ID
+ *
* @param string $channel
*/
public function __construct(string $channel)
@@ -47,12 +48,10 @@ public function __construct(string $channel)
*/
public function log($level, $message, array $context = array())
{
- // init the log entry
- $entry = $this->initEntry($message, $level, $context);
+ $entry = ($this->initEntry($message, $level, $context))->process();
- /** @var HandlerInterface $handler */
foreach ($this->getHandlers($entry) as $handler) {
- $entry = $handler->handle($entry);
+ $handler($entry);
}
}
@@ -61,14 +60,13 @@ public function log($level, $message, array $context = array())
* @param string $level
* @param array $context
* @return LogEntryInterface
+ * @throws \InvalidArgumentException if message not right
*/
protected function initEntry($message, string $level, array $context): LogEntryInterface
{
- if (is_object($message) && $message instanceof LogEntryInterface) {
- $entry = $message;
- } else {
- $entry = new LogEntry($message);
- }
+ $entry = $this->validate($message);
+
+ // update channel name in context
$this->setChannel($context);
return $entry
@@ -77,6 +75,25 @@ protected function initEntry($message, string $level, array $context): LogEntryI
}
/**
+ * @param $message
+ * @return LogEntryInterface
+ * @throws \InvalidArgumentException if message not right
+ */
+ protected function validate($message): LogEntryInterface
+ {
+ if (is_string($message)) {
+ $entry = new LogEntry($message);
+ } elseif (is_object($message) && $message instanceof LogEntryInterface) {
+ $entry = $message;
+ } else {
+ throw new \InvalidArgumentException("not valid message " . (string) $message);
+ }
+ return $entry;
+ }
+
+ /**
+ * Set channel name in context
+ *
* @param array &$context
*/
protected function setChannel(array &$context)
diff --git a/src/Processor/MemoryProcessor.php b/src/Processor/MemoryProcessor.php
index 5432a84..369bb5c 100644
--- a/src/Processor/MemoryProcessor.php
+++ b/src/Processor/MemoryProcessor.php
@@ -7,12 +7,12 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Processor;
/**
- * MemoryProcessor
+ * Add system memory usage to log entry's context
*
* @package Phoole\Logger
*/
diff --git a/src/Processor/ProcessorAbstract.php b/src/Processor/ProcessorAbstract.php
index 88aa732..1f0fe7b 100644
--- a/src/Processor/ProcessorAbstract.php
+++ b/src/Processor/ProcessorAbstract.php
@@ -7,7 +7,7 @@
* @package Phoole\Logger
* @copyright Copyright (c) 2019 Hong Zhang
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Phoole\Logger\Processor;
@@ -18,12 +18,14 @@
*
* @package Phoole\Logger
*/
-abstract class ProcessorAbstract implements ProcessorInterface
+abstract class ProcessorAbstract
{
/**
- * {@inheritDoc}
+ * make it an invokable
+ *
+ * @param LogEntryInterface $entry
*/
- public function process(LogEntryInterface $entry)
+ public function __invoke(LogEntryInterface $entry)
{
$context = $entry->getContext();
$entry->setContext($this->updateContext($context));
@@ -32,6 +34,14 @@ public function process(LogEntryInterface $entry)
/**
* update info in the $context
*
+ * ```php
+ * protected function updateContext(array $context): array
+ * {
+ * $context['bingo'] = 'wow';
+ * return $context;
+ * }
+ * ```
+ *
* @param array $context
* @return array
*/
diff --git a/src/Processor/ProcessorAwareInterface.php b/src/Processor/ProcessorAwareInterface.php
new file mode 100644
index 0000000..f1f231b
--- /dev/null
+++ b/src/Processor/ProcessorAwareInterface.php
@@ -0,0 +1,36 @@
+isProcessed) {
+ foreach (static::getProcessors() as $processor) {
+ $processor($this);
+ }
+ $this->isProcessed = TRUE;
+ }
+ return $this;
+ }
+
+ /**
+ * Set processors for THIS class
+ *
+ * @param callable ...$callables
+ * @return string called class name
+ * @throws \LogicException if not valid processor found
+ */
+ public static function addProcessor(callable ...$callables): string
+ {
+ static::initProcessors();
+
+ $class = \get_called_class();
+ $queue = self::$processors[$class];
+
+ foreach ($callables as $callable) {
+ static::verifyCallable($callable);
+ $queue->insert($callable);
+ }
+ return $class;
+ }
+
+ /**
+ * get related processors
+ *
+ * @return iterable
+ */
+ protected static function getProcessors(): iterable
+ {
+ $queue = new UniquePriorityQueue();
+
+ /** @var string $class */
+ foreach (static::getClassTree() as $class) {
+ if (\method_exists($class, 'initProcessors')) {
+ $class::initProcessors();
+ }
+ $queue = $queue->combine(self::$processors[$class]);
+ }
+ return $queue;
+ }
+
+ /**
+ * convert predefined processors from classProcessors()
+ */
+ protected static function initProcessors()
+ {
+ $class = \get_called_class();
+ if (!isset(self::$processors[$class])) {
+ self::$processors[$class] = new UniquePriorityQueue();
+ foreach (static::classProcessors() as $processor) {
+ static::addProcessor($processor);
+ }
+ }
+ }
+
+ /**
+ * Define processors for THIS class
+ *
+ * @return array
+ */
+ protected static function classProcessors(): array
+ {
+ return [];
+ }
+
+ /**
+ * @return array
+ */
+ protected static function getClassTree(): array
+ {
+ $tree = [];
+ $class = \get_called_class();
+ while ($class) {
+ $tree[] = $class;
+ $class = \get_parent_class($class);
+ }
+ return \array_reverse($tree);
+ }
+}
\ No newline at end of file
diff --git a/src/Processor/ProcessorInterface.php b/src/Processor/ProcessorInterface.php
deleted file mode 100644
index 0ef712e..0000000
--- a/src/Processor/ProcessorInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-getClass()->getName(), $className, TRUE)
+ ) {
+ throw new \InvalidArgumentException("non valid processor found");
+ }
+ return $parameters[0]->getClass()->getName();
+ } catch (\Throwable $e) {
+ throw new \LogicException($e->getMessage());
+ }
+ }
+
+ /**
+ * Get callable parameters
+ *
+ * @param callable $callable
+ * @return \ReflectionParameter[]
+ * @throws \InvalidArgumentException if something goes wrong
+ */
+ protected static function getCallableParameters(callable $callable): array
+ {
+ try {
+ if (is_array($callable)) { // [class, method]
+ $reflector = new \ReflectionClass($callable[0]);
+ $method = $reflector->getMethod($callable[1]);
+ } elseif (is_string($callable) || $callable instanceof \Closure) { // function
+ $method = new \ReflectionFunction($callable);
+ } else { // __invokable
+ $reflector = new \ReflectionClass($callable);
+ $method = $reflector->getMethod('__invoke');
+ }
+ } catch (\Throwable $e) {
+ throw new \InvalidArgumentException($e->getMessage());
+ }
+ return $method->getParameters();
+ }
+}
\ No newline at end of file
diff --git a/tests/Entry/LogEntryTest.php b/tests/Entry/LogEntryTest.php
index abf3489..4bafd3c 100644
--- a/tests/Entry/LogEntryTest.php
+++ b/tests/Entry/LogEntryTest.php
@@ -1,6 +1,6 @@
obj = new LogEntry();
+ $this->ref = new \ReflectionClass(get_class($this->obj));
+ }
+
+ protected function tearDown(): void
+ {
+ $this->obj = $this->ref = NULL;
+ parent::tearDown();
+ }
+
+ protected function invokeMethod($methodName, array $parameters = array())
+ {
+ $method = $this->ref->getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($this->obj, $parameters);
+ }
+
/**
* @covers Phoole\Logger\Entry\LogEntry::__construct()
*/
public function testConstruct()
{
- $obj = new LogEntry('new {msg}', ['msg' => 'message']);
+ $obj = new LogEntry('new {msg} {msg}', ['msg' => 'message']);
$this->assertEquals(
- 'new message',
+ 'new message message',
(string) $obj
);
}
@@ -64,14 +84,6 @@ public function testGetContext()
$this->assertEquals($c, $this->obj->getContext());
}
- /**
- * @covers Phoole\Logger\Entry\LogEntry::getProcessors()
- */
- public function testGetProcessors()
- {
- $this->assertEquals([], $this->obj->getProcessors());
- }
-
/**
* @covers Phoole\Logger\Entry\LogEntry::__toString()
*/
@@ -96,24 +108,4 @@ public function testInterpolate()
$this->invokeMethod('interpolate', [$message, $context])
);
}
-
- protected function invokeMethod($methodName, array $parameters = array())
- {
- $method = $this->ref->getMethod($methodName);
- $method->setAccessible(TRUE);
- return $method->invokeArgs($this->obj, $parameters);
- }
-
- protected function setUp(): void
- {
- parent::setUp();
- $this->obj = new LogEntry();
- $this->ref = new \ReflectionClass(get_class($this->obj));
- }
-
- protected function tearDown(): void
- {
- $this->obj = $this->ref = NULL;
- parent::tearDown();
- }
}
\ No newline at end of file
diff --git a/tests/Entry/MemoryInfoTest.php b/tests/Entry/MemoryInfoTest.php
new file mode 100644
index 0000000..24769fa
--- /dev/null
+++ b/tests/Entry/MemoryInfoTest.php
@@ -0,0 +1,52 @@
+obj = new MemoryInfo();
+ $this->ref = new \ReflectionClass(get_class($this->obj));
+ }
+
+ protected function tearDown(): void
+ {
+ $this->obj = $this->ref = NULL;
+ parent::tearDown();
+ }
+
+ protected function invokeMethod(object $object, $methodName, array $parameters = array())
+ {
+ $ref = new \ReflectionClass(get_class($object));
+ $method = $ref->getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($object, $parameters);
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\MemoryInfo::process()
+ */
+ public function testProcess()
+ {
+ $this->obj->process();
+ $queue = $this->invokeMethod($this->obj, 'getProcessors');
+ $this->assertEquals(1, count($queue));
+
+ $context = $this->obj->getContext();
+ $this->assertTrue(isset($context['memory_used']));
+
+ $this->expectOutputRegex('/peak usage/');
+ echo (string) $this->obj;
+ }
+}
\ No newline at end of file
diff --git a/tests/Entry/SystemLogTest.php b/tests/Entry/SystemLogTest.php
deleted file mode 100644
index ffb22e9..0000000
--- a/tests/Entry/SystemLogTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-obj->getProcessors();
- $this->assertTrue(1 === count($a));
- $this->assertEquals(
- MemoryProcessor::class,
- $a[0]
- );
- }
-
- protected function setUp(): void
- {
- parent::setUp();
- $this->obj = new SystemLog();
- $this->ref = new \ReflectionClass(get_class($this->obj));
- }
-
- protected function tearDown(): void
- {
- $this->obj = $this->ref = NULL;
- parent::tearDown();
- }
-
- protected function invokeMethod($methodName, array $parameters = array())
- {
- $method = $this->ref->getMethod($methodName);
- $method->setAccessible(TRUE);
- return $method->invokeArgs($this->obj, $parameters);
- }
-}
\ No newline at end of file
diff --git a/tests/Formatter/AnsiFormatterTest.php b/tests/Formatter/AnsiFormatterTest.php
index 8f9ecd0..1d8e814 100644
--- a/tests/Formatter/AnsiFormatterTest.php
+++ b/tests/Formatter/AnsiFormatterTest.php
@@ -1,6 +1,6 @@
'PHOOLE', 'wow' => 'bingo']);
- $m->setLevel('error');
- $this->expectOutputRegex('/test bingo/');
- echo $this->obj->format($m);
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -44,4 +33,15 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Formatter\AnsiFormatter::format()
+ */
+ public function testFormatter()
+ {
+ $m = new LogEntry('test {wow}', ['__channel' => 'PHOOLE', 'wow' => 'bingo']);
+ $m->setLevel('error');
+ $this->expectOutputRegex('/test bingo/');
+ echo $this->obj->format($m);
+ }
}
\ No newline at end of file
diff --git a/tests/Formatter/DefaultFormatterTest.php b/tests/Formatter/DefaultFormatterTest.php
index e2e0ff8..ec7a38c 100644
--- a/tests/Formatter/DefaultFormatterTest.php
+++ b/tests/Formatter/DefaultFormatterTest.php
@@ -1,6 +1,6 @@
'PHOOLE', 'wow' => 'bingo']);
- $s = $this->obj->format($m);
- $this->assertEquals(
- '[PHOOLE] test bingo',
- trim($s)
- );
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -46,4 +33,17 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Formatter\DefaultFormatter::format()
+ */
+ public function testFormatter()
+ {
+ $m = new LogEntry('test {wow}', ['__channel' => 'PHOOLE', 'wow' => 'bingo']);
+ $s = $this->obj->format($m);
+ $this->assertEquals(
+ '[PHOOLE] INFO: test bingo',
+ trim($s)
+ );
+ }
}
\ No newline at end of file
diff --git a/tests/Formatter/FormatterAwareTraitTest.php b/tests/Formatter/FormatterAwareTraitTest.php
index 9573708..687c80f 100644
--- a/tests/Formatter/FormatterAwareTraitTest.php
+++ b/tests/Formatter/FormatterAwareTraitTest.php
@@ -1,6 +1,6 @@
obj->setFormatter($f);
- $this->assertTrue($f === $this->obj->getFormatter());
- }
-
- /**
- * @covers Phoole\Logger\Formatter\FormatterAwareTrait::getFormatter()
- */
- public function testGetFormatter()
- {
- $this->expectExceptionMessage('null');
- $this->obj->getFormatter();
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -58,4 +39,23 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Formatter\FormatterAwareTrait::setFormatter()
+ */
+ public function testSetFormatter()
+ {
+ $f = new DefaultFormatter;
+ $this->obj->setFormatter($f);
+ $this->assertTrue($f === $this->obj->getFormatter());
+ }
+
+ /**
+ * @covers Phoole\Logger\Formatter\FormatterAwareTrait::getFormatter()
+ */
+ public function testGetFormatter()
+ {
+ $this->expectExceptionMessage('null');
+ $this->obj->getFormatter();
+ }
}
\ No newline at end of file
diff --git a/tests/Handler/EchoHandlerTest.php b/tests/Handler/EchoHandlerTest.php
index 6a8e274..419cbe5 100644
--- a/tests/Handler/EchoHandlerTest.php
+++ b/tests/Handler/EchoHandlerTest.php
@@ -1,6 +1,6 @@
expectOutputRegex('/test/');
- $this->obj->handle($m);
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -43,4 +33,15 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Handler\EchoHandler::__invoke()
+ */
+ public function testInvoke()
+ {
+ $m = new LogEntry('test');
+ $this->expectOutputRegex('/test/');
+ $handler = $this->obj;
+ $handler($m);
+ }
}
\ No newline at end of file
diff --git a/tests/Handler/HandlerAbstractTest.php b/tests/Handler/HandlerAbstractTest.php
index bfeb155..06bb05c 100644
--- a/tests/Handler/HandlerAbstractTest.php
+++ b/tests/Handler/HandlerAbstractTest.php
@@ -1,6 +1,6 @@
assertTrue($this->obj->getFormatter() instanceof DefaultFormatter);
-
- $obj = new myHandler(new AnsiFormatter());
- $this->assertTrue($obj->getFormatter() instanceof AnsiFormatter);
- }
-
- /**
- * @covers Phoole\Logger\Handler\HandlerAbstract::handle()
- */
- public function testHandle()
- {
- $this->expectOutputString('test');
- $this->obj->handle(new LogEntry('test'));
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -64,4 +44,25 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Handler\HandlerAbstract::__construct()
+ */
+ public function testConstruct()
+ {
+ $this->assertTrue($this->obj->getFormatter() instanceof DefaultFormatter);
+
+ $obj = new myHandler(new AnsiFormatter());
+ $this->assertTrue($obj->getFormatter() instanceof AnsiFormatter);
+ }
+
+ /**
+ * @covers Phoole\Logger\Handler\HandlerAbstract::__invoke()
+ */
+ public function testInvoke()
+ {
+ $this->expectOutputString('test');
+ $handler = $this->obj;
+ $handler(new LogEntry('test'));
+ }
}
\ No newline at end of file
diff --git a/tests/Handler/HandlerAwareTraitTest.php b/tests/Handler/HandlerAwareTraitTest.php
index 75c8bae..a7b233d 100644
--- a/tests/Handler/HandlerAwareTraitTest.php
+++ b/tests/Handler/HandlerAwareTraitTest.php
@@ -1,13 +1,13 @@
file = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'handlerAware';
+ $this->file2 = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'handlerAware2';
+ $this->obj = new myHandlerAware();
+ $this->ref = new \ReflectionClass(get_class($this->obj));
+ }
+
+ protected function tearDown(): void
+ {
+ if (\file_exists($this->file)) {
+ unlink($this->file);
+ }
+ if (\file_exists($this->file2)) {
+ unlink($this->file2);
+ }
+ $this->obj = $this->ref = NULL;
+ parent::tearDown();
+ }
+
+ protected function invokeMethod($methodName, array $parameters = array())
+ {
+ $method = $this->ref->getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($this->obj, $parameters);
+ }
+
/**
* @covers Phoole\Logger\Handler\HandlerAwareTrait::addHandler()
*/
public function testAddHandler()
{
$filelog = new LogfileHandler($this->file);
- $this->obj->addHandler(
- $filelog,
- LogLevel::ERROR
- );
+ $this->obj->addHandler(LogLevel::ERROR, $filelog);
$m = (new LogEntry())->setLevel(LogLevel::INFO);
- $h = $this->obj->getHandlers($m);
+ $h = $this->invokeMethod('getHandlers', [$m]);
$this->assertEquals(0, count($h));
$m = (new LogEntry())->setLevel(LogLevel::ERROR);
- $h = $this->obj->getHandlers($m);
+ $h = $this->invokeMethod('getHandlers', [$m]);
$this->assertEquals(1, count($h));
}
@@ -55,47 +80,20 @@ public function testGetHandlers()
$file = new LogfileHandler($this->file);
$file2 = new LogfileHandler($this->file2);
- $this->obj->addHandler(
- $file,
- LogLevel::INFO
- );
+ $this->obj->addHandler(LogLevel::INFO, $file);
$this->obj->addHandler(
- $file2,
LogLevel::ERROR,
- SystemLog::class
+ $file2,
+ MemoryInfo::class
);
$m = (new LogEntry())->setLevel(LogLevel::ALERT);
- $h = $this->obj->getHandlers($m);
+ $h = $this->invokeMethod('getHandlers', [$m]);
$this->assertEquals(1, count($h));
- $m = (new SystemLog())->setLevel(LogLevel::ALERT);
- $h = $this->obj->getHandlers($m);
+ $m = (new MemoryInfo())->setLevel(LogLevel::ALERT);
+ $h = $this->invokeMethod('getHandlers', [$m]);
$this->assertEquals(2, count($h));
}
-
- protected function setUp(): void
- {
- parent::setUp();
- $this->file = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'handlerAware';
- $this->file2 = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'handlerAware2';
- $this->obj = new myHandlerAware();
- $this->ref = new \ReflectionClass(get_class($this->obj));
- }
-
- protected function tearDown(): void
- {
- //@unlink($this->file);
- //@unlink($this->file2);
- $this->obj = $this->ref = NULL;
- parent::tearDown();
- }
-
- protected function invokeMethod($methodName, array $parameters = array())
- {
- $method = $this->ref->getMethod($methodName);
- $method->setAccessible(TRUE);
- return $method->invokeArgs($this->obj, $parameters);
- }
}
\ No newline at end of file
diff --git a/tests/Handler/LogfileHandlerTest.php b/tests/Handler/LogfileHandlerTest.php
index 8d4087a..af81288 100644
--- a/tests/Handler/LogfileHandlerTest.php
+++ b/tests/Handler/LogfileHandlerTest.php
@@ -1,6 +1,6 @@
file = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'logfileTest';
+ $this->obj = new LogfileHandler($this->file);
+ $this->ref = new \ReflectionClass(get_class($this->obj));
+ }
+
+ protected function tearDown(): void
+ {
+ unlink($this->file);
+ $this->obj = $this->ref = NULL;
+ parent::tearDown();
+ }
+
+ protected function invokeMethod($methodName, array $parameters = array())
+ {
+ $method = $this->ref->getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($this->obj, $parameters);
+ }
+
/**
* @covers Phoole\Logger\Handler\LogfileHandler::__construct()
*/
@@ -40,38 +62,17 @@ public function testDoRotation()
unlink($new);
}
- protected function invokeMethod($methodName, array $parameters = array())
- {
- $method = $this->ref->getMethod($methodName);
- $method->setAccessible(TRUE);
- return $method->invokeArgs($this->obj, $parameters);
- }
-
/**
- * @covers Phoole\Logger\Handler\LogfileHandler::handle()
+ * @covers Phoole\Logger\Handler\LogfileHandler::__invoke()
*/
- public function testHandle()
+ public function testInvoke()
{
$m = new LogEntry('test');
- $this->obj->handle($m);
+ $handler = $this->obj;
+ $handler($m);
$this->assertEquals(
- 'test',
+ 'INFO: test',
trim(file_get_contents($this->file))
);
}
-
- protected function setUp(): void
- {
- parent::setUp();
- $this->file = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'logfileTest';
- $this->obj = new LogfileHandler($this->file);
- $this->ref = new \ReflectionClass(get_class($this->obj));
- }
-
- protected function tearDown(): void
- {
- unlink($this->file);
- $this->obj = $this->ref = NULL;
- parent::tearDown();
- }
}
\ No newline at end of file
diff --git a/tests/Handler/StreamHandlerTest.php b/tests/Handler/StreamHandlerTest.php
index 1b40ab7..62c69a2 100644
--- a/tests/Handler/StreamHandlerTest.php
+++ b/tests/Handler/StreamHandlerTest.php
@@ -1,6 +1,6 @@
assertTrue(file_exists($this->file));
- }
-
- /**
- * @covers Phoole\Logger\Handler\StreamHandler::handle()
- */
- public function testHandle()
- {
- $m = new LogEntry('test');
- $this->obj->handle($m);
- $this->assertEquals(
- 'test',
- trim(file_get_contents($this->file))
- );
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -58,4 +37,26 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Handler\StreamHandler::__construct()
+ */
+ public function testConstruct()
+ {
+ $this->assertTrue(file_exists($this->file));
+ }
+
+ /**
+ * @covers Phoole\Logger\Handler\StreamHandler::__invoke()
+ */
+ public function testInvoke()
+ {
+ $m = new LogEntry('test');
+ $handler = $this->obj;
+ $handler($m);
+ $this->assertEquals(
+ 'INFO: test',
+ trim(file_get_contents($this->file))
+ );
+ }
}
\ No newline at end of file
diff --git a/tests/Handler/TerminalHandlerTest.php b/tests/Handler/TerminalHandlerTest.php
index b34f394..118994e 100644
--- a/tests/Handler/TerminalHandlerTest.php
+++ b/tests/Handler/TerminalHandlerTest.php
@@ -1,6 +1,6 @@
expectExceptionMessage('unknown stream');
- $obj2 = new TerminalHandler('test');
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -42,4 +32,14 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Handler\TerminalHandler::__construct()
+ */
+ public function testConstruct()
+ {
+ $obj1 = new TerminalHandler('php://stdout');
+ $this->expectExceptionMessage('unknown stream');
+ $obj2 = new TerminalHandler('test');
+ }
}
\ No newline at end of file
diff --git a/tests/LoggerTest.php b/tests/LoggerTest.php
index 01e9e5e..784276c 100644
--- a/tests/LoggerTest.php
+++ b/tests/LoggerTest.php
@@ -1,14 +1,20 @@
obj = new Logger('LOG');
+ $this->ref = new \ReflectionClass(get_class($this->obj));
+ }
+
+ protected function tearDown(): void
+ {
+ $this->obj = $this->ref = NULL;
+ parent::tearDown();
+ }
+
+ protected function invokeMethod($methodName, array $parameters = array())
+ {
+ $method = $this->ref->getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($this->obj, $parameters);
+ }
+
/**
* @covers Phoole\Logger\Logger::log()
*/
public function testLog()
{
- $this->obj->addHandler(
- new EchoHandler(),
- LogLevel::INFO
- );
- $this->expectOutputRegex('/test.*peak.*peak.*/s');
+ $echoHandler = new EchoHandler();
- $this->obj->info('test');
+ $this->obj->addHandler(LogLevel::INFO, $echoHandler);
+ $this->expectOutputRegex('/test.*peak.*/s');
- $this->obj->addHandler(
- new EchoHandler(),
- LogLevel::ALERT,
- SystemLog::class
- );
+ $this->obj->info('test');
- $this->obj->alert(new SystemLog());
- $this->assertTrue(TRUE);
+ $this->obj->addHandler(LogLevel::ALERT, $echoHandler, MemoryInfo::class);
+ $this->obj->alert(new MemoryInfo());
}
/**
+ * unknown log level
+ *
* @covers Phoole\Logger\Logger::log()
*/
public function testLog2()
{
- $this->expectExceptionMessage('unknown log');
+ $this->expectExceptionMessage('unknown log level');
$this->obj->log('test', 'test');
}
- protected function setUp(): void
+ /**
+ * closure as handler
+ *
+ * @covers Phoole\Logger\Logger::log()
+ */
+ public function testLog3()
{
- parent::setUp();
- $this->obj = new Logger('LOG');
- $this->ref = new \ReflectionClass(get_class($this->obj));
- }
+ // closure as handler
+ $handler = function(LogEntryInterface $entry) {
+ echo (string) $entry;
+ };
- protected function tearDown(): void
- {
- $this->obj = $this->ref = NULL;
- parent::tearDown();
- }
+ // set class processor
+ $this->obj->addHandler(
+ 'warning',
+ $handler,
+ MyEntry::addProcessor(function(LogEntryInterface $entry) {
+ $context = $entry->getContext();
+ $context['wow'] = 'bingo';
+ $entry->setContext($context);
+ })
+ );
- protected function invokeMethod($methodName, array $parameters = array())
- {
- $method = $this->ref->getMethod($methodName);
- $method->setAccessible(TRUE);
- return $method->invokeArgs($this->obj, $parameters);
+ $this->expectOutputString('my is bingo');
+ $this->obj->info('info is {wow}');
+ $this->obj->error('error is {wow}');
+ $this->obj->error(new MyEntry('my is {wow}'));
}
}
\ No newline at end of file
diff --git a/tests/Processor/MemoryProcessorTest.php b/tests/Processor/MemoryProcessorTest.php
index 2d48c60..c100103 100644
--- a/tests/Processor/MemoryProcessorTest.php
+++ b/tests/Processor/MemoryProcessorTest.php
@@ -1,6 +1,6 @@
'a']);
- $this->obj->process($m);
- $b = $m->getContext();
- $this->assertEquals(3, count($b));
- $this->assertTrue(isset($b['memory_used']));
- $this->assertTrue(isset($b['memory_peak']));
- }
-
protected function setUp(): void
{
parent::setUp();
@@ -46,4 +33,19 @@ protected function invokeMethod($methodName, array $parameters = array())
$method->setAccessible(TRUE);
return $method->invokeArgs($this->obj, $parameters);
}
+
+ /**
+ * @covers Phoole\Logger\Processor\MemoryProcessor::process()
+ */
+ public function testProcess()
+ {
+ $m = new LogEntry('test', ['a' => 'a']);
+ $callable = $this->obj;
+ $callable($m);
+
+ $b = $m->getContext();
+ $this->assertEquals(3, count($b));
+ $this->assertTrue(isset($b['memory_used']));
+ $this->assertTrue(isset($b['memory_peak']));
+ }
}
\ No newline at end of file
diff --git a/tests/Processor/ProcessorAbstractTest.php b/tests/Processor/ProcessorAbstractTest.php
index 89d3520..ffea5da 100644
--- a/tests/Processor/ProcessorAbstractTest.php
+++ b/tests/Processor/ProcessorAbstractTest.php
@@ -1,6 +1,6 @@
invokeMethod('updateContext', [$a]);
- $this->assertEquals(
- ['test' => 'bingo'],
- $b
- );
+ parent::setUp();
+ $this->obj = new myProcessor();
+ $this->ref = new \ReflectionClass(get_class($this->obj));
+ }
+
+ protected function tearDown(): void
+ {
+ $this->obj = $this->ref = NULL;
+ parent::tearDown();
}
protected function invokeMethod($methodName, array $parameters = array())
@@ -44,28 +44,30 @@ protected function invokeMethod($methodName, array $parameters = array())
}
/**
- * @covers Phoole\Logger\Processor\ProcessorAbstract::process()
+ * @covers Phoole\Logger\Processor\ProcessorAbstract::__invoke()
*/
- public function testProcess()
+ public function testInvoke()
{
$m = new LogEntry('test', ['a' => 'a']);
- $this->obj->process($m);
+ $callable = $this->obj;
+ $callable($m);
+
$this->assertEquals(
['a' => 'a', 'test' => 'bingo'],
$m->getContext()
);
}
- protected function setUp(): void
- {
- parent::setUp();
- $this->obj = new myProcessor();
- $this->ref = new \ReflectionClass(get_class($this->obj));
- }
-
- protected function tearDown(): void
+ /**
+ * @covers Phoole\Logger\Processor\ProcessorAbstract::updateContext()
+ */
+ public function testUpdateContext()
{
- $this->obj = $this->ref = NULL;
- parent::tearDown();
+ $a = [];
+ $b = $this->invokeMethod('updateContext', [$a]);
+ $this->assertEquals(
+ ['test' => 'bingo'],
+ $b
+ );
}
}
\ No newline at end of file
diff --git a/tests/Processor/ProcessorAwareTraitTest.php b/tests/Processor/ProcessorAwareTraitTest.php
new file mode 100644
index 0000000..d8f20e2
--- /dev/null
+++ b/tests/Processor/ProcessorAwareTraitTest.php
@@ -0,0 +1,156 @@
+getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($object, $parameters);
+ }
+
+ protected function getPrivateProperty($obj, $propertyName)
+ {
+ $ref = new \ReflectionClass(get_class($obj));
+ $property = $ref->getProperty($propertyName);
+ $property->setAccessible(TRUE);
+ return $property->getValue($obj);
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\ProcessorAwareTrait::initProcessors()
+ */
+ public function testInitProcessors()
+ {
+ $obj = new AA();
+ $res = $this->getPrivateProperty($obj, 'processors');
+ $this->assertEquals(0, count($res));
+
+ $this->invokeMethod($obj, 'initProcessors');
+ $res = $this->getPrivateProperty($obj, 'processors');
+ $this->assertEquals(1, count($res));
+
+ $obj = new A();
+ $this->invokeMethod($obj, 'initProcessors');
+ $res = $this->getPrivateProperty($obj, 'processors');
+ $this->assertEquals(2, count($res));
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\ProcessorAwareTrait::process()
+ */
+ public function testProcess()
+ {
+ $aa = new AA();
+
+ $this->expectOutputString('inAinAA');
+ $aa->process();
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\ProcessorAwareTrait::getClassTree()
+ */
+ public function testGetClassTree()
+ {
+ $obj = new AA();
+ $this->assertEquals(
+ [
+ A::class,
+ AA::class
+ ],
+ $this->invokeMethod($obj, 'getClassTree')
+ );
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\ProcessorAwareTrait::classProcessors()
+ */
+ public function testClassProcessors()
+ {
+ $obj = new AA();
+ $res = $this->invokeMethod($obj, 'classProcessors');
+ $this->assertEquals(1, count($res));
+
+ $obj = new A();
+ $res = $this->invokeMethod($obj, 'classProcessors');
+ $this->assertEquals(1, count($res));
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\ProcessorAwareTrait::GetProcessors()
+ */
+ public function testGetProcessors()
+ {
+ $obj = new AA();
+ $res = $this->invokeMethod($obj, 'getProcessors');
+ $this->assertEquals(2, count($res));
+ }
+
+ /**
+ * @covers Phoole\Logger\Entry\ProcessorAwareTrait::addProcessor()
+ */
+ public function testAddProcessor()
+ {
+ $obj = new AA();
+ $this->invokeMethod($obj, 'getProcessors');
+ $res = $this->getPrivateProperty($obj, 'processors');
+ $this->assertEquals(1, count($res[AA::class]));
+
+ $this->invokeMethod(
+ $obj, 'addProcessor', [
+ function(A $bingo) {
+ echo 'bingo';
+ }
+ ]
+ );
+ $res = $this->getPrivateProperty($obj, 'processors');
+ $this->assertEquals(2, count($res[AA::class]));
+ }
+}
\ No newline at end of file
diff --git a/tests/Processor/VerifyCallableTraitTest.php b/tests/Processor/VerifyCallableTraitTest.php
new file mode 100644
index 0000000..dbb7c03
--- /dev/null
+++ b/tests/Processor/VerifyCallableTraitTest.php
@@ -0,0 +1,43 @@
+getMethod($methodName);
+ $method->setAccessible(TRUE);
+ return $method->invokeArgs($object, $parameters);
+ }
+
+ /**
+ * @covers Phoole\Logger\Processor\VerifyCallableTrait::verifyCallable()
+ */
+ public function testVerifyCallable()
+ {
+ $obj = new LogEntry();
+ $callable = function(LogEntry $entry) { };
+ $this->invokeMethod($obj, 'verifyCallable', [$callable, LogEntry::class]);
+
+ $this->expectExceptionMessage('non valid processor');
+ $callable = function() { };
+ $this->invokeMethod($obj, 'verifyCallable', [$callable, LogEntry::class]);
+ }
+}
\ No newline at end of file