diff --git a/CHANGELOG.md b/CHANGELOG.md index 37ec790d8..28e4ea75e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Added - [#405](https://github.com/hyperf-cloud/hyperf/pull/405) Added Context::override() method. +- [#415](https://github.com/hyperf-cloud/hyperf/pull/415) Added handlers configuration for logger, now you could config multiple handlers to logger. ## Fixed - [#414](https://github.com/hyperf-cloud/hyperf/pull/414) Fixed WebSocketExceptionHandler typo diff --git a/src/grpc-client/tests/GPBMetadata/Grpc.php b/src/grpc-client/tests/GPBMetadata/Grpc.php index 1c74297e0..7b5f24f93 100644 --- a/src/grpc-client/tests/GPBMetadata/Grpc.php +++ b/src/grpc-client/tests/GPBMetadata/Grpc.php @@ -1,5 +1,15 @@ internalAddGeneratedFile(hex2bin( - "0aae010a0a677270632e70726f746f12046772706322200a04496e666f12" . - "0a0a026964180120012805120c0a046e616d6518022001280922360a0955" . - "7365725265706c79120f0a076d65737361676518012001280912180a0469" . - "6e666f18022001280b320a2e677270632e496e666f32380a0c757365725f" . - "7365727669636512280a0767657455736572120a2e677270632e496e666f" . - "1a0f2e677270632e557365725265706c792200620670726f746f33" + '0aae010a0a677270632e70726f746f12046772706322200a04496e666f12' . + '0a0a026964180120012805120c0a046e616d6518022001280922360a0955' . + '7365725265706c79120f0a076d65737361676518012001280912180a0469' . + '6e666f18022001280b320a2e677270632e496e666f32380a0c757365725f' . + '7365727669636512280a0767657455736572120a2e677270632e496e666f' . + '1a0f2e677270632e557365725265706c792200620670726f746f33' )); static::$is_initialized = true; } } - diff --git a/src/grpc-client/tests/Grpc/Info.php b/src/grpc-client/tests/Grpc/Info.php index 3031ea6fb..075c46e75 100644 --- a/src/grpc-client/tests/Grpc/Info.php +++ b/src/grpc-client/tests/Grpc/Info.php @@ -1,24 +1,33 @@ grpc.Info + * Generated from protobuf message grpc.Info. */ class Info extends \Google\Protobuf\Internal\Message { /** - * Generated from protobuf field int32 id = 1; + * Generated from protobuf field int32 id = 1;. */ private $id = 0; + /** - * Generated from protobuf field string name = 2; + * Generated from protobuf field string name = 2;. */ private $name = ''; @@ -26,19 +35,20 @@ class Info extends \Google\Protobuf\Internal\Message * Constructor. * * @param array $data { - * Optional. Data for populating the Message object. + * Optional. Data for populating the Message object. * - * @type int $id - * @type string $name + * @var int $id + * @var string $name * } */ - public function __construct($data = NULL) { + public function __construct($data = null) + { \GPBMetadata\Grpc::initOnce(); parent::__construct($data); } /** - * Generated from protobuf field int32 id = 1; + * Generated from protobuf field int32 id = 1;. * @return int */ public function getId() @@ -47,7 +57,7 @@ class Info extends \Google\Protobuf\Internal\Message } /** - * Generated from protobuf field int32 id = 1; + * Generated from protobuf field int32 id = 1;. * @param int $var * @return $this */ @@ -60,7 +70,7 @@ class Info extends \Google\Protobuf\Internal\Message } /** - * Generated from protobuf field string name = 2; + * Generated from protobuf field string name = 2;. * @return string */ public function getName() @@ -69,17 +79,15 @@ class Info extends \Google\Protobuf\Internal\Message } /** - * Generated from protobuf field string name = 2; + * Generated from protobuf field string name = 2;. * @param string $var * @return $this */ public function setName($var) { - GPBUtil::checkString($var, True); + GPBUtil::checkString($var, true); $this->name = $var; return $this; } - } - diff --git a/src/grpc-client/tests/Grpc/UserReply.php b/src/grpc-client/tests/Grpc/UserReply.php index 534a5bbd1..7684a7cc6 100644 --- a/src/grpc-client/tests/Grpc/UserReply.php +++ b/src/grpc-client/tests/Grpc/UserReply.php @@ -1,44 +1,54 @@ grpc.UserReply + * Generated from protobuf message grpc.UserReply. */ class UserReply extends \Google\Protobuf\Internal\Message { /** - * Generated from protobuf field string message = 1; + * Generated from protobuf field string message = 1;. */ private $message = ''; + /** - * Generated from protobuf field .grpc.Info info = 2; + * Generated from protobuf field .grpc.Info info = 2;. */ - private $info = null; + private $info; /** * Constructor. * * @param array $data { - * Optional. Data for populating the Message object. + * Optional. Data for populating the Message object. * - * @type string $message - * @type \Grpc\Info $info + * @var string $message + * @var \Grpc\Info $info * } */ - public function __construct($data = NULL) { + public function __construct($data = null) + { \GPBMetadata\Grpc::initOnce(); parent::__construct($data); } /** - * Generated from protobuf field string message = 1; + * Generated from protobuf field string message = 1;. * @return string */ public function getMessage() @@ -47,20 +57,20 @@ class UserReply extends \Google\Protobuf\Internal\Message } /** - * Generated from protobuf field string message = 1; + * Generated from protobuf field string message = 1;. * @param string $var * @return $this */ public function setMessage($var) { - GPBUtil::checkString($var, True); + GPBUtil::checkString($var, true); $this->message = $var; return $this; } /** - * Generated from protobuf field .grpc.Info info = 2; + * Generated from protobuf field .grpc.Info info = 2;. * @return \Grpc\Info */ public function getInfo() @@ -69,7 +79,7 @@ class UserReply extends \Google\Protobuf\Internal\Message } /** - * Generated from protobuf field .grpc.Info info = 2; + * Generated from protobuf field .grpc.Info info = 2;. * @param \Grpc\Info $var * @return $this */ @@ -80,6 +90,4 @@ class UserReply extends \Google\Protobuf\Internal\Message return $this; } - } - diff --git a/src/grpc-client/tests/RequestTest.php b/src/grpc-client/tests/RequestTest.php index e16953ad4..56a70bb52 100644 --- a/src/grpc-client/tests/RequestTest.php +++ b/src/grpc-client/tests/RequestTest.php @@ -26,10 +26,9 @@ class RequestTest extends TestCase public function testRequest() { $request = new Request($path = 'grpc.service/path', $info = new Info()); - $this->assertSame([ - 'content-type' => 'application/grpc+proto', - 'user-agent' => 'grpc-php-hyperf/1.0 (hyperf-grpc-client/dev-master)', - ], $request->headers); + $this->assertSame(2, count($request->headers)); + $this->assertSame('application/grpc+proto', $request->headers['content-type']); + $this->assertRegExp('/^grpc-php-hyperf\/1.0 \(hyperf-grpc-client\/.*\)$/', $request->headers['user-agent']); $this->assertSame($path, $request->path); $this->assertSame(Parser::serializeMessage($info), $request->data); } @@ -37,10 +36,9 @@ class RequestTest extends TestCase public function testGetDefaultHeaders() { $request = new Request($path = 'grpc.service/path', $info = new Info()); - $this->assertSame([ - 'content-type' => 'application/grpc+proto', - 'user-agent' => 'grpc-php-hyperf/1.0 (hyperf-grpc-client/dev-master)', - ], $request->getDefaultHeaders()); + $this->assertSame(2, count($request->getDefaultHeaders())); + $this->assertSame('application/grpc+proto', $request->getDefaultHeaders()['content-type']); + $this->assertRegExp('/^grpc-php-hyperf\/1.0 \(hyperf-grpc-client\/.*\)$/', $request->getDefaultHeaders()['user-agent']); } public function testUserDefinedHeaders() @@ -49,10 +47,10 @@ class RequestTest extends TestCase 'content-type' => 'application/grpc', 'foo' => 'bar', ]); - $this->assertSame([ - 'content-type' => 'application/grpc', - 'user-agent' => 'grpc-php-hyperf/1.0 (hyperf-grpc-client/dev-master)', - 'foo' => 'bar', - ], $request->headers); + + $this->assertSame(3, count($request->headers)); + $this->assertSame('application/grpc', $request->headers['content-type']); + $this->assertRegExp('/^grpc-php-hyperf\/1.0 \(hyperf-grpc-client\/.*\)$/', $request->headers['user-agent']); + $this->assertSame('bar', $request->headers['foo']); } } diff --git a/src/logger/publish/logger.php b/src/logger/publish/logger.php index 900417b2f..616fed008 100644 --- a/src/logger/publish/logger.php +++ b/src/logger/publish/logger.php @@ -12,16 +12,18 @@ declare(strict_types=1); return [ 'default' => [ - 'handler' => [ - 'class' => \Monolog\Handler\StreamHandler::class, - 'constructor' => [ - 'stream' => BASE_PATH . '/runtime/logs/hyperf.log', - 'level' => \Monolog\Logger::DEBUG, + 'handlers' => [ + [ + 'class' => Monolog\Handler\StreamHandler::class, + 'constructor' => [ + 'stream' => BASE_PATH . '/runtime/logs/hyperf.log', + 'level' => Monolog\Logger::DEBUG, + ], + 'formatter' => [ + 'class' => Monolog\Formatter\LineFormatter::class, + 'constructor' => [], + ], ], ], - 'formatter' => [ - 'class' => \Monolog\Formatter\LineFormatter::class, - 'constructor' => [], - ], ], ]; diff --git a/src/logger/src/LoggerFactory.php b/src/logger/src/LoggerFactory.php index a42efa2f4..dde6b4473 100644 --- a/src/logger/src/LoggerFactory.php +++ b/src/logger/src/LoggerFactory.php @@ -14,8 +14,11 @@ namespace Hyperf\Logger; use Hyperf\Contract\ConfigInterface; use Hyperf\Logger\Exception\InvalidConfigException; +use Hyperf\Utils\Arr; use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; use Monolog\Handler\HandlerInterface; +use Monolog\Handler\StreamHandler; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -50,11 +53,11 @@ class LoggerFactory } $config = $config[$group]; - $handler = $this->handler($config); + $handlers = $this->handlers($config); return make(Logger::class, [ 'name' => $name, - 'handlers' => [$handler], + 'handlers' => $handlers, ]); } @@ -67,16 +70,55 @@ class LoggerFactory return $this->loggers[$name] = $this->make($name, $group); } - protected function handler(array $config): HandlerInterface + protected function getDefaultFormatterConfig($config) { - $handlerClass = $config['handler']['class']; - $handlerConstructor = $config['handler']['constructor']; + $formatterClass = Arr::get($config, 'formatter.class', LineFormatter::class); + $formatterConstructor = Arr::get($config, 'formatter.constructor', []); + return [ + 'class' => $formatterClass, + 'constructor' => $formatterConstructor, + ]; + } + + protected function getDefaultHandlerConfig($config) + { + $handlerClass = Arr::get($config, 'handler.class', StreamHandler::class); + $handlerConstructor = Arr::get($config, 'handler.constructor', [ + 'stream' => BASE_PATH . '/runtime/logs/hyperf.log', + 'level' => Logger::DEBUG, + ]); + + return [ + 'class' => $handlerClass, + 'constructor' => $handlerConstructor, + ]; + } + + protected function handlers(array $config): array + { + $handlerConfigs = $config['handlers'] ?? [[]]; + $handlers = []; + $defaultHandlerConfig = $this->getDefaultHandlerConfig($config); + $defaultFormatterConfig = $this->getDefaultFormatterConfig($config); + foreach ($handlerConfigs as $value) { + $class = $value['class'] ?? $defaultHandlerConfig['class']; + $constructor = $value['constructor'] ?? $defaultHandlerConfig['constructor']; + $formatterConfig = $value['formatter'] ?? $defaultFormatterConfig; + + $handlers[] = $this->handler($class, $constructor, $formatterConfig); + } + + return $handlers; + } + + protected function handler($class, $constructor, $formatterConfig): HandlerInterface + { /** @var HandlerInterface $handler */ - $handler = make($handlerClass, $handlerConstructor); + $handler = make($class, $constructor); - $formatterClass = $config['formatter']['class']; - $formatterConstructor = $config['formatter']['constructor']; + $formatterClass = $formatterConfig['class']; + $formatterConstructor = $formatterConfig['constructor']; /** @var FormatterInterface $formatter */ $formatter = make($formatterClass, $formatterConstructor); diff --git a/src/logger/tests/LoggerFactoryTest.php b/src/logger/tests/LoggerFactoryTest.php index aac705755..c67f3ad4d 100644 --- a/src/logger/tests/LoggerFactoryTest.php +++ b/src/logger/tests/LoggerFactoryTest.php @@ -18,10 +18,13 @@ use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\Logger\LoggerFactory; use Hyperf\Utils\ApplicationContext; use Mockery; +use Monolog\Handler\StreamHandler; +use Monolog\Handler\TestHandler; use Monolog\Logger; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use ReflectionClass; /** * @internal @@ -47,17 +50,43 @@ class LoggerFactoryTest extends TestCase ApplicationContext::setContainer($container); $factory = $container->get(LoggerFactory::class); $logger = $factory->get('hyperf'); - $this->assertInstanceOf(StdoutLoggerInterface::class, $logger); - $this->assertInstanceOf(LoggerInterface::class, $logger); - $this->assertInstanceOf(Logger::class, $logger); $this->assertInstanceOf(\Hyperf\Logger\Logger::class, $logger); } - private function mockContainer() + public function testHandlerConfig() + { + $container = $this->mockContainer(); + $factory = $container->get(LoggerFactory::class); + $logger = $factory->get('hyperf', 'default'); + $this->assertInstanceOf(\Hyperf\Logger\Logger::class, $logger); + $reflectionClass = new ReflectionClass($logger); + $handlersProperty = $reflectionClass->getProperty('handlers'); + $handlersProperty->setAccessible(true); + $handlers = $handlersProperty->getValue($logger); + $this->assertCount(1, $handlers); + $this->assertInstanceOf(StreamHandler::class, current($handlers)); + } + + public function testHandlersConfig() + { + $container = $this->mockContainer(); + $factory = $container->get(LoggerFactory::class); + $logger = $factory->get('hyperf', 'default-handlers'); + $this->assertInstanceOf(\Hyperf\Logger\Logger::class, $logger); + $reflectionClass = new ReflectionClass($logger); + $handlersProperty = $reflectionClass->getProperty('handlers'); + $handlersProperty->setAccessible(true); + $handlers = $handlersProperty->getValue($logger); + $this->assertCount(2, $handlers); + $this->assertInstanceOf(StreamHandler::class, $handlers[0]); + $this->assertInstanceOf(TestHandler::class, $handlers[1]); + } + + private function mockContainer(): ContainerInterface { $container = Mockery::mock(ContainerInterface::class); - $container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([ + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([ 'logger' => [ 'default' => [ 'handler' => [ @@ -72,11 +101,31 @@ class LoggerFactoryTest extends TestCase 'constructor' => [], ], ], + 'default-handlers' => [ + 'handlers' => [ + [ + 'class' => \Monolog\Handler\StreamHandler::class, + 'constructor' => [ + 'stream' => BASE_PATH . '/runtime/logs/hyperf.log', + 'level' => \Monolog\Logger::DEBUG, + ], + ], + [ + 'class' => \Monolog\Handler\TestHandler::class, + 'constructor' => [ + 'level' => \Monolog\Logger::DEBUG, + ], + ] + ], + 'formatter' => [ + 'class' => \Monolog\Formatter\LineFormatter::class, + 'constructor' => [], + ], + ], ], ])); $container->shouldReceive('get') - ->once() ->with(LoggerFactory::class) ->andReturn(new LoggerFactory($container));