Ensured different loggers are used for swoole and for the app regular logs

This commit is contained in:
Alejandro Celaya 2018-11-25 17:14:03 +01:00
parent 22b02de405
commit 282ffef200
5 changed files with 221 additions and 10 deletions

View file

@ -7,6 +7,7 @@ use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\Processor;
use Zend\Expressive\Swoole\Log\AccessLogInterface;
use const PHP_EOL;
return [
@ -20,17 +21,18 @@ return [
],
'handlers' => [
'shlink_log_handler' => Common\Exec\ExecutionContext::currentContextIsSwoole() ? [
'shlink_rotating_handler' => [
'class' => RotatingFileHandler::class,
'level' => Logger::INFO,
'filename' => 'data/log/shlink_log.log',
'max_files' => 30,
'formatter' => 'dashed',
],
'swoole_access_handler' => [
'class' => StreamHandler::class,
'level' => Logger::INFO,
'stream' => 'php://stdout',
'formatter' => 'dashed',
] : [
'class' => RotatingFileHandler::class,
'level' => Logger::INFO,
'filename' => 'data/log/shlink_log.log',
'formatter' => 'dashed',
'max_files' => 30,
],
],
@ -45,9 +47,30 @@ return [
'loggers' => [
'Shlink' => [
'handlers' => ['shlink_log_handler'],
'handlers' => ['shlink_rotating_handler'],
'processors' => ['exception_with_new_line', 'psr3'],
],
'Swoole' => [
'handlers' => ['swoole_access_handler'],
'processors' => ['psr3'],
],
],
],
'dependencies' => [
'factories' => [
'Logger_Shlink' => Common\Factory\LoggerFactory::class,
'Logger_Swoole' => Common\Factory\LoggerFactory::class,
AccessLogInterface::class => Common\Logger\Swoole\AccessLogFactory::class,
],
],
'zend-expressive-swoole' => [
'swoole-http-server' => [
'logger' => [
'logger_name' => 'Logger_Swoole',
],
],
],

View file

@ -7,7 +7,7 @@ return [
'logger' => [
'handlers' => [
'shlink_log_handler' => [
'shlink_rotating_handler' => [
'level' => Logger::DEBUG,
],
],

View file

@ -23,7 +23,6 @@ return [
EntityManager::class => Factory\EntityManagerFactory::class,
GuzzleClient::class => InvokableFactory::class,
Cache::class => Factory\CacheFactory::class,
'Logger_Shlink' => Factory\LoggerFactory::class,
Filesystem::class => InvokableFactory::class,
Reader::class => ConfigAbstractFactory::class,

View file

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Common\Logger\Swoole;
use Interop\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Zend\Expressive\Swoole\Log;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Exception\ServiceNotFoundException;
use Zend\ServiceManager\Factory\FactoryInterface;
class AccessLogFactory implements FactoryInterface
{
/**
* Create an object
*
* @param ContainerInterface $container
* @param string $requestedName
* @param null|array $options
* @return object
* @throws ServiceNotFoundException if unable to resolve the service.
* @throws ServiceNotCreatedException if an exception is raised when creating a service.
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$config = $container->has('config') ? $container->get('config') : [];
$config = $config['zend-expressive-swoole']['swoole-http-server']['logger'] ?? [];
return new Log\Psr3AccessLogDecorator(
$this->getLogger($container, $config),
$this->getFormatter($container, $config),
$config['use-hostname-lookups'] ?? false
);
}
private function getLogger(ContainerInterface $container, array $config): LoggerInterface
{
$loggerName = $config['logger_name'] ?? LoggerInterface::class;
return $container->has($loggerName) ? $container->get($loggerName) : new Log\StdoutLogger();
}
private function getFormatter(ContainerInterface $container, array $config): Log\AccessLogFormatterInterface
{
if ($container->has(Log\AccessLogFormatterInterface::class)) {
return $container->get(Log\AccessLogFormatterInterface::class);
}
return new Log\AccessLogFormatter($config['format'] ?? Log\AccessLogFormatter::FORMAT_COMMON);
}
}

View file

@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Common\Logger\Swoole;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use ReflectionObject;
use Shlinkio\Shlink\Common\Logger\Swoole\AccessLogFactory;
use Zend\Expressive\Swoole\Log\AccessLogFormatter;
use Zend\Expressive\Swoole\Log\AccessLogFormatterInterface;
use Zend\Expressive\Swoole\Log\Psr3AccessLogDecorator;
use Zend\Expressive\Swoole\Log\StdoutLogger;
use Zend\ServiceManager\ServiceManager;
use function is_string;
class AccessLogFactoryTest extends TestCase
{
/** @var AccessLogFactory */
private $factory;
public function setUp()
{
$this->factory = new AccessLogFactory();
}
/**
* @test
*/
public function createsService()
{
$service = ($this->factory)(new ServiceManager(), '');
$this->assertInstanceOf(Psr3AccessLogDecorator::class, $service);
}
/**
* @test
* @dataProvider provideLoggers
* @param array $config
* @param string|LoggerInterface $expectedLogger
*/
public function wrapsProperLogger(array $config, $expectedLogger)
{
$service = ($this->factory)(new ServiceManager(['services' => $config]), '');
$ref = new ReflectionObject($service);
$loggerProp = $ref->getProperty('logger');
$loggerProp->setAccessible(true);
$logger = $loggerProp->getValue($service);
if (is_string($expectedLogger)) {
$this->assertInstanceOf($expectedLogger, $logger);
} else {
$this->assertSame($expectedLogger, $logger);
}
}
public function provideLoggers(): iterable
{
yield 'without-any-logger' => [[], StdoutLogger::class];
yield 'with-standard-logger' => (function () {
$logger = new NullLogger();
return [[LoggerInterface::class => $logger], $logger];
})();
yield 'with-custom-logger' => (function () {
$logger = new NullLogger();
return [[
'config' => [
'zend-expressive-swoole' => [
'swoole-http-server' => [
'logger' => [
'logger_name' => 'my-logger',
],
],
],
],
'my-logger' => $logger,
], $logger];
})();
}
/**
* @test
* @dataProvider provideFormatters
* @param array $config
* @param string|AccessLogFormatterInterface $expectedFormatter
*/
public function wrappsProperFormatter(array $config, $expectedFormatter, string $expectedFormat)
{
$service = ($this->factory)(new ServiceManager(['services' => $config]), '');
$ref = new ReflectionObject($service);
$formatterProp = $ref->getProperty('formatter');
$formatterProp->setAccessible(true);
$formatter = $formatterProp->getValue($service);
$ref = new ReflectionObject($formatter);
$formatProp = $ref->getProperty('format');
$formatProp->setAccessible(true);
$format = $formatProp->getValue($formatter);
if (is_string($expectedFormatter)) {
$this->assertInstanceOf($expectedFormatter, $formatter);
} else {
$this->assertSame($expectedFormatter, $formatter);
}
$this->assertSame($expectedFormat, $format);
}
public function provideFormatters(): iterable
{
yield 'with-registered-formatter-and-default-format' => (function () {
$formatter = new AccessLogFormatter();
return [[AccessLogFormatterInterface::class => $formatter], $formatter, AccessLogFormatter::FORMAT_COMMON];
})();
yield 'with-registered-formatter-and-custom-format' => (function () {
$formatter = new AccessLogFormatter(AccessLogFormatter::FORMAT_AGENT);
return [[AccessLogFormatterInterface::class => $formatter], $formatter, AccessLogFormatter::FORMAT_AGENT];
})();
yield 'with-no-formatter-and-not-configured-format' => [
[],
AccessLogFormatter::class,
AccessLogFormatter::FORMAT_COMMON,
];
yield 'with-no-formatter-and-configured-format' => [[
'config' => [
'zend-expressive-swoole' => [
'swoole-http-server' => [
'logger' => [
'format' => AccessLogFormatter::FORMAT_COMBINED_DEBIAN,
],
],
],
],
], AccessLogFormatter::class, AccessLogFormatter::FORMAT_COMBINED_DEBIAN];
}
}