diff --git a/common/oatbox/log/ServiceProvider/LogServiceProvider.php b/common/oatbox/log/ServiceProvider/LogServiceProvider.php index 850f95cbe..6d76e743a 100644 --- a/common/oatbox/log/ServiceProvider/LogServiceProvider.php +++ b/common/oatbox/log/ServiceProvider/LogServiceProvider.php @@ -22,14 +22,16 @@ namespace oat\oatbox\log\ServiceProvider; -use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; -use oat\oatbox\log\logger\AdvancedLogger; -use oat\oatbox\log\logger\extender\RequestContextExtender; -use oat\oatbox\log\logger\extender\UserContextExtender; use oat\oatbox\log\LoggerService; use oat\oatbox\session\SessionService; +use oat\oatbox\log\logger\AdvancedLogger; +use oat\oatbox\log\logger\extender\UserContextExtender; +use oat\oatbox\log\logger\extender\RequestContextExtender; +use oat\oatbox\log\logger\extender\ExceptionContextExtender; +use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use function Symfony\Component\DependencyInjection\Loader\Configurator\param; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; class LogServiceProvider implements ContainerServiceProviderInterface @@ -38,16 +40,34 @@ public function __invoke(ContainerConfigurator $configurator): void { $services = $configurator->services(); + $services->set(ExceptionContextExtender::class, ExceptionContextExtender::class); $services->set(RequestContextExtender::class, RequestContextExtender::class); - $services->set(UserContextExtender::class, UserContextExtender::class) + $services + ->set(UserContextExtender::class, UserContextExtender::class) ->args( [ service(SessionService::SERVICE_ID), ] ); - $services->set(AdvancedLogger::class, AdvancedLogger::class) + $services + ->set(UserContextExtender::ACL_SERVICE_ID, UserContextExtender::class) + ->args( + [ + service(SessionService::SERVICE_ID), + true, + ] + ); + + $services + ->set(AdvancedLogger::class, AdvancedLogger::class) ->public() + ->call( + 'addContextExtender', + [ + service(ExceptionContextExtender::class), + ] + ) ->call( 'addContextExtender', [ @@ -65,5 +85,32 @@ public function __invoke(ContainerConfigurator $configurator): void service(LoggerService::SERVICE_ID), ] ); + + $services + ->set(AdvancedLogger::ACL_SERVICE_ID, AdvancedLogger::class) + ->public() + ->args( + [ + service(LoggerService::SERVICE_ID), + ] + ) + ->call( + 'addContextExtender', + [ + service(ExceptionContextExtender::class), + ] + ) + ->call( + 'addContextExtender', + [ + service(RequestContextExtender::class), + ] + ) + ->call( + 'addContextExtender', + [ + service(UserContextExtender::ACL_SERVICE_ID), + ] + ); } } diff --git a/common/oatbox/log/logger/AdvancedLogger.php b/common/oatbox/log/logger/AdvancedLogger.php index 9dc2c6810..0988c2601 100644 --- a/common/oatbox/log/logger/AdvancedLogger.php +++ b/common/oatbox/log/logger/AdvancedLogger.php @@ -27,6 +27,8 @@ class AdvancedLogger implements LoggerInterface { + public const ACL_SERVICE_ID = self::class . '::ACL'; + /** @var LoggerInterface */ private $logger; diff --git a/common/oatbox/log/logger/extender/ExceptionContextExtender.php b/common/oatbox/log/logger/extender/ExceptionContextExtender.php new file mode 100644 index 000000000..ae4af2abe --- /dev/null +++ b/common/oatbox/log/logger/extender/ExceptionContextExtender.php @@ -0,0 +1,63 @@ +buildLogMessage($context[self::CONTEXT_EXCEPTION]); + } + + return $context; + } + + private function buildLogMessage(Throwable $exception): string + { + $message = $this->createMessage($exception); + + if ($exception->getPrevious()) { + $message = sprintf( + '%s, previous: %s', + $message, + $this->buildLogMessage($exception->getPrevious()) + ); + } + + return $message; + } + + private function createMessage(Throwable $exception): string + { + return sprintf( + '"%s", code: %s, file: "%s", line: %s', + $exception->getMessage(), + $exception->getCode(), + $exception->getFile(), + $exception->getLine() + ); + } +} diff --git a/common/oatbox/log/logger/extender/UserContextExtender.php b/common/oatbox/log/logger/extender/UserContextExtender.php index 1acc06903..3c8dc7215 100644 --- a/common/oatbox/log/logger/extender/UserContextExtender.php +++ b/common/oatbox/log/logger/extender/UserContextExtender.php @@ -22,20 +22,26 @@ namespace oat\oatbox\log\logger\extender; -use oat\oatbox\session\SessionService; use Throwable; +use oat\oatbox\session\SessionService; class UserContextExtender implements ContextExtenderInterface { + public const ACL_SERVICE_ID = self::class . '::ACL'; + /** @var SessionService */ private $sessionService; /** @var array|null */ private $userData; - public function __construct(SessionService $sessionService) + /** @var bool */ + private $extendWithUserRoles; + + public function __construct(SessionService $sessionService, bool $extendWithUserRoles = false) { $this->sessionService = $sessionService; + $this->extendWithUserRoles = $extendWithUserRoles; } public function extend(array $context): array @@ -60,6 +66,10 @@ private function getContextUserData(): array $this->userData = [ 'id' => $this->getUserIdentifier(), ]; + + if ($this->extendWithUserRoles) { + $this->userData['roles'] = $this->getUserRoles(); + } } return $this->userData; @@ -79,4 +89,15 @@ private function getUserIdentifier(): ?string return 'unreachable'; } } + + private function getUserRoles(): array + { + try { + $user = $this->sessionService->getCurrentUser(); + + return $user ? $user->getRoles() : []; + } catch (Throwable $exception) { + return []; + } + } } diff --git a/test/unit/common/oatbox/log/logger/extender/ExceptionContextExtenderTest.php b/test/unit/common/oatbox/log/logger/extender/ExceptionContextExtenderTest.php new file mode 100644 index 000000000..c8581d0f1 --- /dev/null +++ b/test/unit/common/oatbox/log/logger/extender/ExceptionContextExtenderTest.php @@ -0,0 +1,76 @@ +sut = new ExceptionContextExtender(); + } + + public function testExtend(): void + { + $this->assertSame( + [ + ContextExtenderInterface::CONTEXT_EXCEPTION => '"Last error", code: 200, file: "' + . __FILE__ . '", line: 67, previous: "Original error", code: 100, file: "' + . __FILE__ . '", line: 70', + ], + $this->sut->extend( + [ + ContextExtenderInterface::CONTEXT_EXCEPTION => $this->createException(), + ] + ) + ); + } + + public function testExtendWithoutException(): void + { + $this->assertSame( + [], + $this->sut->extend([]) + ); + } + + private function createException(): Throwable + { + return new Exception( + 'Last error', + 200, + new Exception( + 'Original error', + 100 + ) + ); + } +} diff --git a/test/unit/common/oatbox/log/logger/extender/UserContextExtenderTest.php b/test/unit/common/oatbox/log/logger/extender/UserContextExtenderTest.php index f5e37cc62..ec6431c82 100644 --- a/test/unit/common/oatbox/log/logger/extender/UserContextExtenderTest.php +++ b/test/unit/common/oatbox/log/logger/extender/UserContextExtenderTest.php @@ -33,7 +33,7 @@ class UserContextExtenderTest extends TestCase { - /** @var AdvancedLogger */ + /** @var UserContextExtender */ private $sut; /** @var SessionService|MockObject */ @@ -41,7 +41,6 @@ class UserContextExtenderTest extends TestCase public function setUp(): void { - $this->logger = $this->createMock(LoggerInterface::class); $this->sessionService = $this->createMock(SessionService::class); $this->sut = new UserContextExtender($this->sessionService); } @@ -49,7 +48,8 @@ public function setUp(): void public function testExtend(): void { $user = $this->createMock(User::class); - $user->method('getIdentifier') + $user + ->method('getIdentifier') ->willReturn('userUri'); $this->sessionService @@ -73,7 +73,8 @@ public function testExtend(): void public function testExtendWithoutUserData(): void { $user = $this->createMock(User::class); - $user->method('getIdentifier') + $user + ->method('getIdentifier') ->willReturn('userUri'); $this->sessionService @@ -105,4 +106,31 @@ public function testExtendWithAnonymous(): void $this->sut->extend([]) ); } + + public function testExtendWithUserRoles(): void + { + $user = $this->createMock(User::class); + $user + ->method('getIdentifier') + ->willReturn('userUri'); + $user + ->method('getRoles') + ->willReturn(['userRole']); + + $this->sessionService + ->method('getCurrentUser') + ->willReturn($user); + + $sut = new UserContextExtender($this->sessionService, true); + + $this->assertSame( + [ + ContextExtenderInterface::CONTEXT_USER_DATA => [ + 'id' => 'userUri', + 'roles' => ['userRole'], + ], + ], + $sut->extend([]) + ); + } }