From 8a9178950140e05ea3c943563a3dca2e9c747f64 Mon Sep 17 00:00:00 2001 From: Jean <1191198+jlabedo@users.noreply.github.com> Date: Wed, 4 Sep 2024 08:01:01 +0200 Subject: [PATCH] Send logs to dedicated monolog channel in symfony bundle (#369) * refactor LoggingService * use LoggingService to add span event * add monolog channel to symfony extension * fix phpdi container implementation for optional reference * fix phpstan * add test compat with monolog 2.0 * drop code duplication for LoggerExample.php * add `critical` method to LoggingGateway * log to console with laravel * remove EchoLogger --- composer.json | 3 +- .../Fixture/Support/Logger/LoggerExample.php | 180 ------------------ .../Integration/AmqpMessageChannelTest.php | 2 +- .../DbalTransactionInterceptor.php | 4 +- .../DeduplicationInterceptor.php | 8 +- .../src/Deduplication/DeduplicationModule.php | 4 +- .../Fixture/Support/Logger/LoggerExample.php | 180 ------------------ .../DbalBackedMessageChannelTest.php | 2 +- .../DbalDeduplicationInterceptorTest.php | 8 +- .../Lite/InMemoryContainerImplementation.php | 10 - .../src/Lite/LazyInMemoryContainer.php | 10 - .../DynamicChannel/DynamicMessageChannel.php | 6 +- .../RetriesChannelInterceptorBuilder.php | 4 +- .../BasicMessagingModule.php | 15 -- .../src/Messaging/Config/Configuration.php | 2 + .../Config/Container/ContainerConfig.php | 5 - .../Config/MessagingSystemConfiguration.php | 26 +++ .../src/Messaging/Config/ModuleClassList.php | 4 - .../AcknowledgeConfirmationInterceptor.php | 4 +- .../InterceptedChannelAdapterBuilder.php | 3 +- .../InterceptedConsumerRunner.php | 4 +- .../InterceptedPollingConsumerBuilder.php | 3 +- ...PollingConsumerErrorChannelInterceptor.php | 6 +- .../Gateway/ErrorChannelInterceptor.php | 4 +- .../InMemoryReferenceSearchService.php | 5 - .../Handler/Logger/Config/LoggingModule.php | 11 +- .../Handler/Logger/LoggingGateway.php | 29 +-- .../Handler/Logger/LoggingHandlerBuilder.php | 136 ------------- .../Handler/Logger/LoggingInterceptor.php | 69 +++---- .../Handler/Logger/LoggingService.php | 149 +++------------ .../Messaging/Handler/Logger/QuickLogger.php | 24 --- .../Handler/Logger/StubLoggingGateway.php | 53 +++--- .../Logger/SubscribableLoggingGateway.php | 15 ++ .../Handler/Recoverability/ErrorHandler.php | 6 +- .../Handler/Recoverability/RetryTemplate.php | 2 +- .../src/Modelling/Config/EventBusRouter.php | 4 +- .../InstantRetry/InstantRetryInterceptor.php | 4 +- packages/Ecotone/src/Test/LoggerExample.php | 12 +- .../Lite/LiteContainerImplementationTest.php | 4 +- .../MessagingTestSupportFrameworkTest.php | 3 +- .../AnnotationBasedMessagingContext.php | 2 - .../Handler/ErrorHandler/ErrorHandlerTest.php | 6 +- .../Logger/LoggingHandlerBuilderTest.php | 45 ----- .../Handler/Logger/LoggingInterceptorTest.php | 124 ++++++++++++ .../Unit/Handler/Logger/LoggingModuleTest.php | 5 +- .../Handler/Logger/LoggingServiceTest.php | 145 -------------- .../src/EnqueueAcknowledgementCallback.php | 2 +- packages/Laravel/src/EcotoneProvider.php | 31 +-- .../src/PhpDiContainerImplementation.php | 21 +- .../OpenTelemetry/src/AddSpanEventLogger.php | 35 ++++ .../src/Configuration/OpenTelemetryModule.php | 6 +- ...RegisterAddSpanEventLoggerCompilerPass.php | 26 +++ .../OpenTelemetry/src/TracerInterceptor.php | 31 --- .../tests/Integration/MultiTenantTest.php | 4 - .../Fixture/Support/Logger/LoggerExample.php | 180 ------------------ .../RedisBackedMessageChannelTest.php | 2 +- .../Fixture/Support/Logger/LoggerExample.php | 180 ------------------ .../SqsBackedMessageChannelTest.php | 2 +- .../DependencyInjection/EcotoneExtension.php | 3 + packages/Symfony/composer.json | 7 +- packages/Symfony/config/bundles.php | 2 + .../test_monolog_integration/framework.yaml | 5 + .../test_monolog_integration/monolog.yaml | 6 + .../tests/phpunit/SymfonyApplicationTest.php | 30 +++ 64 files changed, 469 insertions(+), 1454 deletions(-) delete mode 100644 packages/Amqp/tests/Fixture/Support/Logger/LoggerExample.php delete mode 100644 packages/Dbal/tests/Fixture/Support/Logger/LoggerExample.php delete mode 100644 packages/Ecotone/src/Messaging/Handler/Logger/LoggingHandlerBuilder.php delete mode 100644 packages/Ecotone/src/Messaging/Handler/Logger/QuickLogger.php create mode 100644 packages/Ecotone/src/Messaging/Handler/Logger/SubscribableLoggingGateway.php delete mode 100644 packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingHandlerBuilderTest.php create mode 100644 packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingInterceptorTest.php delete mode 100644 packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingServiceTest.php create mode 100644 packages/OpenTelemetry/src/AddSpanEventLogger.php create mode 100644 packages/OpenTelemetry/src/Configuration/RegisterAddSpanEventLoggerCompilerPass.php delete mode 100644 packages/Redis/tests/Fixture/Support/Logger/LoggerExample.php delete mode 100644 packages/Sqs/tests/Fixture/Support/Logger/LoggerExample.php create mode 100644 packages/Symfony/config/packages/test_monolog_integration/framework.yaml create mode 100644 packages/Symfony/config/packages/test_monolog_integration/monolog.yaml diff --git a/composer.json b/composer.json index 48ac981a1..ff3d2f9ac 100644 --- a/composer.json +++ b/composer.json @@ -157,7 +157,8 @@ "open-telemetry/exporter-otlp": "^1.0.0", "nesbot/carbon": "^2.71", "moneyphp/money": "^4.1.0", - "timacdonald/log-fake": "^2.0" + "timacdonald/log-fake": "^2.0", + "symfony/monolog-bundle": "^3.10" }, "conflict": { "symfony/doctrine-messenger": ">7.0.5 < 7.1.0" diff --git a/packages/Amqp/tests/Fixture/Support/Logger/LoggerExample.php b/packages/Amqp/tests/Fixture/Support/Logger/LoggerExample.php deleted file mode 100644 index 471df84ef..000000000 --- a/packages/Amqp/tests/Fixture/Support/Logger/LoggerExample.php +++ /dev/null @@ -1,180 +0,0 @@ - - */ -/** - * licence Apache-2.0 - */ -class LoggerExample implements LoggerInterface -{ - private array $emergency = []; - private array $alert = []; - private array $critical = []; - private array $error = []; - private array $warning = []; - private array $notice = []; - private array $info = []; - private array $debug = []; - private array $log = []; - - private function __construct() - { - } - - public static function create(): self - { - return new self(); - } - - /** - * @return array - */ - public function getEmergency(): array - { - return $this->emergency; - } - - /** - * @return array - */ - public function getAlert(): array - { - return $this->alert; - } - - /** - * @return array - */ - public function getCritical(): array - { - return $this->critical; - } - - /** - * @return array - */ - public function getError(): array - { - return $this->error; - } - - /** - * @return array - */ - public function getWarning(): array - { - return $this->warning; - } - - /** - * @return array - */ - public function getNotice(): array - { - return $this->notice; - } - - /** - * @return array - */ - public function getInfo(): array - { - return $this->info; - } - - /** - * @return array - */ - public function getDebug(): array - { - return $this->debug; - } - - /** - * @return array - */ - public function getLog(): array - { - return $this->log; - } - - /** - * @inheritDoc - */ - public function emergency(string|Stringable $message, array $context = []): void - { - $this->emergency[] = $message; - } - - /** - * @inheritDoc - */ - public function alert(string|Stringable $message, array $context = []): void - { - $this->alert[] = $message; - } - - /** - * @inheritDoc - */ - public function critical(string|Stringable $message, array $context = []): void - { - $this->critical[] = $message; - } - - /** - * @inheritDoc - */ - public function error(string|Stringable $message, array $context = []): void - { - $this->error[] = $message; - } - - /** - * @inheritDoc - */ - public function warning(string|Stringable $message, array $context = []): void - { - $this->warning[] = $message; - } - - /** - * @inheritDoc - */ - public function notice(string|Stringable $message, array $context = []): void - { - $this->notice[] = $message; - } - - /** - * @inheritDoc - */ - public function info(string|Stringable $message, array $context = []): void - { - $this->info[] = $message; - } - - /** - * @inheritDoc - */ - public function debug(string|Stringable $message, array $context = []): void - { - $this->debug[] = $message; - } - - /** - * @inheritDoc - */ - public function log($level, string|Stringable $message, array $context = []): void - { - $this->log[] = $level; - } -} diff --git a/packages/Amqp/tests/Integration/AmqpMessageChannelTest.php b/packages/Amqp/tests/Integration/AmqpMessageChannelTest.php index cae9a0e91..468cd5ccd 100644 --- a/packages/Amqp/tests/Integration/AmqpMessageChannelTest.php +++ b/packages/Amqp/tests/Integration/AmqpMessageChannelTest.php @@ -15,13 +15,13 @@ use Ecotone\Messaging\Handler\Recoverability\RetryTemplateBuilder; use Ecotone\Messaging\PollableChannel; use Ecotone\Messaging\Support\MessageBuilder; +use Ecotone\Test\LoggerExample; use Enqueue\AmqpExt\AmqpConnectionFactory; use Interop\Amqp\Impl\AmqpQueue; use Ramsey\Uuid\Uuid; use Test\Ecotone\Amqp\AmqpMessagingTest; use Test\Ecotone\Amqp\Fixture\DeadLetter\ErrorConfigurationContext; use Test\Ecotone\Amqp\Fixture\Order\OrderService; -use Test\Ecotone\Amqp\Fixture\Support\Logger\LoggerExample; /** * @internal diff --git a/packages/Dbal/src/DbalTransaction/DbalTransactionInterceptor.php b/packages/Dbal/src/DbalTransaction/DbalTransactionInterceptor.php index 164c54ba5..5078e9950 100644 --- a/packages/Dbal/src/DbalTransaction/DbalTransactionInterceptor.php +++ b/packages/Dbal/src/DbalTransaction/DbalTransactionInterceptor.php @@ -97,7 +97,7 @@ public function transactional(MethodInvocation $methodInvocation, Message $messa $logger->info( 'Implicit Commit was detected, skipping manual one.', $message, - $exception + ['exception' => $exception], ); try { @@ -117,7 +117,7 @@ public function transactional(MethodInvocation $methodInvocation, Message $messa $logger->info( 'Exception has been thrown, rolling back transaction.', $message, - $exception + ['exception' => $exception] ); /** Doctrine hold the state, so it needs to be cleaned */ diff --git a/packages/Dbal/src/Deduplication/DeduplicationInterceptor.php b/packages/Dbal/src/Deduplication/DeduplicationInterceptor.php index 535a87068..59a9277cd 100644 --- a/packages/Dbal/src/Deduplication/DeduplicationInterceptor.php +++ b/packages/Dbal/src/Deduplication/DeduplicationInterceptor.php @@ -10,6 +10,7 @@ use Ecotone\Messaging\Attribute\AsynchronousRunningEndpoint; use Ecotone\Messaging\Attribute\Deduplicated; use Ecotone\Messaging\Attribute\IdentifiedAnnotation; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; use Ecotone\Messaging\Handler\Processor\MethodInvoker\MethodInvocation; use Ecotone\Messaging\Message; use Ecotone\Messaging\MessageHeaders; @@ -17,7 +18,6 @@ use Enqueue\Dbal\DbalContext; use Interop\Queue\ConnectionFactory; use Interop\Queue\Exception\Exception; -use Psr\Log\LoggerInterface; use function spl_object_id; @@ -36,11 +36,11 @@ class DeduplicationInterceptor public const DEFAULT_DEDUPLICATION_TABLE = 'ecotone_deduplication'; private array $initialized = []; - public function __construct(private ConnectionFactory $connection, private Clock $clock, private int $minimumTimeToRemoveMessageInMilliseconds, private LoggerInterface $logger) + public function __construct(private ConnectionFactory $connection, private Clock $clock, private int $minimumTimeToRemoveMessageInMilliseconds, private LoggingGateway $logger) { } - public function deduplicate(MethodInvocation $methodInvocation, Message $message, ?Deduplicated $deduplicatedAttribute, ?IdentifiedAnnotation $identifiedAnnotation, ?AsynchronousRunningEndpoint $asynchronousRunningEndpoint) + public function deduplicate(MethodInvocation $methodInvocation, Message $message, ?Deduplicated $deduplicatedAttribute, ?IdentifiedAnnotation $identifiedAnnotation, ?AsynchronousRunningEndpoint $asynchronousRunningEndpoint): mixed { $connectionFactory = CachedConnectionFactory::createFor(new DbalReconnectableConnectionFactory($this->connection)); $contextId = spl_object_id($connectionFactory->createContext()); @@ -77,7 +77,7 @@ public function deduplicate(MethodInvocation $methodInvocation, Message $message 'consumer_endpoint_id' => $consumerEndpointId, 'routing_slip' => $routingSlip, ]); - return; + return null; } try { diff --git a/packages/Dbal/src/Deduplication/DeduplicationModule.php b/packages/Dbal/src/Deduplication/DeduplicationModule.php index 90b8d3514..9e7c28251 100644 --- a/packages/Dbal/src/Deduplication/DeduplicationModule.php +++ b/packages/Dbal/src/Deduplication/DeduplicationModule.php @@ -15,10 +15,10 @@ use Ecotone\Messaging\Config\ModulePackageList; use Ecotone\Messaging\Config\ModuleReferenceSearchService; use Ecotone\Messaging\Handler\InterfaceToCallRegistry; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; use Ecotone\Messaging\Handler\Processor\MethodInvoker\AroundInterceptorBuilder; use Ecotone\Messaging\Precedence; use Ecotone\Messaging\Scheduling\Clock; -use Psr\Log\LoggerInterface; #[ModuleAnnotation] /** @@ -64,7 +64,7 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO new Reference($connectionFactory), new Reference(Clock::class), $minimumTimeToRemoveMessageFromDeduplication, - new Reference(LoggerInterface::class), + new Reference(LoggingGateway::class), ] ) ); diff --git a/packages/Dbal/tests/Fixture/Support/Logger/LoggerExample.php b/packages/Dbal/tests/Fixture/Support/Logger/LoggerExample.php deleted file mode 100644 index d6de24e2e..000000000 --- a/packages/Dbal/tests/Fixture/Support/Logger/LoggerExample.php +++ /dev/null @@ -1,180 +0,0 @@ - - */ -/** - * licence Apache-2.0 - */ -class LoggerExample implements LoggerInterface -{ - private array $emergency = []; - private array $alert = []; - private array $critical = []; - private array $error = []; - private array $warning = []; - private array $notice = []; - private array $info = []; - private array $debug = []; - private array $log = []; - - private function __construct() - { - } - - public static function create(): self - { - return new self(); - } - - /** - * @return array - */ - public function getEmergency(): array - { - return $this->emergency; - } - - /** - * @return array - */ - public function getAlert(): array - { - return $this->alert; - } - - /** - * @return array - */ - public function getCritical(): array - { - return $this->critical; - } - - /** - * @return array - */ - public function getError(): array - { - return $this->error; - } - - /** - * @return array - */ - public function getWarning(): array - { - return $this->warning; - } - - /** - * @return array - */ - public function getNotice(): array - { - return $this->notice; - } - - /** - * @return array - */ - public function getInfo(): array - { - return $this->info; - } - - /** - * @return array - */ - public function getDebug(): array - { - return $this->debug; - } - - /** - * @return array - */ - public function getLog(): array - { - return $this->log; - } - - /** - * @inheritDoc - */ - public function emergency(string|Stringable $message, array $context = []): void - { - $this->emergency[] = $message; - } - - /** - * @inheritDoc - */ - public function alert(string|Stringable $message, array $context = []): void - { - $this->alert[] = $message; - } - - /** - * @inheritDoc - */ - public function critical(string|Stringable $message, array $context = []): void - { - $this->critical[] = $message; - } - - /** - * @inheritDoc - */ - public function error(string|Stringable $message, array $context = []): void - { - $this->error[] = $message; - } - - /** - * @inheritDoc - */ - public function warning(string|Stringable $message, array $context = []): void - { - $this->warning[] = $message; - } - - /** - * @inheritDoc - */ - public function notice(string|Stringable $message, array $context = []): void - { - $this->notice[] = $message; - } - - /** - * @inheritDoc - */ - public function info(string|Stringable $message, array $context = []): void - { - $this->info[] = $message; - } - - /** - * @inheritDoc - */ - public function debug(string|Stringable $message, array $context = []): void - { - $this->debug[] = $message; - } - - /** - * @inheritDoc - */ - public function log($level, string|Stringable $message, array $context = []): void - { - $this->log[] = $level; - } -} diff --git a/packages/Dbal/tests/Integration/DbalBackedMessageChannelTest.php b/packages/Dbal/tests/Integration/DbalBackedMessageChannelTest.php index 4bf2f8f17..8f9a2683f 100644 --- a/packages/Dbal/tests/Integration/DbalBackedMessageChannelTest.php +++ b/packages/Dbal/tests/Integration/DbalBackedMessageChannelTest.php @@ -14,12 +14,12 @@ use Ecotone\Messaging\PollableChannel; use Ecotone\Messaging\Support\MessageBuilder; use Ecotone\Test\ComponentTestBuilder; +use Ecotone\Test\LoggerExample; use Enqueue\Dbal\DbalConnectionFactory; use Enqueue\Dbal\DbalContext; use Ramsey\Uuid\Uuid; use Test\Ecotone\Dbal\DbalMessagingTestCase; use Test\Ecotone\Dbal\Fixture\AsynchronousHandler\OrderService; -use Test\Ecotone\Dbal\Fixture\Support\Logger\LoggerExample; /** * @internal diff --git a/packages/Dbal/tests/Integration/Deduplication/DbalDeduplicationInterceptorTest.php b/packages/Dbal/tests/Integration/Deduplication/DbalDeduplicationInterceptorTest.php index fec3c54de..eebf70745 100644 --- a/packages/Dbal/tests/Integration/Deduplication/DbalDeduplicationInterceptorTest.php +++ b/packages/Dbal/tests/Integration/Deduplication/DbalDeduplicationInterceptorTest.php @@ -4,11 +4,11 @@ use Ecotone\Dbal\Deduplication\DeduplicationInterceptor; use Ecotone\Messaging\Attribute\AsynchronousRunningEndpoint; +use Ecotone\Messaging\Handler\Logger\StubLoggingGateway; use Ecotone\Messaging\MessageHeaders; use Ecotone\Messaging\Scheduling\EpochBasedClock; use Ecotone\Messaging\Scheduling\StubUTCClock; use Ecotone\Messaging\Support\MessageBuilder; -use Psr\Log\NullLogger; use Test\Ecotone\Dbal\DbalMessagingTestCase; use Test\Ecotone\Dbal\Fixture\StubMethodInvocation; @@ -27,7 +27,7 @@ public function test_not_deduplicating_for_different_endpoints() $this->getConnectionFactory(), new EpochBasedClock(), 1000, - new NullLogger() + new StubLoggingGateway() ); $methodInvocation = StubMethodInvocation::create(); @@ -59,7 +59,7 @@ public function test_not_handling_same_message_twice() $this->getConnectionFactory(), new EpochBasedClock(), 1000, - new NullLogger() + new StubLoggingGateway() ); $methodInvocation = StubMethodInvocation::create(); @@ -92,7 +92,7 @@ public function test_handling_message_with_same_id_when_it_was_removed_by_time_l $this->getConnectionFactory(), $clock, 1000, - new NullLogger() + new StubLoggingGateway() ); $methodInvocation = StubMethodInvocation::create(); diff --git a/packages/Ecotone/src/Lite/InMemoryContainerImplementation.php b/packages/Ecotone/src/Lite/InMemoryContainerImplementation.php index da3aaebd2..56424f7f5 100644 --- a/packages/Ecotone/src/Lite/InMemoryContainerImplementation.php +++ b/packages/Ecotone/src/Lite/InMemoryContainerImplementation.php @@ -17,8 +17,6 @@ use function method_exists; use Psr\Container\ContainerInterface; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use ReflectionMethod; use function str_starts_with; @@ -111,14 +109,6 @@ private function resolveReference(Reference $reference, ContainerBuilder $builde if ($this->externalContainer?->has(self::ALIAS_PREFIX . $id)) { return $this->externalContainer->get(self::ALIAS_PREFIX . $id); } - // This is the only default service we provide - if ($id === 'logger' || $id === LoggerInterface::class) { - $alias = $id === 'logger' ? LoggerInterface::class : 'logger'; - $logger = $this->externalContainer?->has($alias) ? $this->externalContainer->get($alias) : new NullLogger(); - $this->container->set('logger', $logger); - $this->container->set(LoggerInterface::class, $logger); - return $logger; - } if ($reference->getInvalidBehavior() === self::NULL_ON_INVALID_REFERENCE) { return null; } diff --git a/packages/Ecotone/src/Lite/LazyInMemoryContainer.php b/packages/Ecotone/src/Lite/LazyInMemoryContainer.php index 339ca82aa..ee70b4d0d 100644 --- a/packages/Ecotone/src/Lite/LazyInMemoryContainer.php +++ b/packages/Ecotone/src/Lite/LazyInMemoryContainer.php @@ -8,8 +8,6 @@ use Ecotone\Messaging\Config\DefinedObjectWrapper; use InvalidArgumentException; use Psr\Container\ContainerInterface; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use ReflectionMethod; /** @@ -93,14 +91,6 @@ private function resolveReference(Reference $reference): mixed if ($this->externalContainer?->has(InMemoryContainerImplementation::ALIAS_PREFIX . $id)) { return $this->externalContainer->get(InMemoryContainerImplementation::ALIAS_PREFIX . $id); } - // This is the only default service we provide - if ($id === 'logger' || $id === LoggerInterface::class) { - $alias = $id === 'logger' ? LoggerInterface::class : 'logger'; - $logger = $this->externalContainer?->has($alias) ? $this->externalContainer->get($alias) : new NullLogger(); - $this->resolvedObjects['logger'] = $logger; - $this->resolvedObjects[LoggerInterface::class] = $logger; - return $logger; - } if ($reference->getInvalidBehavior() === ContainerImplementation::NULL_ON_INVALID_REFERENCE) { return null; } diff --git a/packages/Ecotone/src/Messaging/Channel/DynamicChannel/DynamicMessageChannel.php b/packages/Ecotone/src/Messaging/Channel/DynamicChannel/DynamicMessageChannel.php index 8b07b5b20..28c677332 100644 --- a/packages/Ecotone/src/Messaging/Channel/DynamicChannel/DynamicMessageChannel.php +++ b/packages/Ecotone/src/Messaging/Channel/DynamicChannel/DynamicMessageChannel.php @@ -34,7 +34,7 @@ public function send(Message $message): void Assert::notNullAndEmpty($channelName, "Channel name to send message to cannot be null. If you want to skip message sending, return 'nullChannel' instead."); $channel = $this->channelResolver->resolve($channelName); - $this->loggingGateway->info("Decided to send message to `{$channelName}` for `{$this->channelName}`", $message, contextData: ['channel_name' => $this->channelName, 'chosen_channel_name' => $channelName]); + $this->loggingGateway->info("Decided to send message to `{$channelName}` for `{$this->channelName}`", $message, ['channel_name' => $this->channelName, 'chosen_channel_name' => $channelName]); $channel->send($message); } @@ -46,7 +46,7 @@ public function receiveWithTimeout(int $timeoutInMilliseconds): ?Message $channel = $this->resolveMessageChannel($channelName); $message = $channel->receiveWithTimeout($timeoutInMilliseconds); - $this->loggingGateway->info("Decided to received message from `{$channelName}` for `{$this->channelName}`", $message, contextData: ['channel_name' => $this->channelName, 'chosen_channel_name' => $channelName]); + $this->loggingGateway->info("Decided to received message from `{$channelName}` for `{$this->channelName}`", $message, ['channel_name' => $this->channelName, 'chosen_channel_name' => $channelName]); return $message; } @@ -59,7 +59,7 @@ public function receive(): ?Message $channel = $this->resolveMessageChannel($channelName); $message = $channel->receive(); - $this->loggingGateway->info("Decided to received message from `{$channelName}` for `{$this->channelName}`", $message, contextData: ['channel_name' => $this->channelName, 'chosen_channel_name' => $channelName]); + $this->loggingGateway->info("Decided to received message from `{$channelName}` for `{$this->channelName}`", $message, ['channel_name' => $this->channelName, 'chosen_channel_name' => $channelName]); return $message; } diff --git a/packages/Ecotone/src/Messaging/Channel/PollableChannel/SendRetries/RetriesChannelInterceptorBuilder.php b/packages/Ecotone/src/Messaging/Channel/PollableChannel/SendRetries/RetriesChannelInterceptorBuilder.php index 16eab9f09..b93b7c8e0 100644 --- a/packages/Ecotone/src/Messaging/Channel/PollableChannel/SendRetries/RetriesChannelInterceptorBuilder.php +++ b/packages/Ecotone/src/Messaging/Channel/PollableChannel/SendRetries/RetriesChannelInterceptorBuilder.php @@ -9,9 +9,9 @@ use Ecotone\Messaging\Config\Container\Definition; use Ecotone\Messaging\Config\Container\MessagingContainerBuilder; use Ecotone\Messaging\Config\Container\Reference; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; use Ecotone\Messaging\Handler\Recoverability\RetryTemplate; use Ecotone\Messaging\PrecedenceChannelInterceptor; -use Psr\Log\LoggerInterface; /** * licence Apache-2.0 @@ -42,7 +42,7 @@ public function compile(MessagingContainerBuilder $builder): Definition $this->retryTemplate, $this->errorChannel, new Reference(ConfiguredMessagingSystem::class), - new Reference(LoggerInterface::class), + new Reference(LoggingGateway::class), ]); } } diff --git a/packages/Ecotone/src/Messaging/Config/Annotation/ModuleConfiguration/BasicMessagingModule.php b/packages/Ecotone/src/Messaging/Config/Annotation/ModuleConfiguration/BasicMessagingModule.php index 4d8ae54d5..94c526061 100644 --- a/packages/Ecotone/src/Messaging/Config/Annotation/ModuleConfiguration/BasicMessagingModule.php +++ b/packages/Ecotone/src/Messaging/Config/Annotation/ModuleConfiguration/BasicMessagingModule.php @@ -11,12 +11,10 @@ use Ecotone\Messaging\Config\Annotation\ModuleConfiguration\MessagingCommands\MessagingCommandsModule; use Ecotone\Messaging\Config\Configuration; use Ecotone\Messaging\Config\Container\Definition; -use Ecotone\Messaging\Config\Container\Reference; use Ecotone\Messaging\Config\LicenceDecider; use Ecotone\Messaging\Config\ModulePackageList; use Ecotone\Messaging\Config\ModuleReferenceSearchService; use Ecotone\Messaging\Config\ServiceConfiguration; -use Ecotone\Messaging\Conversion\ConversionService; use Ecotone\Messaging\Conversion\ObjectToSerialized\SerializingConverterBuilder; use Ecotone\Messaging\Conversion\SerializedToObject\DeserializingConverterBuilder; use Ecotone\Messaging\Conversion\StringToUuid\StringToUuidConverterBuilder; @@ -33,8 +31,6 @@ use Ecotone\Messaging\Handler\Gateway\ParameterToMessageConverter\GatewayHeadersBuilder; use Ecotone\Messaging\Handler\Gateway\ParameterToMessageConverter\GatewayPayloadBuilder; use Ecotone\Messaging\Handler\InterfaceToCallRegistry; -use Ecotone\Messaging\Handler\Logger\LoggingHandlerBuilder; -use Ecotone\Messaging\Handler\Logger\LoggingService; use Ecotone\Messaging\Handler\MessageHandlerBuilder; use Ecotone\Messaging\Handler\Processor\MethodInvoker\Converter\PollingMetadataConverter; use Ecotone\Messaging\Handler\Router\HeaderRouter; @@ -197,17 +193,6 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO ]) ); - $messagingConfiguration->registerServiceDefinition( - LoggingService::class, - new Definition( - LoggingService::class, - [ - Reference::to(ConversionService::REFERENCE_NAME), - Reference::to(LoggingHandlerBuilder::LOGGER_REFERENCE), - ] - ) - ); - $messagingConfiguration->registerServiceDefinition(PollingMetadataConverter::class, new Definition(PollingMetadataConverter::class)); $messagingConfiguration->registerServiceDefinition(LicenceDecider::class, new Definition(LicenceDecider::class, [$messagingConfiguration->isRunningForEnterpriseLicence()])); } diff --git a/packages/Ecotone/src/Messaging/Config/Configuration.php b/packages/Ecotone/src/Messaging/Config/Configuration.php index 3f1658627..0e8a501f8 100644 --- a/packages/Ecotone/src/Messaging/Config/Configuration.php +++ b/packages/Ecotone/src/Messaging/Config/Configuration.php @@ -143,5 +143,7 @@ public function registerServiceAlias(string|Reference $id, Reference $aliasTo): public function isRunningForEnterpriseLicence(): bool; + public function addCompilerPass(CompilerPass $compilerPass): self; + public function isRunningForTest(): bool; } diff --git a/packages/Ecotone/src/Messaging/Config/Container/ContainerConfig.php b/packages/Ecotone/src/Messaging/Config/Container/ContainerConfig.php index a59d207a4..10a11ba4d 100644 --- a/packages/Ecotone/src/Messaging/Config/Container/ContainerConfig.php +++ b/packages/Ecotone/src/Messaging/Config/Container/ContainerConfig.php @@ -11,8 +11,6 @@ use Ecotone\Messaging\Config\ServiceCacheConfiguration; use Ecotone\Messaging\ConfigurationVariableService; use Ecotone\Messaging\Handler\Gateway\ProxyFactory; -use Ecotone\Messaging\Handler\Logger\LoggingGateway; -use Ecotone\Messaging\Handler\Logger\StubLoggingGateway; use Ecotone\Messaging\InMemoryConfigurationVariableService; use Psr\Container\ContainerInterface; @@ -35,9 +33,6 @@ public static function buildMessagingSystemInMemoryContainer( $container = new LazyInMemoryContainer($containerBuilder->getDefinitions(), $externalContainer); $container->set(ConfigurationVariableService::REFERENCE_NAME, $configurationVariableService ?? InMemoryConfigurationVariableService::createEmpty()); $container->set(ProxyFactory::class, $proxyFactory ?? new ProxyFactory(ServiceCacheConfiguration::noCache())); - if (! $container->has(LoggingGateway::class)) { - $container->set(LoggingGateway::class, StubLoggingGateway::create()); - } return $container->get(ConfiguredMessagingSystem::class); } diff --git a/packages/Ecotone/src/Messaging/Config/MessagingSystemConfiguration.php b/packages/Ecotone/src/Messaging/Config/MessagingSystemConfiguration.php index c31caa62c..5fa07a706 100644 --- a/packages/Ecotone/src/Messaging/Config/MessagingSystemConfiguration.php +++ b/packages/Ecotone/src/Messaging/Config/MessagingSystemConfiguration.php @@ -4,6 +4,7 @@ namespace Ecotone\Messaging\Config; +use Ecotone\Messaging\Config\Container\Compiler\CompilerPass; use Ecotone\Messaging\Config\Annotation\ModuleConfiguration\ExtensionObjectResolver; use function array_map; @@ -17,11 +18,14 @@ use Ecotone\Messaging\Channel\PollableChannelInterceptorAdapter; use Ecotone\Messaging\Channel\SimpleMessageChannelBuilder; use Ecotone\Messaging\Config\Annotation\AnnotationModuleRetrievingService; + use Ecotone\Messaging\Config\Annotation\ModuleConfiguration\AsynchronousModule; + use Ecotone\Messaging\Config\Annotation\ModuleConfiguration\MethodInterceptor\BeforeSendChannelInterceptorBuilder; use Ecotone\Messaging\Config\Container\AttributeDefinition; use Ecotone\Messaging\Config\Container\ChannelReference; use Ecotone\Messaging\Config\Container\CompilableBuilder; +use Ecotone\Messaging\Config\Container\Compiler\ContainerImplementation; use Ecotone\Messaging\Config\Container\Compiler\RegisterSingletonMessagingServices; use Ecotone\Messaging\Config\Container\ContainerBuilder; use Ecotone\Messaging\Config\Container\ContainerConfig; @@ -42,6 +46,8 @@ use Ecotone\Messaging\Handler\InterceptedEndpoint; use Ecotone\Messaging\Handler\InterfaceToCall; use Ecotone\Messaging\Handler\InterfaceToCallRegistry; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; +use Ecotone\Messaging\Handler\Logger\LoggingService; use Ecotone\Messaging\Handler\MessageHandlerBuilder; use Ecotone\Messaging\Handler\MessageHandlerBuilderWithOutputChannel; use Ecotone\Messaging\Handler\Processor\MethodInvoker\AroundInterceptorBuilder; @@ -153,6 +159,10 @@ final class MessagingSystemConfiguration implements Configuration private InterfaceToCallRegistry $interfaceToCallRegistry; private bool $isRunningForEnterpriseLicence; + /** + * @var CompilerPass[] $compilerPasses + */ + private array $compilerPasses = []; private bool $isRunningForTest = false; @@ -826,6 +836,13 @@ public function isRunningForTest(): bool return $this->isRunningForTest; } + public function addCompilerPass(CompilerPass $compilerPass): self + { + $this->compilerPasses[] = $compilerPass; + + return $this; + } + /** * @inheritDoc */ @@ -847,6 +864,12 @@ public function process(ContainerBuilder $builder): void $messagingBuilder->register($id, $definition); } + $messagingBuilder->register( + LoggingGateway::class, + (new Definition(LoggingService::class)) + ->addMethodCall('registerLogger', [new Reference('logger', ContainerImplementation::NULL_ON_INVALID_REFERENCE)]) + ); + // TODO: some service configuration should be handled at runtime. Here they are all cached in the container // $messagingBuilder->register('config.defaultSerializationMediaType', MediaType::parseMediaType($this->applicationConfiguration->getDefaultSerializationMediaType())); @@ -931,6 +954,9 @@ public function process(ContainerBuilder $builder): void $messagingBuilder->register(ConfiguredMessagingSystem::class, new Definition(MessagingSystemContainer::class, [new Reference(ContainerInterface::class), $messagingBuilder->getPollingEndpoints(), $gatewayListReferences])); (new RegisterSingletonMessagingServices())->process($builder); + foreach ($this->compilerPasses as $compilerPass) { + $compilerPass->process($builder); + } } /** diff --git a/packages/Ecotone/src/Messaging/Config/ModuleClassList.php b/packages/Ecotone/src/Messaging/Config/ModuleClassList.php index 082252cde..4aa72b5c0 100644 --- a/packages/Ecotone/src/Messaging/Config/ModuleClassList.php +++ b/packages/Ecotone/src/Messaging/Config/ModuleClassList.php @@ -44,8 +44,6 @@ use Ecotone\Messaging\Config\Annotation\ModuleConfiguration\TransformerModule; use Ecotone\Messaging\Handler\Logger\Config\LoggingModule; use Ecotone\Messaging\Handler\Logger\Config\MessageHandlerLogger; -use Ecotone\Messaging\Handler\Logger\LoggingGateway; -use Ecotone\Messaging\Handler\Logger\LoggingService; use Ecotone\Modelling\Config\BusModule; use Ecotone\Modelling\Config\BusRoutingModule; use Ecotone\Modelling\Config\DistributedGatewayModule; @@ -92,8 +90,6 @@ class ModuleClassList DynamicMessageChannelModule::class, /** Attribute based configurations */ - LoggingGateway::class, - LoggingService::class, MessageHeadersPropagatorInterceptor::class, MessageHandlerLogger::class, ]; diff --git a/packages/Ecotone/src/Messaging/Endpoint/AcknowledgeConfirmationInterceptor.php b/packages/Ecotone/src/Messaging/Endpoint/AcknowledgeConfirmationInterceptor.php index 63c81ab5a..6f0b4a353 100644 --- a/packages/Ecotone/src/Messaging/Endpoint/AcknowledgeConfirmationInterceptor.php +++ b/packages/Ecotone/src/Messaging/Endpoint/AcknowledgeConfirmationInterceptor.php @@ -71,7 +71,7 @@ public function ack(MethodInvocation $methodInvocation, Message $message, #[Refe throw $exception; } - $logger->error( + $logger->critical( sprintf( 'Error occurred during acknowledging message with id `%s` in Message Channel `%s`. This means message may return to the channel. Error: %s', $message->getHeaders()->getMessageId(), @@ -79,7 +79,7 @@ public function ack(MethodInvocation $methodInvocation, Message $message, #[Refe $exception->getMessage() ), $message, - $exception, + ['exception' => $exception], ); } } diff --git a/packages/Ecotone/src/Messaging/Endpoint/InterceptedChannelAdapterBuilder.php b/packages/Ecotone/src/Messaging/Endpoint/InterceptedChannelAdapterBuilder.php index 1c8c2ed44..01ea74fdc 100644 --- a/packages/Ecotone/src/Messaging/Endpoint/InterceptedChannelAdapterBuilder.php +++ b/packages/Ecotone/src/Messaging/Endpoint/InterceptedChannelAdapterBuilder.php @@ -22,7 +22,6 @@ use Ecotone\Messaging\Handler\Processor\MethodInvoker\AroundInterceptorBuilder; use Ecotone\Messaging\Precedence; use Ecotone\Messaging\Scheduling\Clock; -use Psr\Log\LoggerInterface; /** * Class InterceptedConsumerBuilder @@ -64,7 +63,7 @@ public function registerConsumer(MessagingContainerBuilder $builder): void $messagePoller, new PollingMetadataReference($this->endpointId), new Reference(Clock::class), - new Reference(LoggerInterface::class), + new Reference(LoggingGateway::class), new Reference(MessagingEntrypoint::class), ]); $builder->registerPollingEndpoint($this->endpointId, $consumerRunner); diff --git a/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedConsumerRunner.php b/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedConsumerRunner.php index b391d585d..a5a9cd453 100644 --- a/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedConsumerRunner.php +++ b/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedConsumerRunner.php @@ -7,13 +7,13 @@ use Ecotone\Messaging\Endpoint\ExecutionPollingMetadata; use Ecotone\Messaging\Endpoint\PollingMetadata; use Ecotone\Messaging\Gateway\MessagingEntrypoint; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; use Ecotone\Messaging\Handler\NonProxyGateway; use Ecotone\Messaging\MessagePoller; use Ecotone\Messaging\Scheduling\Clock; use Ecotone\Messaging\Scheduling\CronTrigger; use Ecotone\Messaging\Scheduling\PeriodicTrigger; use Ecotone\Messaging\Scheduling\SyncTaskScheduler; -use Psr\Log\LoggerInterface; /** * licence Apache-2.0 @@ -25,7 +25,7 @@ public function __construct( private MessagePoller $messagePoller, private PollingMetadata $defaultPollingMetadata, private Clock $clock, - private LoggerInterface $logger, + private LoggingGateway $logger, private MessagingEntrypoint $messagingEntrypoint, ) { } diff --git a/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedPollingConsumerBuilder.php b/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedPollingConsumerBuilder.php index ca70bfdd5..57e4e0f1d 100644 --- a/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedPollingConsumerBuilder.php +++ b/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/InterceptedPollingConsumerBuilder.php @@ -23,7 +23,6 @@ use Ecotone\Messaging\Handler\Processor\MethodInvoker\AroundInterceptorBuilder; use Ecotone\Messaging\Precedence; use Ecotone\Messaging\Scheduling\Clock; -use Psr\Log\LoggerInterface; use Ramsey\Uuid\Uuid; /** @@ -101,7 +100,7 @@ public function registerConsumer(MessagingContainerBuilder $builder, MessageHand $this->compileMessagePoller($builder, $messageHandlerBuilder), new PollingMetadataReference($endpointId), new Reference(Clock::class), - new Reference(LoggerInterface::class), + new Reference(LoggingGateway::class), new Reference(MessagingEntrypoint::class), ]); $builder->registerPollingEndpoint($endpointId, $consumerRunner, $this->withContinuesPolling()); diff --git a/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/PollingConsumerErrorChannelInterceptor.php b/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/PollingConsumerErrorChannelInterceptor.php index 4426555cb..f8a408692 100644 --- a/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/PollingConsumerErrorChannelInterceptor.php +++ b/packages/Ecotone/src/Messaging/Endpoint/PollingConsumer/PollingConsumerErrorChannelInterceptor.php @@ -40,10 +40,10 @@ private function tryToSendToErrorChannel(Throwable $exception, Message $requestM $errorChannelName = $pollingMetadata->getErrorChannelName(); if ($errorChannelName && $this->channelResolver->hasChannelWithName($errorChannelName)) { - $this->loggingGateway->error( + $this->loggingGateway->critical( sprintf('Error occurred during handling message. Sending Message to handle it in predefined Error Channel: `%s`.', $errorChannelName), $requestMessage, - $exception, + ['exception' => $exception], ); $errorChannel = $this->channelResolver->resolve($errorChannelName); @@ -52,7 +52,7 @@ private function tryToSendToErrorChannel(Throwable $exception, Message $requestM $this->loggingGateway->info( sprintf('Message was sent to Error Channel: `%s` successfully.', $errorChannelName), $requestMessage, - $exception, + ['exception' => $exception], ); return true; diff --git a/packages/Ecotone/src/Messaging/Handler/Gateway/ErrorChannelInterceptor.php b/packages/Ecotone/src/Messaging/Handler/Gateway/ErrorChannelInterceptor.php index fd7addb06..3291118a0 100644 --- a/packages/Ecotone/src/Messaging/Handler/Gateway/ErrorChannelInterceptor.php +++ b/packages/Ecotone/src/Messaging/Handler/Gateway/ErrorChannelInterceptor.php @@ -29,7 +29,7 @@ public function handle(MethodInvocation $methodInvocation, Message $requestMessa $this->loggingGateway->info( 'Error occurred during handling message. Sending Message to handle it in predefined Error Channel.', $requestMessage, - $exception, + ['exception' => $exception], ); $this->errorChannel->send(ErrorMessage::create(MessageHandlingException::fromOtherException($exception, $requestMessage))); @@ -37,7 +37,7 @@ public function handle(MethodInvocation $methodInvocation, Message $requestMessa $this->loggingGateway->info( 'Message was sent to Error Channel successfully.', $requestMessage, - $exception, + ['exception' => $exception], ); } } diff --git a/packages/Ecotone/src/Messaging/Handler/InMemoryReferenceSearchService.php b/packages/Ecotone/src/Messaging/Handler/InMemoryReferenceSearchService.php index 6b694885d..6e5c59f85 100644 --- a/packages/Ecotone/src/Messaging/Handler/InMemoryReferenceSearchService.php +++ b/packages/Ecotone/src/Messaging/Handler/InMemoryReferenceSearchService.php @@ -8,11 +8,9 @@ use Ecotone\Messaging\Conversion\ConversionService; use Ecotone\Messaging\Gateway\MessagingEntrypoint; use Ecotone\Messaging\Gateway\StorageMessagingEntrypoint; -use Ecotone\Messaging\Handler\Logger\LoggingHandlerBuilder; use Ecotone\Messaging\MessagingException; use Ecotone\Messaging\Support\Assert; use Psr\Container\ContainerInterface; -use Psr\Log\NullLogger; /** * Class InMemoryReferenceSearchService @@ -50,9 +48,6 @@ private function __construct(array $objectsToResolve, ?ContainerInterface $refer false ); } - if (! array_key_exists(LoggingHandlerBuilder::LOGGER_REFERENCE, $objectsToResolve) && ! self::hasInOriginalReferenceService(LoggingHandlerBuilder::LOGGER_REFERENCE, $referenceSearchService)) { - $objectsToResolve[LoggingHandlerBuilder::LOGGER_REFERENCE] = new NullLogger(); - } if (! self::hasInOriginalReferenceService(MessagingEntrypoint::class, $referenceSearchService)) { $objectsToResolve[MessagingEntrypoint::class] = StorageMessagingEntrypoint::create(); } diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/Config/LoggingModule.php b/packages/Ecotone/src/Messaging/Handler/Logger/Config/LoggingModule.php index bd996b0b6..dea595e08 100644 --- a/packages/Ecotone/src/Messaging/Handler/Logger/Config/LoggingModule.php +++ b/packages/Ecotone/src/Messaging/Handler/Logger/Config/LoggingModule.php @@ -10,7 +10,6 @@ use Ecotone\Messaging\Config\Annotation\AnnotationModule; use Ecotone\Messaging\Config\Annotation\ModuleConfiguration\NoExternalConfigurationModule; use Ecotone\Messaging\Config\Configuration; -use Ecotone\Messaging\Config\Container\Definition; use Ecotone\Messaging\Config\Container\Reference; use Ecotone\Messaging\Config\ModulePackageList; use Ecotone\Messaging\Config\ModuleReferenceSearchService; @@ -19,12 +18,11 @@ use Ecotone\Messaging\Handler\Logger\Annotation\LogAfter; use Ecotone\Messaging\Handler\Logger\Annotation\LogBefore; use Ecotone\Messaging\Handler\Logger\Annotation\LogError; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; use Ecotone\Messaging\Handler\Logger\LoggingInterceptor; -use Ecotone\Messaging\Handler\Logger\LoggingService; use Ecotone\Messaging\Handler\Processor\MethodInvoker\AroundInterceptorBuilder; use Ecotone\Messaging\Handler\Processor\MethodInvoker\MethodInterceptorBuilder; use Ecotone\Messaging\Precedence; -use Psr\Log\LoggerInterface; #[ModuleAnnotation] /** @@ -46,13 +44,14 @@ public static function create(AnnotationFinder $annotationRegistrationService, I public function prepare(Configuration $messagingConfiguration, array $extensionObjects, ModuleReferenceSearchService $moduleReferenceSearchService, InterfaceToCallRegistry $interfaceToCallRegistry): void { $messagingConfiguration->registerServiceDefinition(LoggingInterceptor::class, [ - new Definition(LoggingService::class, [Reference::to(ConversionService::REFERENCE_NAME), Reference::to(LoggerInterface::class)]), + Reference::to(LoggingGateway::class), + Reference::to(ConversionService::class), ]); $messagingConfiguration->registerBeforeMethodInterceptor( MethodInterceptorBuilder::create( Reference::to(LoggingInterceptor::class), - $interfaceToCallRegistry->getFor(LoggingInterceptor::class, 'logBefore'), + $interfaceToCallRegistry->getFor(LoggingInterceptor::class, 'log'), Precedence::EXCEPTION_LOGGING_PRECEDENCE, LogBefore::class ) @@ -60,7 +59,7 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO $messagingConfiguration->registerAfterMethodInterceptor( MethodInterceptorBuilder::create( Reference::to(LoggingInterceptor::class), - $interfaceToCallRegistry->getFor(LoggingInterceptor::class, 'logAfter'), + $interfaceToCallRegistry->getFor(LoggingInterceptor::class, 'log'), Precedence::EXCEPTION_LOGGING_PRECEDENCE, LogAfter::class ) diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingGateway.php b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingGateway.php index 08725d417..6eb31636a 100644 --- a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingGateway.php +++ b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingGateway.php @@ -4,33 +4,16 @@ namespace Ecotone\Messaging\Handler\Logger; -use Ecotone\Messaging\Attribute\MessageGateway; -use Ecotone\Messaging\Attribute\Parameter\Header; -use Ecotone\Messaging\Attribute\Parameter\Payload; -use Ecotone\Messaging\Attribute\PropagateHeaders; use Ecotone\Messaging\Message; -use Throwable; +use Psr\Log\LoggerInterface; +use Stringable; /** * licence Apache-2.0 */ -interface LoggingGateway +interface LoggingGateway extends LoggerInterface { - #[MessageGateway(LoggingService::INFO_LOGGING_CHANNEL)] - #[PropagateHeaders(false)] - public function info( - #[Payload] string $text, - #[Header(LoggingService::CONTEXT_MESSAGE_HEADER)] ?Message $message = null, - #[Header(LoggingService::CONTEXT_EXCEPTION_HEADER)] ?Throwable $exception = null, - #[Header(LoggingService::CONTEXT_DATA_HEADER)] array $contextData = [], - ): void; - - #[MessageGateway(LoggingService::ERROR_LOGGING_CHANNEL)] - #[PropagateHeaders(false)] - public function error( - #[Payload] string $text, - #[Header(LoggingService::CONTEXT_MESSAGE_HEADER)] Message $message, - #[Header(LoggingService::CONTEXT_EXCEPTION_HEADER)] ?Throwable $exception = null, - #[Header(LoggingService::CONTEXT_DATA_HEADER)] array $contextData = [], - ): void; + public function info(Stringable|string $message, array|Message|null $context = [], array $additionalContext = []): void; + public function error(Stringable|string $message, array|Message|null $context = [], array $additionalContext = []): void; + public function critical(Stringable|string $message, array|Message|null $context = [], array $additionalContext = []): void; } diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingHandlerBuilder.php b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingHandlerBuilder.php deleted file mode 100644 index b2d97d592..000000000 --- a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingHandlerBuilder.php +++ /dev/null @@ -1,136 +0,0 @@ - - */ -/** - * licence Apache-2.0 - */ -class LoggingHandlerBuilder extends InputOutputMessageHandlerBuilder implements MessageHandlerBuilderWithParameterConverters -{ - public const LOGGER_REFERENCE = 'logger'; - public const LOG_FULL_MESSAGE = false; - - private string $logLevel = LogLevel::DEBUG; - private bool $logFullMessage = self::LOG_FULL_MESSAGE; - /** - * @var ParameterConverterBuilder[] - */ - private array $methodParameterConverters = []; - - /** - * LoggingHandlerBuilder constructor. - * @param bool $isBefore - */ - private function __construct(private bool $isBefore) - { - } - - /** - * @return LoggingHandlerBuilder - */ - public static function createForBefore(): self - { - return new self(true); - } - - public static function createForAfter(): self - { - return new self(false); - } - - /** - * @param string $logLevel - * @return LoggingHandlerBuilder - */ - public function withLogLevel(string $logLevel): self - { - $this->logLevel = $logLevel; - - return $this; - } - - /** - * @param bool $logFullMessage - * @return LoggingHandlerBuilder - */ - public function withLogFullMessage(bool $logFullMessage): self - { - $this->logFullMessage = $logFullMessage; - - return $this; - } - - /** - * @inheritDoc - */ - public function withMethodParameterConverters(array $methodParameterConverterBuilders): self - { - $this->methodParameterConverters = $methodParameterConverterBuilders; - - return $this; - } - - /** - * @inheritDoc - */ - public function getParameterConverters(): array - { - return $this->methodParameterConverters; - } - - /** - * @inheritDoc - */ - public function compile(MessagingContainerBuilder $builder): Definition - { - if (! $builder->has(LoggingInterceptor::class)) { - $builder->register(LoggingInterceptor::class, new Definition(LoggingInterceptor::class, [ - new Definition(LoggingService::class, [Reference::to(ConversionService::REFERENCE_NAME), Reference::to(self::LOGGER_REFERENCE)]), - ])); - } - return ServiceActivatorBuilder::create( - LoggingInterceptor::class, - $builder->getInterfaceToCall(new InterfaceToCallReference(LoggingInterceptor::class, $this->getMethodName())) - ) - ->withPassThroughMessageOnVoidInterface(true) - ->withOutputMessageChannel($this->getOutputMessageChannelName()) - ->withMethodParameterConverters($this->methodParameterConverters) - ->compile($builder); - } - - /** - * @inheritDoc - */ - public function getInterceptedInterface(InterfaceToCallRegistry $interfaceToCallRegistry): InterfaceToCall - { - return $interfaceToCallRegistry->getFor(LoggingInterceptor::class, $this->getMethodName()); - } - - /** - * @return string - */ - private function getMethodName(): string - { - return $this->isBefore ? 'logBefore' : 'logAfter'; - } -} diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingInterceptor.php b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingInterceptor.php index 556f248d3..de70ca97c 100644 --- a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingInterceptor.php +++ b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingInterceptor.php @@ -4,14 +4,13 @@ namespace Ecotone\Messaging\Handler\Logger; -use Ecotone\Messaging\Handler\Logger\Annotation\LogAfter; -use Ecotone\Messaging\Handler\Logger\Annotation\LogBefore; +use Ecotone\Messaging\Conversion\ConversionService; +use Ecotone\Messaging\Conversion\MediaType; use Ecotone\Messaging\Handler\Logger\Annotation\LogError; use Ecotone\Messaging\Handler\Processor\MethodInvoker\MethodInvocation; -use Ecotone\Messaging\Handler\TypeDefinitionException; +use Ecotone\Messaging\Handler\TypeDescriptor; use Ecotone\Messaging\Message; -use Ecotone\Messaging\MessagingException; -use Ecotone\Messaging\Support\InvalidArgumentException; +use Psr\Log\LogLevel; use Throwable; /** @@ -24,50 +23,52 @@ */ class LoggingInterceptor { - public function __construct(private LoggingService $loggingService) + public function __construct(private LoggingGateway $loggingGateway, private ConversionService $conversionService) { } - /** - * @param Message $message - * @param LogBefore $log - * @throws InvalidArgumentException - * @throws MessagingException - * @throws TypeDefinitionException - */ - public function logBefore(Message $message, ?LogBefore $log): void + public function log(Message $message, Logger $logAnnotation): void { - $log ??= new LogBefore(); + $payload = $this->convertPayloadToScalarType($message); - $this->loggingService->log(LoggingLevel::create($log->logLevel, $log->logFullMessage), $message); + $this->loggingGateway->log($logAnnotation->logLevel, $payload, $logAnnotation->logFullMessage ? ['headers' => (string)$message->getHeaders()] : []); } - /** - * @param Message $message - * @param LogAfter $log - * @throws InvalidArgumentException - * @throws MessagingException - * @throws TypeDefinitionException - */ - public function logAfter(Message $message, ?LogAfter $log): void + public function logException(MethodInvocation $methodInvocation, Message $message, ?LogError $logAnnotation) { - $log ??= new LogAfter(); - - $this->loggingService->log(LoggingLevel::create($log->logLevel, $log->logFullMessage), $message); - } - - public function logException(MethodInvocation $methodInvocation, Message $message, ?LogError $log) - { - $log ??= new LogError(); - try { $returnValue = $methodInvocation->proceed(); } catch (Throwable $exception) { - $this->loggingService->logException(LoggingLevel::create($log->logLevel, $log->logFullMessage), $exception, $message); + $context = ['payload' => $this->convertPayloadToScalarType($message), 'exception' => $exception]; + + if ($logAnnotation?->isLogFullMessage()) { + $context['headers'] = (string)$message->getHeaders(); + } + + $this->loggingGateway->log($logAnnotation?->logLevel ?? LogLevel::CRITICAL, $exception->getMessage(), $context); throw $exception; } return $returnValue; } + + private function convertPayloadToScalarType(Message $message): string + { + $data = $message->getPayload(); + $sourceMediaType = $message->getHeaders()->hasContentType() ? $message->getHeaders()->getContentType() : MediaType::createApplicationXPHP(); + $sourceTypeDescriptor = $sourceMediaType->hasTypeParameter() ? $sourceMediaType->getTypeParameter() : TypeDescriptor::createFromVariable($message->getPayload()); + + if (is_object($data) && method_exists($data, '__toString')) { + $data = (string)$data; + } elseif (! TypeDescriptor::createFromVariable($data)->isScalar()) { + if ($this->conversionService->canConvert($sourceTypeDescriptor, $sourceMediaType, TypeDescriptor::createStringType(), MediaType::createApplicationJson())) { + $data = $this->conversionService->convert($data, $sourceTypeDescriptor, $sourceMediaType, TypeDescriptor::createStringType(), MediaType::createApplicationJson()); + } else { + $data = $this->conversionService->convert($data, $sourceTypeDescriptor, $sourceMediaType, TypeDescriptor::createStringType(), MediaType::createApplicationXPHPSerialized()); + } + } + + return (string) $data; + } } diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingService.php b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingService.php index 0ea6ca59d..47697e7d1 100644 --- a/packages/Ecotone/src/Messaging/Handler/Logger/LoggingService.php +++ b/packages/Ecotone/src/Messaging/Handler/Logger/LoggingService.php @@ -4,18 +4,13 @@ namespace Ecotone\Messaging\Handler\Logger; -use Ecotone\Messaging\Attribute\Parameter\Header; -use Ecotone\Messaging\Attribute\Parameter\Payload; -use Ecotone\Messaging\Attribute\ServiceActivator; -use Ecotone\Messaging\Conversion\ConversionService; -use Ecotone\Messaging\Conversion\MediaType; -use Ecotone\Messaging\Handler\TypeDefinitionException; -use Ecotone\Messaging\Handler\TypeDescriptor; +use function array_merge; + use Ecotone\Messaging\Message; -use Ecotone\Messaging\MessagingException; -use Ecotone\Messaging\Support\InvalidArgumentException; use Psr\Log\LoggerInterface; -use Throwable; +use Psr\Log\LoggerTrait; +use Psr\Log\LogLevel; +use Stringable; /** * Class LoggingService @@ -25,132 +20,50 @@ /** * licence Apache-2.0 */ -class LoggingService +class LoggingService implements LoggingGateway, SubscribableLoggingGateway { - public const CONTEXT_MESSAGE_HEADER = 'ecotone.logging.contextMessage'; - public const CONTEXT_EXCEPTION_HEADER = 'ecotone.logging.exceptionMessage'; - public const CONTEXT_DATA_HEADER = 'ecotone.logging.contextData'; - public const INFO_LOGGING_CHANNEL = 'infoLoggingChannel'; - public const ERROR_LOGGING_CHANNEL = 'errorLoggingChannel'; - - private ConversionService $conversionService; - private LoggerInterface $logger; + use LoggerTrait; /** - * LoggingService constructor. - * @param ConversionService $conversionService - * @param LoggerInterface $logger + * @var LoggerInterface[] $loggers */ - public function __construct(ConversionService $conversionService, LoggerInterface $logger) - { - $this->conversionService = $conversionService; - $this->logger = $logger; - } - - #[ServiceActivator(self::INFO_LOGGING_CHANNEL)] - public function info( - #[Payload] string $text, - #[Header(self::CONTEXT_MESSAGE_HEADER)] ?Message $message, - #[Header(self::CONTEXT_EXCEPTION_HEADER)] ?Throwable $exception, - #[Header(self::CONTEXT_DATA_HEADER)] array $contextData, - ): void { - if ($message === null) { - $this->logger->info($text, $contextData); - - return; - } + private array $loggers = []; - $this->logger->info( - $text, - array_merge($contextData, [ - 'message_id' => $message->getHeaders()->getMessageId(), - 'correlation_id' => $message->getHeaders()->getCorrelationId(), - 'parent_id' => $message->getHeaders()->getParentId(), - 'headers' => (string)$message->getHeaders(), - 'exception' => $exception, - ]) - ); + public function info(Stringable|string $message, Message|array|null $context = [], array $additionalContext = []): void + { + $this->log(LogLevel::INFO, $message, $context ?? [], $additionalContext); } - #[ServiceActivator(self::ERROR_LOGGING_CHANNEL)] - public function error( - #[Payload] string $text, - #[Header(self::CONTEXT_MESSAGE_HEADER)] Message $message, - #[Header(self::CONTEXT_EXCEPTION_HEADER)] ?Throwable $exception, - #[Header(self::CONTEXT_DATA_HEADER)] array $contextData, - ): void { - $this->logger->critical( - $text, - array_merge($contextData, [ - 'message_id' => $message->getHeaders()->getMessageId(), - 'correlation_id' => $message->getHeaders()->getCorrelationId(), - 'parent_id' => $message->getHeaders()->getParentId(), - 'headers' => (string)$message->getHeaders(), - 'exception' => $exception, - ]) - ); + public function error(Stringable|string $message, Message|array|null $context = [], array $additionalContext = []): void + { + $this->log(LogLevel::ERROR, $message, $context ?? [], $additionalContext); } - /** - * @param LoggingLevel $loggingLevel - * @param Message $message - * @throws InvalidArgumentException - * @throws TypeDefinitionException - * @throws MessagingException - */ - public function log(LoggingLevel $loggingLevel, Message $message): void + public function critical(Stringable|string $message, Message|array|null $context = [], array $additionalContext = []): void { - $payload = $this->convertPayloadToScalarType($message); - - if ($loggingLevel->isFullMessageLog()) { - $this->logger->{$loggingLevel->getLevel()}($payload, ['headers' => (string)$message->getHeaders()]); - return; - } - - $this->logger->{$loggingLevel->getLevel()}($payload); + $this->log(LogLevel::CRITICAL, $message, $context ?? [], $additionalContext); } - /** - * @param LoggingLevel $loggingLevel - * @param Throwable $exception - * @param Message $message - * @throws InvalidArgumentException - * @throws TypeDefinitionException - * @throws MessagingException - */ - public function logException(LoggingLevel $loggingLevel, Throwable $exception, Message $message): void + public function log($level, Stringable|string $message, Message|array $context = [], array $additionalContext = []): void { - $context = ['payload' => $this->convertPayloadToScalarType($message), 'exception' => $exception]; + $resultingContext = array_merge( + $context instanceof Message ? [ + 'message_id' => $context->getHeaders()->getMessageId(), + 'correlation_id' => $context->getHeaders()->getCorrelationId(), + 'parent_id' => $context->getHeaders()->getParentId(), + ] : $context, + $additionalContext + ); - if ($loggingLevel->isFullMessageLog()) { - $context = array_merge(['headers' => (string)$message->getHeaders()], $context); + foreach ($this->loggers as $logger) { + $logger->log($level, $message, $resultingContext); } - - $this->logger->{$loggingLevel->getLevel()}($exception->getMessage(), $context); } - /** - * @param Message $message - * @throws InvalidArgumentException - * @throws TypeDefinitionException - * @throws MessagingException - */ - private function convertPayloadToScalarType(Message $message): string + public function registerLogger(?LoggerInterface $logger): void { - $data = $message->getPayload(); - $sourceMediaType = $message->getHeaders()->hasContentType() ? $message->getHeaders()->getContentType() : MediaType::createApplicationXPHP(); - $sourceTypeDescriptor = $sourceMediaType->hasTypeParameter() ? $sourceMediaType->getTypeParameter() : TypeDescriptor::createFromVariable($message->getPayload()); - - if (is_object($data) && method_exists($data, '__toString')) { - $data = (string)$data; - } elseif (! TypeDescriptor::createFromVariable($data)->isScalar()) { - if ($this->conversionService->canConvert($sourceTypeDescriptor, $sourceMediaType, TypeDescriptor::createStringType(), MediaType::createApplicationJson())) { - $data = $this->conversionService->convert($data, $sourceTypeDescriptor, $sourceMediaType, TypeDescriptor::createStringType(), MediaType::createApplicationJson()); - } else { - $data = $this->conversionService->convert($data, $sourceTypeDescriptor, $sourceMediaType, TypeDescriptor::createStringType(), MediaType::createApplicationXPHPSerialized()); - } + if ($logger && ! in_array($logger, $this->loggers)) { + $this->loggers[] = $logger; } - - return $data; } } diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/QuickLogger.php b/packages/Ecotone/src/Messaging/Handler/Logger/QuickLogger.php deleted file mode 100644 index e0905a146..000000000 --- a/packages/Ecotone/src/Messaging/Handler/Logger/QuickLogger.php +++ /dev/null @@ -1,24 +0,0 @@ -getHeaders()->getMessageId() . " arrived.\n"; - - return $message; - } -} diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/StubLoggingGateway.php b/packages/Ecotone/src/Messaging/Handler/Logger/StubLoggingGateway.php index 0ec04a42d..ceaf3c3f0 100644 --- a/packages/Ecotone/src/Messaging/Handler/Logger/StubLoggingGateway.php +++ b/packages/Ecotone/src/Messaging/Handler/Logger/StubLoggingGateway.php @@ -5,46 +5,55 @@ namespace Ecotone\Messaging\Handler\Logger; use Ecotone\Messaging\Message; -use Throwable; +use Psr\Log\LogLevel; +use Stringable; /** * licence Apache-2.0 */ -final class StubLoggingGateway implements LoggingGateway +final class StubLoggingGateway extends LoggingService { - private array $info = []; - private array $critical = []; + private array $logs = []; public static function create(): self { return new self(); } - public function info( - string $text, - ?Message $message = null, - ?Throwable $exception = null, - array $contextData = [], - ): void { - $this->info[] = $text; + /** + * @inheritDoc + */ + public function log($level, Stringable|string $message, Message|array $context = [], array $additionalContext = []): void + { + $this->logs[] = new LogRecord($level, $message, $context); } - public function error( - string $text, - Message $message, - ?Throwable $exception = null, - array $contextData = [], - ): void { - $this->critical[] = $text; + public function getError(): array + { + return $this->getLogs(LogLevel::ERROR); } - public function getCritical(): array + public function getInfo(): array { - return $this->critical; + return $this->getLogs(LogLevel::INFO); } - public function getInfo(): array + public function getLogs(?string $withLogLevel = null): array + { + if ($withLogLevel) { + return array_filter($this->logs, fn (LogRecord $logRecord) => $logRecord->level === $withLogLevel); + } + return $this->logs; + } +} + +/** + * licence Apache-2.0 + * @internal + */ +class LogRecord +{ + public function __construct(public string $level, public string $message, public array|Message $context) { - return $this->info; } } diff --git a/packages/Ecotone/src/Messaging/Handler/Logger/SubscribableLoggingGateway.php b/packages/Ecotone/src/Messaging/Handler/Logger/SubscribableLoggingGateway.php new file mode 100644 index 000000000..37b2e078c --- /dev/null +++ b/packages/Ecotone/src/Messaging/Handler/Logger/SubscribableLoggingGateway.php @@ -0,0 +1,15 @@ +getMessage() ), $failedMessage, - $cause + ['exception' => $cause], ); return null; @@ -84,7 +84,7 @@ public function handle( $cause->getMessage() ), $failedMessage, - $cause + ['exception' => $cause], ); $messageBuilder->removeHeader(self::ECOTONE_RETRY_HEADER); @@ -109,7 +109,7 @@ public function handle( $cause->getMessage() ), $failedMessage, - $cause + ['exception' => $cause], ); $messageChannel->send( $messageBuilder diff --git a/packages/Ecotone/src/Messaging/Handler/Recoverability/RetryTemplate.php b/packages/Ecotone/src/Messaging/Handler/Recoverability/RetryTemplate.php index e42193544..245635f9f 100644 --- a/packages/Ecotone/src/Messaging/Handler/Recoverability/RetryTemplate.php +++ b/packages/Ecotone/src/Messaging/Handler/Recoverability/RetryTemplate.php @@ -68,7 +68,7 @@ public function runCallbackWithRetries(Closure $closure, Message $message, strin throw $exception; } - $logger->info($retryMessage, $message, $exception); + $logger->info($retryMessage, $message, ['exception' => $exception]); usleep($this->calculateNextDelay($retryNumber) * 1000); $retryNumber++; diff --git a/packages/Ecotone/src/Modelling/Config/EventBusRouter.php b/packages/Ecotone/src/Modelling/Config/EventBusRouter.php index ed0dc0194..ca944e953 100644 --- a/packages/Ecotone/src/Modelling/Config/EventBusRouter.php +++ b/packages/Ecotone/src/Modelling/Config/EventBusRouter.php @@ -42,7 +42,7 @@ public function routeByObject(object $object, Message $message): array $this->loggingGateway->info( sprintf('Publishing Event Message using Class routing: %s.', $reflectionClass->getName()), $message, - contextData: ['resolvedChannels' => $channelsToSend] + ['resolvedChannels' => $channelsToSend] ); return $channelsToSend; } @@ -91,7 +91,7 @@ public function routeByName(?string $routedName, Message $message): array $this->loggingGateway->info( sprintf('Publishing Event Message using Named routing: %s.', $routedName), $message, - contextData: ['resolvedChannels' => $resolvedChannels] + ['resolvedChannels' => $resolvedChannels] ); return $resolvedChannels; } diff --git a/packages/Ecotone/src/Modelling/Config/InstantRetry/InstantRetryInterceptor.php b/packages/Ecotone/src/Modelling/Config/InstantRetry/InstantRetryInterceptor.php index 494ff52be..d00c6bef0 100644 --- a/packages/Ecotone/src/Modelling/Config/InstantRetry/InstantRetryInterceptor.php +++ b/packages/Ecotone/src/Modelling/Config/InstantRetry/InstantRetryInterceptor.php @@ -35,7 +35,7 @@ public function retry(MethodInvocation $methodInvocation, Message $message, #[Re $logger->info( sprintf('Instant retry have exceed %d/%d retry limit. No more retries will be done', $retries, $this->maxRetryAttempts), $message, - $exception + ['exception' => $exception], ); throw $exception; } @@ -49,7 +49,7 @@ public function retry(MethodInvocation $methodInvocation, Message $message, #[Re $exception->getMessage() ), $message, - $exception + ['exception' => $exception] ); } } diff --git a/packages/Ecotone/src/Test/LoggerExample.php b/packages/Ecotone/src/Test/LoggerExample.php index 53604da11..cee1c8049 100644 --- a/packages/Ecotone/src/Test/LoggerExample.php +++ b/packages/Ecotone/src/Test/LoggerExample.php @@ -23,7 +23,6 @@ class LoggerExample implements LoggerInterface private array $notice = []; private array $info = []; private array $debug = []; - private array $log = []; private function __construct() { @@ -98,14 +97,6 @@ public function getDebug(): array return $this->debug; } - /** - * @return array - */ - public function getLog(): array - { - return $this->log; - } - /** * @inheritDoc */ @@ -175,7 +166,7 @@ public function debug(string|Stringable $message, array $context = []): void */ public function log($level, string|Stringable $message, array $context = []): void { - $this->log[] = $level; + $this->$level[] = $message; } public function clear(): void @@ -188,6 +179,5 @@ public function clear(): void $this->notice = []; $this->info = []; $this->debug = []; - $this->log = []; } } diff --git a/packages/Ecotone/tests/Lite/LiteContainerImplementationTest.php b/packages/Ecotone/tests/Lite/LiteContainerImplementationTest.php index 8bdc3fc6a..fd91de4d0 100644 --- a/packages/Ecotone/tests/Lite/LiteContainerImplementationTest.php +++ b/packages/Ecotone/tests/Lite/LiteContainerImplementationTest.php @@ -30,9 +30,9 @@ public function test_it_replace_provided_dependencies(): void { $logger = LoggerExample::create(); $externalContainer = InMemoryPSRContainer::createFromAssociativeArray([ - 'logger' => $logger, + 'externallyDefined' => $logger, ]); - $container = self::buildContainerFromDefinitions(['aReference' => new Reference('logger')], $externalContainer); + $container = self::buildContainerFromDefinitions(['aReference' => new Reference('externallyDefined')], $externalContainer); self::assertSame($logger, $container->get('aReference')); } diff --git a/packages/Ecotone/tests/Lite/Test/MessagingTestSupportFrameworkTest.php b/packages/Ecotone/tests/Lite/Test/MessagingTestSupportFrameworkTest.php index 908508fc4..582e419e6 100644 --- a/packages/Ecotone/tests/Lite/Test/MessagingTestSupportFrameworkTest.php +++ b/packages/Ecotone/tests/Lite/Test/MessagingTestSupportFrameworkTest.php @@ -17,7 +17,6 @@ use Ecotone\Messaging\Scheduling\TimeSpan; use Ecotone\Modelling\CommandBus; use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; use Ramsey\Uuid\Uuid; use stdClass; use Test\Ecotone\Modelling\Fixture\CommandHandler\Aggregate\CreateOrderCommand; @@ -147,7 +146,7 @@ public function test_failing_serializing_event_message_due_to_lack_of_converter( { $ecotoneTestSupport = EcotoneLite::bootstrapFlowTesting( [OrderService::class, PlaceOrderConverter::class], - [new OrderService(), new PlaceOrderConverter(), 'logger' => new NullLogger()], + [new OrderService(), new PlaceOrderConverter()], enableAsynchronousProcessing: [ SimpleMessageChannelBuilder::createQueueChannel('orders', conversionMediaType: MediaType::createApplicationXPHPArray()), ], diff --git a/packages/Ecotone/tests/Messaging/Behat/Bootstrap/AnnotationBasedMessagingContext.php b/packages/Ecotone/tests/Messaging/Behat/Bootstrap/AnnotationBasedMessagingContext.php index 998992a43..d211ec6d7 100644 --- a/packages/Ecotone/tests/Messaging/Behat/Bootstrap/AnnotationBasedMessagingContext.php +++ b/packages/Ecotone/tests/Messaging/Behat/Bootstrap/AnnotationBasedMessagingContext.php @@ -19,7 +19,6 @@ use Ecotone\Modelling\QueryBus; use PHPUnit\Framework\Assert; use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; use Ramsey\Uuid\Uuid; use ReflectionException; use Test\Ecotone\Messaging\Fixture\Behat\Calculating\Calculator; @@ -353,7 +352,6 @@ public function iActiveMessagingForNamespace(string $namespace) } } - $objects['logger'] = new NullLogger(); $cacheDirectoryPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . Uuid::uuid4()->toString() . 'ecotone_testing_behat_cache'; $applicationConfiguration = ServiceConfiguration::createWithAsynchronicityOnly() diff --git a/packages/Ecotone/tests/Messaging/Unit/Handler/ErrorHandler/ErrorHandlerTest.php b/packages/Ecotone/tests/Messaging/Unit/Handler/ErrorHandler/ErrorHandlerTest.php index e2361abd4..faa61cbab 100644 --- a/packages/Ecotone/tests/Messaging/Unit/Handler/ErrorHandler/ErrorHandlerTest.php +++ b/packages/Ecotone/tests/Messaging/Unit/Handler/ErrorHandler/ErrorHandlerTest.php @@ -61,7 +61,7 @@ public function test_retrying_message_according_to_retry_template() )); $this->assertNotNull($consumedChannel->receive()); $this->assertCount(2, $logger->getInfo()); - $this->assertCount(0, $logger->getCritical()); + $this->assertCount(0, $logger->getError()); } private function createFailedMessage(Message $message, Throwable $exception = null): ErrorMessage @@ -114,7 +114,7 @@ public function test_if_exceeded_retries_returning_message_with_exception_in_hea $this->assertEquals('exceptionMessage', $resultMessage->getHeaders()->get(ErrorHandler::EXCEPTION_MESSAGE)); $this->assertNotEmpty($resultMessage->getHeaders()->get(ErrorHandler::EXCEPTION_STACKTRACE)); - $this->assertCount(1, $logger->getCritical()); + $this->assertCount(1, $logger->getError()); } public function test_if_exceeded_retries_and_no_dead_letter_defined_drop_message() @@ -140,7 +140,7 @@ public function test_if_exceeded_retries_and_no_dead_letter_defined_drop_message ); $this->assertNull($resultMessage); - $this->assertCount(1, $logger->getCritical()); + $this->assertCount(1, $logger->getError()); } public function test_if_exceeded_retries_returning_message_with_causation_exception_if_exists() diff --git a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingHandlerBuilderTest.php b/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingHandlerBuilderTest.php deleted file mode 100644 index d5a63638a..000000000 --- a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingHandlerBuilderTest.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * @internal - */ -/** - * licence Apache-2.0 - * @internal - */ -class LoggingHandlerBuilderTest extends MessagingTest -{ - public function test_logging_during_sending() - { - $messaging = EcotoneLite::bootstrapFlowTesting( - [Merchant::class, User::class, MerchantSubscriber::class], - [ - new MerchantSubscriber(), - LoggingHandlerBuilder::LOGGER_REFERENCE => $logger = LoggerExample::create(), - ] - ); - - $this->assertEmpty($logger->getInfo()); - - $messaging->sendCommand(new CreateMerchant('123')); - - $this->assertNotEmpty($logger->getInfo()); - } -} diff --git a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingInterceptorTest.php b/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingInterceptorTest.php new file mode 100644 index 000000000..384061d9f --- /dev/null +++ b/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingInterceptorTest.php @@ -0,0 +1,124 @@ + + * + * @internal + */ +/** + * licence Apache-2.0 + * @internal + */ +class LoggingInterceptorTest extends TestCase +{ + public function test_throwing_exception_if_wrong_log_level_passed() + { + $this->expectException(InvalidArgumentException::class); + + LoggingLevel::create('bla', false); + } + + public function test_serializing_payload_if_is_not_primitive() + { + $loggingService = new StubLoggingGateway(); + $loggingInterceptor = new LoggingInterceptor($loggingService, AutoCollectionConversionService::createWith([ + new SerializingConverter(), + ])); + + $payload = ['some']; + $message = MessageBuilder::withPayload($payload)->build(); + + $loggingInterceptor->log($message, new LogAfter(LogLevel::DEBUG, false)); + + $logs = $loggingService->getLogs(); + $this->assertCount(1, $logs); + $this->assertEquals(LogLevel::DEBUG, $logs[0]->level); + $this->assertEquals(addslashes(serialize($payload)), $logs[0]->message); + } + + public function test_calling_to_string_method_if_possible() + { + $loggingService = new StubLoggingGateway(); + $loggingInterceptor = new LoggingInterceptor($loggingService, AutoCollectionConversionService::createWith([ + new SerializingConverter(), + ])); + + $payload = Uuid::uuid4(); + $message = MessageBuilder::withPayload($payload)->build(); + + $loggingInterceptor->log($message, new LogAfter(LogLevel::DEBUG, false)); + $logs = $loggingService->getLogs(); + $this->assertCount(1, $logs); + $this->assertEquals(LogLevel::DEBUG, $logs[0]->level); + $this->assertEquals($payload->toString(), $logs[0]->message); + } + + public function test_serializing_payload_to_json_if_converter_available() + { + $loggingService = new StubLoggingGateway(); + $loggingInterceptor = new LoggingInterceptor($loggingService, AutoCollectionConversionService::createWith([ + new ArrayToJsonConverter(), + ])); + + $payload = ['some']; + $message = MessageBuilder::withPayload($payload) + ->setContentType(MediaType::createApplicationXPHPWithTypeParameter(TypeDescriptor::ARRAY)) + ->build(); + + $loggingInterceptor->log($message, new LogAfter(LogLevel::DEBUG, false)); + $logs = $loggingService->getLogs(); + $this->assertCount(1, $logs); + $this->assertEquals(LogLevel::DEBUG, $logs[0]->level); + $this->assertEquals(json_encode($payload), $logs[0]->message); + } + + public function test_logging_full_message() + { + $loggingService = new StubLoggingGateway(); + $loggingInterceptor = new LoggingInterceptor($loggingService, AutoCollectionConversionService::createWith([ + new ArrayToJsonConverter(), + ])); + + $payload = 'some'; + $message = MessageBuilder::withPayload($payload)->build(); + + $loggingInterceptor->log($message, new LogAfter(LogLevel::DEBUG, true)); + $logs = $loggingService->getLogs(); + $this->assertCount(1, $logs); + $this->assertEquals(LogLevel::DEBUG, $logs[0]->level); + $this->assertEquals($payload, $logs[0]->message); + $this->assertEquals([ + 'headers' => json_encode([ + 'id' => $message->getHeaders()->get(MessageHeaders::MESSAGE_ID), + 'timestamp' => $message->getHeaders()->get(MessageHeaders::TIMESTAMP), + 'correlationId' => $message->getHeaders()->getCorrelationId(), + ]), + ], $logs[0]->context); + } +} diff --git a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingModuleTest.php b/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingModuleTest.php index 8aea12cbb..063211917 100644 --- a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingModuleTest.php +++ b/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingModuleTest.php @@ -8,7 +8,6 @@ use Ecotone\Messaging\Channel\SimpleMessageChannelBuilder; use Ecotone\Messaging\Config\ServiceConfiguration; use Ecotone\Messaging\Endpoint\ExecutionPollingMetadata; -use Ecotone\Messaging\Handler\Logger\LoggingHandlerBuilder; use Ecotone\Test\LoggerExample; use PHPUnit\Framework\TestCase; use Test\Ecotone\Messaging\Fixture\Handler\FailureHandler\ExampleFailureCommandHandler; @@ -29,7 +28,7 @@ public function test_logging_critical_when_exception_occurred_on_message_consume $loggerExample = LoggerExample::create(); $ecotoneLite = EcotoneLite::bootstrapFlowTesting( [ExampleFailureCommandHandler::class], - [new ExampleFailureCommandHandler(), LoggingHandlerBuilder::LOGGER_REFERENCE => $loggerExample], + [new ExampleFailureCommandHandler(), 'logger' => $loggerExample], enableAsynchronousProcessing: [ SimpleMessageChannelBuilder::createQueueChannel(self::CHANNEL_NAME), ] @@ -47,7 +46,7 @@ public function test_it_does_log_critical_if_message_sent_to_error_channel() $loggerExample = LoggerExample::create(); $ecotoneLite = EcotoneLite::bootstrapFlowTesting( [ExampleFailureCommandHandler::class], - [new ExampleFailureCommandHandler(), LoggingHandlerBuilder::LOGGER_REFERENCE => $loggerExample], + [new ExampleFailureCommandHandler(), 'logger' => $loggerExample], ServiceConfiguration::createWithDefaults() ->withDefaultErrorChannel('customErrorChannel'), enableAsynchronousProcessing: [ diff --git a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingServiceTest.php b/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingServiceTest.php deleted file mode 100644 index b72368e1c..000000000 --- a/packages/Ecotone/tests/Messaging/Unit/Handler/Logger/LoggingServiceTest.php +++ /dev/null @@ -1,145 +0,0 @@ - - * - * @internal - */ -/** - * licence Apache-2.0 - * @internal - */ -class LoggingServiceTest extends TestCase -{ - public function test_calling_logger_with_correct_debug_level() - { - $logger = $this - ->getMockBuilder(LoggerInterface::class) - ->getMock(); - - $payload = 'someData'; - $message = MessageBuilder::withPayload($payload)->build(); - - $logger - ->expects($this->once()) - ->method('debug') - ->with($payload); - - $loggingService = new LoggingService(AutoCollectionConversionService::createEmpty(), $logger); - $loggingService->log(LoggingLevel::createDebug(), $message); - } - - public function test_throwing_exception_if_wrong_log_level_passed() - { - $this->expectException(InvalidArgumentException::class); - - LoggingLevel::create('bla', false); - } - - public function test_serializing_payload_if_is_not_primitive() - { - $logger = $this - ->getMockBuilder(LoggerInterface::class) - ->getMock(); - - $payload = ['some']; - $message = MessageBuilder::withPayload($payload)->build(); - - $logger - ->expects($this->once()) - ->method('debug') - ->with(addslashes(serialize($payload))); - - $loggingService = new LoggingService(AutoCollectionConversionService::createWith([ - new SerializingConverter(), - ]), $logger); - $loggingService->log(LoggingLevel::createDebug(), $message); - } - - public function test_calling_to_string_method_if_possible() - { - $logger = $this - ->getMockBuilder(LoggerInterface::class) - ->getMock(); - - $payload = Uuid::uuid4(); - $message = MessageBuilder::withPayload($payload)->build(); - - $logger - ->expects($this->once()) - ->method('debug') - ->with($payload->toString()); - - $loggingService = new LoggingService(AutoCollectionConversionService::createEmpty(), $logger); - $loggingService->log(LoggingLevel::createDebug(), $message); - } - - public function test_serializing_payload_to_json_if_converter_available() - { - $logger = $this - ->getMockBuilder(LoggerInterface::class) - ->getMock(); - - $payload = ['some']; - $message = MessageBuilder::withPayload($payload) - ->setContentType(MediaType::createApplicationXPHPWithTypeParameter(TypeDescriptor::ARRAY)) - ->build(); - - $logger - ->expects($this->once()) - ->method('debug') - ->with(json_encode($payload)); - - $loggingService = new LoggingService(AutoCollectionConversionService::createWith([ - new ArrayToJsonConverter(), - ]), $logger); - $loggingService->log(LoggingLevel::createDebug(), $message); - } - - public function test_logging_full_message() - { - $logger = $this - ->getMockBuilder(LoggerInterface::class) - ->getMock(); - - $payload = 'some'; - $message = MessageBuilder::withPayload($payload)->build(); - - $logger - ->expects($this->once()) - ->method('debug') - ->with($payload, [ - 'headers' => json_encode([ - 'id' => $message->getHeaders()->get(MessageHeaders::MESSAGE_ID), - 'timestamp' => $message->getHeaders()->get(MessageHeaders::TIMESTAMP), - 'correlationId' => $message->getHeaders()->getCorrelationId(), - ]), - ]); - - $loggingService = new LoggingService(AutoCollectionConversionService::createEmpty(), $logger); - $loggingService->log(LoggingLevel::createDebugWithFullMessage(), $message); - } -} diff --git a/packages/Enqueue/src/EnqueueAcknowledgementCallback.php b/packages/Enqueue/src/EnqueueAcknowledgementCallback.php index 63a0e74ce..5af9445e3 100644 --- a/packages/Enqueue/src/EnqueueAcknowledgementCallback.php +++ b/packages/Enqueue/src/EnqueueAcknowledgementCallback.php @@ -94,7 +94,7 @@ public function accept(): void try { $this->enqueueConsumer->acknowledge($this->enqueueMessage); } catch (Exception $exception) { - $this->loggingGateway->info('Failed to acknowledge message, disconnecting Connection in order to self-heal. Failure happen due to: ' . $exception->getMessage(), exception: $exception); + $this->loggingGateway->info('Failed to acknowledge message, disconnecting Connection in order to self-heal. Failure happen due to: ' . $exception->getMessage(), ['exception' => $exception]); $this->connectionFactory->reconnect(); diff --git a/packages/Laravel/src/EcotoneProvider.php b/packages/Laravel/src/EcotoneProvider.php index c3a277bde..6af790fc5 100644 --- a/packages/Laravel/src/EcotoneProvider.php +++ b/packages/Laravel/src/EcotoneProvider.php @@ -2,10 +2,16 @@ namespace Ecotone\Laravel; +use Ecotone\Messaging\Handler\Logger\EchoLogger; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; +use Illuminate\Foundation\Application; +use function class_exists; + use const DIRECTORY_SEPARATOR; use Ecotone\Messaging\Config\ConfiguredMessagingSystem; use Ecotone\Messaging\Config\ConsoleCommandResultSet; +use Ecotone\Messaging\Config\Container\Compiler\ContainerImplementation; use Ecotone\Messaging\Config\Container\ContainerConfig; use Ecotone\Messaging\Config\Container\Definition; use Ecotone\Messaging\Config\Container\Reference; @@ -15,15 +21,13 @@ use Ecotone\Messaging\Config\ServiceConfiguration; use Ecotone\Messaging\ConfigurationVariableService; use Ecotone\Messaging\Gateway\ConsoleCommandRunner; -use Ecotone\Messaging\Handler\Logger\EchoLogger; -use Ecotone\Messaging\Handler\Logger\LoggingHandlerBuilder; use Ecotone\Messaging\Handler\Recoverability\RetryTemplateBuilder; -use Illuminate\Foundation\Application; use Illuminate\Foundation\Console\ClosureCommand; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Config; use Illuminate\Support\ServiceProvider; +use InvalidArgumentException; use ReflectionMethod; /** @@ -31,7 +35,6 @@ */ class EcotoneProvider extends ServiceProvider { - public const MESSAGING_SYSTEM_REFERENCE = ConfiguredMessagingSystem::class; /** * Register services. @@ -196,13 +199,8 @@ public function boot() 'ecotone-config' ); - if (! $this->app->has(LoggingHandlerBuilder::LOGGER_REFERENCE)) { - $this->app->singleton( - LoggingHandlerBuilder::LOGGER_REFERENCE, - function (Application $app) { - return new LaravelLogger(); - } - ); + if (! $this->app->has('logger')) { + $this->app->singleton('logger', LaravelLogger::class); } } @@ -241,7 +239,16 @@ private function resolveArgument(mixed $argument): mixed } return $object; } elseif ($argument instanceof Reference) { - return $this->app->make($argument->getId()); + if ($this->app->has($argument->getId())) { + return $this->app->get($argument->getId()); + } + if ($argument->getInvalidBehavior() === ContainerImplementation::NULL_ON_INVALID_REFERENCE) { + return null; + } + if (class_exists($argument->getId())) { + return $this->app->make($argument->getId()); + } + throw new InvalidArgumentException("Reference to {$argument->getId()} is not found"); } else { return $argument; } diff --git a/packages/LiteApplication/src/PhpDiContainerImplementation.php b/packages/LiteApplication/src/PhpDiContainerImplementation.php index 2052f0dd7..6f7b554f1 100644 --- a/packages/LiteApplication/src/PhpDiContainerImplementation.php +++ b/packages/LiteApplication/src/PhpDiContainerImplementation.php @@ -5,16 +5,16 @@ use DI\ContainerBuilder as PhpDiContainerBuilder; use Ecotone\Messaging\Config\Container\AttributeDefinition; use Ecotone\Messaging\Config\Container\Compiler\CompilerPass; +use Ecotone\Messaging\Config\Container\Compiler\ContainerImplementation; use Ecotone\Messaging\Config\Container\ContainerBuilder; use Ecotone\Messaging\Config\Container\DefinedObject; use Ecotone\Messaging\Config\Container\Definition; use Ecotone\Messaging\Config\Container\DefinitionHelper; use Ecotone\Messaging\Config\Container\Reference; +use Psr\Container\ContainerInterface; use function is_array; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use ReflectionMethod; /** @@ -44,15 +44,6 @@ public function process(ContainerBuilder $builder): void } } - if (isset($phpDiDefinitions['logger']) && ! isset($phpDiDefinitions[LoggerInterface::class])) { - $phpDiDefinitions[LoggerInterface::class] = \DI\get('logger'); - } elseif (! isset($phpDiDefinitions['logger']) && isset($phpDiDefinitions[LoggerInterface::class])) { - $phpDiDefinitions['logger'] = \DI\get(LoggerInterface::class); - } elseif (! isset($phpDiDefinitions['logger']) && ! isset($phpDiDefinitions[LoggerInterface::class])) { - $phpDiDefinitions['logger'] = \DI\create(NullLogger::class); - $phpDiDefinitions[LoggerInterface::class] = \DI\get('logger'); - } - $this->containerBuilder->addDefinitions($phpDiDefinitions); } @@ -73,7 +64,13 @@ private function resolveArgument($argument): mixed } return $resolvedArguments; } elseif ($argument instanceof Reference) { - return \DI\get($argument->getId()); + if ($argument->getInvalidBehavior() === ContainerImplementation::NULL_ON_INVALID_REFERENCE) { + return \DI\factory(function (ContainerInterface $c, string $id) { + return $c->has($id) ? $c->get($id) : null; + })->parameter('id', $argument->getId()); + } else { + return \DI\get($argument->getId()); + } } else { return $argument; } diff --git a/packages/OpenTelemetry/src/AddSpanEventLogger.php b/packages/OpenTelemetry/src/AddSpanEventLogger.php new file mode 100644 index 000000000..2c0f2a893 --- /dev/null +++ b/packages/OpenTelemetry/src/AddSpanEventLogger.php @@ -0,0 +1,35 @@ + \in_array($key, [MessageHeaders::MESSAGE_ID,MessageHeaders::MESSAGE_CORRELATION_ID, MessageHeaders::PARENT_MESSAGE_ID] ), + ARRAY_FILTER_USE_KEY); + + if (isset($context['exception']) && $context['exception'] instanceof \Throwable) { + $exception = $context['exception']; + $attributes['exceptionMessage'] = $exception->getMessage(); + $attributes['exceptionClass'] = $exception::class; + $attributes['exceptionTrace'] = $exception->getTraceAsString(); + } + + Span::getCurrent()->addEvent( + $message, + $attributes + ); + } +} \ No newline at end of file diff --git a/packages/OpenTelemetry/src/Configuration/OpenTelemetryModule.php b/packages/OpenTelemetry/src/Configuration/OpenTelemetryModule.php index 1756e24b2..07989f556 100644 --- a/packages/OpenTelemetry/src/Configuration/OpenTelemetryModule.php +++ b/packages/OpenTelemetry/src/Configuration/OpenTelemetryModule.php @@ -33,7 +33,6 @@ use Ecotone\OpenTelemetry\TracerInterceptor; use Ecotone\OpenTelemetry\TracingChannelAdapterBuilder; use OpenTelemetry\API\Trace\TracerProviderInterface; -use Psr\Log\LoggerInterface; #[ModuleAnnotation] /** @@ -51,11 +50,13 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO $tracingConfiguration = ExtensionObjectResolver::resolveUnique(TracingConfiguration::class, $extensionObjects, TracingConfiguration::createWithDefaults()); $messageChannelBuilders = ExtensionObjectResolver::resolve(MessageChannelBuilder::class, $extensionObjects); + $messagingConfiguration->addCompilerPass(new RegisterAddSpanEventLoggerCompilerPass()); + $messagingConfiguration->registerServiceDefinition( TracerInterceptor::class, new Definition(TracerInterceptor::class, [ new Reference(TracerProviderInterface::class), - new Reference(LoggerInterface::class), + new Reference(LoggingGateway::class), ]) ); if ($tracingConfiguration->higherThanOrEqualTo(TracingConfiguration::TRACING_LEVEL_FRAMEWORK)) { @@ -76,7 +77,6 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO $this->registerTracerFor('traceQueryBus', QueryBus::class, $messagingConfiguration, $interfaceToCallRegistry); $this->registerTracerFor('traceEventBus', EventBus::class, $messagingConfiguration, $interfaceToCallRegistry); $this->registerTracerFor('traceAsynchronousEndpoint', AsynchronousRunningEndpoint::class, $messagingConfiguration, $interfaceToCallRegistry); - $this->registerTracerFor('traceLogs', LoggingGateway::class, $messagingConfiguration, $interfaceToCallRegistry); $this->registerTracerFor('traceDistributedBus', DistributedBus::class, $messagingConfiguration, $interfaceToCallRegistry); $messagingConfiguration->registerBeforeMethodInterceptor( diff --git a/packages/OpenTelemetry/src/Configuration/RegisterAddSpanEventLoggerCompilerPass.php b/packages/OpenTelemetry/src/Configuration/RegisterAddSpanEventLoggerCompilerPass.php new file mode 100644 index 000000000..6bd215960 --- /dev/null +++ b/packages/OpenTelemetry/src/Configuration/RegisterAddSpanEventLoggerCompilerPass.php @@ -0,0 +1,26 @@ +has(LoggingGateway::class)) { + $loggingGatewayDefinition = $builder->getDefinition(LoggingGateway::class); + + if (is_a($loggingGatewayDefinition->getClassName(), SubscribableLoggingGateway::class, true)) { + $loggingGatewayDefinition->addMethodCall("registerLogger", [new Definition(AddSpanEventLogger::class)]); + } + } + } +} \ No newline at end of file diff --git a/packages/OpenTelemetry/src/TracerInterceptor.php b/packages/OpenTelemetry/src/TracerInterceptor.php index c456e03c9..2dbffd756 100644 --- a/packages/OpenTelemetry/src/TracerInterceptor.php +++ b/packages/OpenTelemetry/src/TracerInterceptor.php @@ -145,37 +145,6 @@ public function traceQueryBus(MethodInvocation $methodInvocation, Message $messa ); } - public function traceLogs(MethodInvocation $methodInvocation, Message $message) - { - $logMessage = $message->getPayload(); - - $attributes = []; - if ($message->getHeaders()->containsKey(LoggingService::CONTEXT_MESSAGE_HEADER)) { - /** @var Message $contextMessage */ - $contextMessage = $message->getHeaders()->get(LoggingService::CONTEXT_MESSAGE_HEADER); - $attributes = [ - MessageHeaders::MESSAGE_ID => $contextMessage->getHeaders()->getMessageId(), - MessageHeaders::MESSAGE_CORRELATION_ID => $contextMessage->getHeaders()->getCorrelationId(), - MessageHeaders::PARENT_MESSAGE_ID => $contextMessage->getHeaders()->getParentId(), - ]; - } - - if ($message->getHeaders()->containsKey(LoggingService::CONTEXT_EXCEPTION_HEADER)) { - /** @var Exception $exception */ - $exception = $message->getHeaders()->get(LoggingService::CONTEXT_EXCEPTION_HEADER); - $attributes['exceptionMessage'] = $exception->getMessage(); - $attributes['exceptionClass'] = $exception::class; - $attributes['exceptionTrace'] = $exception->getTraceAsString(); - } - - Span::getCurrent()->addEvent( - $logMessage, - $attributes - ); - - return $methodInvocation->proceed(); - } - public function trace( string $type, MethodInvocation $methodInvocation, diff --git a/packages/PdoEventSourcing/tests/Integration/MultiTenantTest.php b/packages/PdoEventSourcing/tests/Integration/MultiTenantTest.php index 33cba5412..da9e94936 100644 --- a/packages/PdoEventSourcing/tests/Integration/MultiTenantTest.php +++ b/packages/PdoEventSourcing/tests/Integration/MultiTenantTest.php @@ -9,7 +9,6 @@ use Ecotone\Lite\EcotoneLite; use Ecotone\Messaging\Config\ModulePackageList; use Ecotone\Messaging\Config\ServiceConfiguration; -use Ecotone\Messaging\Handler\Logger\EchoLogger; use Ecotone\Messaging\Support\InvalidArgumentException; use Test\Ecotone\EventSourcing\EventSourcingMessagingTestCase; use Test\Ecotone\EventSourcing\Fixture\Ticket\Command\CloseTicket; @@ -33,7 +32,6 @@ public function test_building_asynchronous_event_driven_projection_with_multi_te new InProgressTicketList(), new TicketEventConverter(), 'tenant_a_connection' => $this->connectionForTenantA(), 'tenant_b_connection' => $this->connectionForTenantB(), - 'logger' => new EchoLogger(), ], configuration: ServiceConfiguration::createWithDefaults() ->withSkippedModulePackageNames(ModulePackageList::allPackagesExcept([ModulePackageList::EVENT_SOURCING_PACKAGE, ModulePackageList::ASYNCHRONOUS_PACKAGE, ModulePackageList::DBAL_PACKAGE])) @@ -105,7 +103,6 @@ public function test_building_synchronous_event_driven_projection_with_multi_ten new \Test\Ecotone\EventSourcing\Fixture\TicketWithSynchronousEventDrivenProjectionMultiTenant\InProgressTicketList(), new TicketEventConverter(), 'tenant_a_connection' => $this->connectionForTenantA(), 'tenant_b_connection' => $this->connectionForTenantB(), - 'logger' => new EchoLogger(), ], configuration: ServiceConfiguration::createWithDefaults() ->withSkippedModulePackageNames(ModulePackageList::allPackagesExcept([ModulePackageList::EVENT_SOURCING_PACKAGE, ModulePackageList::DBAL_PACKAGE])) @@ -174,7 +171,6 @@ public function test_multi_tenancy_do_not_work_with_polling_endpoint(): void new InProgressTicketList(), new TicketEventConverter(), 'tenant_a_connection' => $this->connectionForTenantA(), 'tenant_b_connection' => $this->connectionForTenantB(), - 'logger' => new EchoLogger(), ], configuration: ServiceConfiguration::createWithDefaults() ->withSkippedModulePackageNames(ModulePackageList::allPackagesExcept([ModulePackageList::EVENT_SOURCING_PACKAGE, ModulePackageList::ASYNCHRONOUS_PACKAGE, ModulePackageList::DBAL_PACKAGE])) diff --git a/packages/Redis/tests/Fixture/Support/Logger/LoggerExample.php b/packages/Redis/tests/Fixture/Support/Logger/LoggerExample.php deleted file mode 100644 index ffac909d2..000000000 --- a/packages/Redis/tests/Fixture/Support/Logger/LoggerExample.php +++ /dev/null @@ -1,180 +0,0 @@ - - */ -/** - * licence Apache-2.0 - */ -class LoggerExample implements LoggerInterface -{ - private array $emergency = []; - private array $alert = []; - private array $critical = []; - private array $error = []; - private array $warning = []; - private array $notice = []; - private array $info = []; - private array $debug = []; - private array $log = []; - - private function __construct() - { - } - - public static function create(): self - { - return new self(); - } - - /** - * @return array - */ - public function getEmergency(): array - { - return $this->emergency; - } - - /** - * @return array - */ - public function getAlert(): array - { - return $this->alert; - } - - /** - * @return array - */ - public function getCritical(): array - { - return $this->critical; - } - - /** - * @return array - */ - public function getError(): array - { - return $this->error; - } - - /** - * @return array - */ - public function getWarning(): array - { - return $this->warning; - } - - /** - * @return array - */ - public function getNotice(): array - { - return $this->notice; - } - - /** - * @return array - */ - public function getInfo(): array - { - return $this->info; - } - - /** - * @return array - */ - public function getDebug(): array - { - return $this->debug; - } - - /** - * @return array - */ - public function getLog(): array - { - return $this->log; - } - - /** - * @inheritDoc - */ - public function emergency(string|Stringable $message, array $context = []): void - { - $this->emergency[] = $message; - } - - /** - * @inheritDoc - */ - public function alert(string|Stringable $message, array $context = []): void - { - $this->alert[] = $message; - } - - /** - * @inheritDoc - */ - public function critical(string|Stringable $message, array $context = []): void - { - $this->critical[] = $message; - } - - /** - * @inheritDoc - */ - public function error(string|Stringable $message, array $context = []): void - { - $this->error[] = $message; - } - - /** - * @inheritDoc - */ - public function warning(string|Stringable $message, array $context = []): void - { - $this->warning[] = $message; - } - - /** - * @inheritDoc - */ - public function notice(string|Stringable $message, array $context = []): void - { - $this->notice[] = $message; - } - - /** - * @inheritDoc - */ - public function info(string|Stringable $message, array $context = []): void - { - $this->info[] = $message; - } - - /** - * @inheritDoc - */ - public function debug(string|Stringable $message, array $context = []): void - { - $this->debug[] = $message; - } - - /** - * @inheritDoc - */ - public function log($level, string|Stringable $message, array $context = []): void - { - $this->log[] = $level; - } -} diff --git a/packages/Redis/tests/Integration/RedisBackedMessageChannelTest.php b/packages/Redis/tests/Integration/RedisBackedMessageChannelTest.php index 889f979f0..7bc1901a8 100644 --- a/packages/Redis/tests/Integration/RedisBackedMessageChannelTest.php +++ b/packages/Redis/tests/Integration/RedisBackedMessageChannelTest.php @@ -13,13 +13,13 @@ use Ecotone\Messaging\PollableChannel; use Ecotone\Messaging\Support\MessageBuilder; use Ecotone\Redis\RedisBackedMessageChannelBuilder; +use Ecotone\Test\LoggerExample; use Enqueue\Redis\RedisConnectionFactory; use Enqueue\Redis\RedisDestination; use Ramsey\Uuid\Uuid; use Test\Ecotone\Redis\AbstractConnectionTest; use Test\Ecotone\Redis\Fixture\AsynchronousHandler\OrderService; use Test\Ecotone\Redis\Fixture\RedisConsumer\RedisAsyncConsumerExample; -use Test\Ecotone\Redis\Fixture\Support\Logger\LoggerExample; /** * @internal diff --git a/packages/Sqs/tests/Fixture/Support/Logger/LoggerExample.php b/packages/Sqs/tests/Fixture/Support/Logger/LoggerExample.php deleted file mode 100644 index 46bdc11b9..000000000 --- a/packages/Sqs/tests/Fixture/Support/Logger/LoggerExample.php +++ /dev/null @@ -1,180 +0,0 @@ - - */ -/** - * licence Apache-2.0 - */ -class LoggerExample implements LoggerInterface -{ - private array $emergency = []; - private array $alert = []; - private array $critical = []; - private array $error = []; - private array $warning = []; - private array $notice = []; - private array $info = []; - private array $debug = []; - private array $log = []; - - private function __construct() - { - } - - public static function create(): self - { - return new self(); - } - - /** - * @return array - */ - public function getEmergency(): array - { - return $this->emergency; - } - - /** - * @return array - */ - public function getAlert(): array - { - return $this->alert; - } - - /** - * @return array - */ - public function getCritical(): array - { - return $this->critical; - } - - /** - * @return array - */ - public function getError(): array - { - return $this->error; - } - - /** - * @return array - */ - public function getWarning(): array - { - return $this->warning; - } - - /** - * @return array - */ - public function getNotice(): array - { - return $this->notice; - } - - /** - * @return array - */ - public function getInfo(): array - { - return $this->info; - } - - /** - * @return array - */ - public function getDebug(): array - { - return $this->debug; - } - - /** - * @return array - */ - public function getLog(): array - { - return $this->log; - } - - /** - * @inheritDoc - */ - public function emergency(string|Stringable $message, array $context = []): void - { - $this->emergency[] = $message; - } - - /** - * @inheritDoc - */ - public function alert(string|Stringable $message, array $context = []): void - { - $this->alert[] = $message; - } - - /** - * @inheritDoc - */ - public function critical(string|Stringable $message, array $context = []): void - { - $this->critical[] = $message; - } - - /** - * @inheritDoc - */ - public function error(string|Stringable $message, array $context = []): void - { - $this->error[] = $message; - } - - /** - * @inheritDoc - */ - public function warning(string|Stringable $message, array $context = []): void - { - $this->warning[] = $message; - } - - /** - * @inheritDoc - */ - public function notice(string|Stringable $message, array $context = []): void - { - $this->notice[] = $message; - } - - /** - * @inheritDoc - */ - public function info(string|Stringable $message, array $context = []): void - { - $this->info[] = $message; - } - - /** - * @inheritDoc - */ - public function debug(string|Stringable $message, array $context = []): void - { - $this->debug[] = $message; - } - - /** - * @inheritDoc - */ - public function log($level, string|Stringable $message, array $context = []): void - { - $this->log[] = $level; - } -} diff --git a/packages/Sqs/tests/Integration/SqsBackedMessageChannelTest.php b/packages/Sqs/tests/Integration/SqsBackedMessageChannelTest.php index 99bcdf16a..2cb5cb823 100644 --- a/packages/Sqs/tests/Integration/SqsBackedMessageChannelTest.php +++ b/packages/Sqs/tests/Integration/SqsBackedMessageChannelTest.php @@ -14,12 +14,12 @@ use Ecotone\Messaging\PollableChannel; use Ecotone\Messaging\Support\MessageBuilder; use Ecotone\Sqs\SqsBackedMessageChannelBuilder; +use Ecotone\Test\LoggerExample; use Enqueue\Sqs\SqsConnectionFactory; use Ramsey\Uuid\Uuid; use Test\Ecotone\Sqs\AbstractConnectionTest; use Test\Ecotone\Sqs\Fixture\AsynchronousHandler\OrderService; use Test\Ecotone\Sqs\Fixture\SqsConsumer\SqsAsyncConsumerExample; -use Test\Ecotone\Sqs\Fixture\Support\Logger\LoggerExample; /** * @internal diff --git a/packages/Symfony/DependencyInjection/EcotoneExtension.php b/packages/Symfony/DependencyInjection/EcotoneExtension.php index 21e54f0b2..02f8aca0b 100644 --- a/packages/Symfony/DependencyInjection/EcotoneExtension.php +++ b/packages/Symfony/DependencyInjection/EcotoneExtension.php @@ -8,6 +8,7 @@ use Ecotone\Messaging\Config\ServiceCacheConfiguration; use Ecotone\Messaging\Config\ServiceConfiguration; use Ecotone\Messaging\Gateway\ConsoleCommandRunner; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; use Ecotone\Messaging\Handler\Recoverability\RetryTemplateBuilder; use Ecotone\SymfonyBundle\DependencyInjection\Compiler\CacheWarmer; use Ecotone\SymfonyBundle\DependencyInjection\Compiler\SymfonyConfigurationVariableService; @@ -93,6 +94,8 @@ public function load(array $configs, ContainerBuilder $container): void $containerBuilder->addCompilerPass(new SymfonyContainerAdapter($container)); $containerBuilder->compile(); + $container->getDefinition(LoggingGateway::class)->addTag('monolog.logger', ['channel' => 'ecotone']); + foreach ($messagingConfiguration->getRegisteredConsoleCommands() as $oneTimeCommandConfiguration) { $definition = new Definition(); $definition->setClass(MessagingEntrypointCommand::class); diff --git a/packages/Symfony/composer.json b/packages/Symfony/composer.json index a21f78197..ab2a3ee3d 100644 --- a/packages/Symfony/composer.json +++ b/packages/Symfony/composer.json @@ -36,6 +36,7 @@ "behat/behat": "^3.10", "doctrine/doctrine-bundle": "^2.7.2", "doctrine/orm": "^2.11|^3.0", + "ecotone/dbal": "~1.230.1", "friends-of-behat/symfony-extension": "<=2.4.2|^2.5", "monolog/monolog": "^2.9|^3.3.1", "phpstan/phpstan": "^1.8", @@ -44,8 +45,8 @@ "symfony/doctrine-messenger": "^5.4|^6.0|^7.0", "symfony/expression-language": "^6.0|^7.0", "symfony/messenger": "^5.4|^6.0|^7.0", - "wikimedia/composer-merge-plugin": "^2.1", - "ecotone/dbal": "~1.230.1" + "symfony/monolog-bundle": "^3.10", + "wikimedia/composer-merge-plugin": "^2.1" }, "conflict": { "symfony/proxy-manager-bridge": "<5.4.0" @@ -111,4 +112,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/Symfony/config/bundles.php b/packages/Symfony/config/bundles.php index 725555966..82fbf6cc1 100644 --- a/packages/Symfony/config/bundles.php +++ b/packages/Symfony/config/bundles.php @@ -4,6 +4,7 @@ use Ecotone\SymfonyBundle\EcotoneSymfonyBundle; use Fixture\TestBundle; use FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle; +use Symfony\Bundle\MonologBundle\MonologBundle; return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], @@ -11,4 +12,5 @@ EcotoneSymfonyBundle::class => ['all' => true], FriendsOfBehatSymfonyExtensionBundle::class => ['all' => true], DoctrineBundle::class => ['all' => true], + MonologBundle::class => ['test_monolog_integration' => true], ]; diff --git a/packages/Symfony/config/packages/test_monolog_integration/framework.yaml b/packages/Symfony/config/packages/test_monolog_integration/framework.yaml new file mode 100644 index 000000000..102375ae2 --- /dev/null +++ b/packages/Symfony/config/packages/test_monolog_integration/framework.yaml @@ -0,0 +1,5 @@ +framework: + test: ~ + +ecotone: + test: true \ No newline at end of file diff --git a/packages/Symfony/config/packages/test_monolog_integration/monolog.yaml b/packages/Symfony/config/packages/test_monolog_integration/monolog.yaml new file mode 100644 index 000000000..b1bcb7681 --- /dev/null +++ b/packages/Symfony/config/packages/test_monolog_integration/monolog.yaml @@ -0,0 +1,6 @@ +monolog: + handlers: + testing: + type: test + level: debug + channels: ["ecotone"] \ No newline at end of file diff --git a/packages/Symfony/tests/phpunit/SymfonyApplicationTest.php b/packages/Symfony/tests/phpunit/SymfonyApplicationTest.php index 66ec11577..6808113ad 100644 --- a/packages/Symfony/tests/phpunit/SymfonyApplicationTest.php +++ b/packages/Symfony/tests/phpunit/SymfonyApplicationTest.php @@ -4,6 +4,9 @@ use Ecotone\Lite\Test\MessagingTestSupport; use Ecotone\Messaging\Config\ConfiguredMessagingSystem; +use Ecotone\Messaging\Handler\Logger\LoggingGateway; +use Monolog\Handler\TestHandler; +use Monolog\LogRecord; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** @@ -26,6 +29,33 @@ public function test_it_boots_kernel_with_test_support(): void ); } + public function test_it_writes_logs_to_ecotone_channel(): void + { + self::bootKernel([ + 'environment' => 'test_monolog_integration', + ]); + + /** @var TestHandler $testHandler */ + $testHandler = self::getContainer()->get('monolog.handler.testing'); + + $ecotoneInternalLogger = self::getContainer()->get(LoggingGateway::class); + + $ecotoneInternalLogger->info('test'); + + $logRecord = $testHandler->getRecords()[0]; + self::assertCount(1, $testHandler->getRecords()); + + if ($logRecord instanceof LogRecord) { + self::assertEquals('test', $logRecord->message); + self::assertEquals('ecotone', $logRecord->channel); + } else { + // For compatibility with Monolog 2.0 + self::assertEquals('test', $logRecord['message']); + self::assertEquals('ecotone', $logRecord['channel']); + } + + } + protected static function getMessagingSystem(): ConfiguredMessagingSystem { return static::getContainer()->get(ConfiguredMessagingSystem::class);