diff --git a/composer.json b/composer.json index 2d5fbba..bb4bc0e 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "require": { "drupal/entity": "^1.0", "drupal/health_check": "^3.0", + "drupal/monolog": "^3.0", "drupal/raven": "^4.0 || ^5.0", "firebase/php-jwt": "^6.5", "php": "^8.1", diff --git a/config/install/helfi_api_base.features.yml b/config/install/helfi_api_base.features.yml index 0342518..f53dda8 100644 --- a/config/install/helfi_api_base.features.yml +++ b/config/install/helfi_api_base.features.yml @@ -1,2 +1 @@ -logger: true disable_user_password: true diff --git a/documentation/feature-toggle.md b/documentation/feature-toggle.md index 9cc6812..1fe1b67 100644 --- a/documentation/feature-toggle.md +++ b/documentation/feature-toggle.md @@ -7,11 +7,11 @@ Provides a service to conditionally check if the given feature is enabled. ```php $service = \Drupal::service(\Drupal\helfi_api_base\Features\FeatureManager::class); -$service->isEnabled(\Drupal\helfi_api_base\Features\FeatureManager::LOGGER); // Returns true if the logger feature is enabled. -// Disables the logger feature. -$service->disableFeature(\Drupal\helfi_api_base\Features\FeatureManager::LOGGER) -// Enables the logger feature. -$service->enableFeature(\Drupal\helfi_api_base\Features\FeatureManager::LOGGER); +$service->isEnabled(\Drupal\helfi_api_base\Features\FeatureManager::DISABLE_USER_PASSWORD); +// Disables the feature. +$service->disableFeature(\Drupal\helfi_api_base\Features\FeatureManager::DISABLE_USER_PASSWORD) +// Enables the feature. +$service->enableFeature(\Drupal\helfi_api_base\Features\FeatureManager::DISABLE_USER_PASSWORD); ``` ## Development diff --git a/documentation/logging.md b/documentation/logging.md index f65ab49..a8a1b8d 100644 --- a/documentation/logging.md +++ b/documentation/logging.md @@ -1,15 +1,9 @@ # Logging -Errors caught by Drupal will be logged to `temporary://drupal.log` file as JSON, which will be piped to container stdout by [15-syslog.sh](https://github.com/City-of-Helsinki/drupal-docker-images/blob/main/openshift/drupal/files/entrypoints/15-syslog.sh) docker entrypoint. +Errors caught by Drupal will be logged to `php://stdout` by `drupal/monolog` module. JSON parsing needs to be enabled manually in order for this to work. See https://helsinkisolutionoffice.atlassian.net/wiki/spaces/HELFI/pages/7854817294/Logging+Structured+logs#Configuration-using-openshift-console. -## How to disable logging +## Usage -Call: -```php -$service = \Drupal::service(\Drupal\helfi_api_base\Features\FeatureManager::class); -$service->disableFeature(\Drupal\helfi_api_base\Features\FeatureManager::LOGGER); -``` - -and export the changed configuration. +Enable `monolog` module: `drush en monolog`. diff --git a/helfi_api_base.info.yml b/helfi_api_base.info.yml index 16daa20..b79f073 100644 --- a/helfi_api_base.info.yml +++ b/helfi_api_base.info.yml @@ -5,5 +5,6 @@ core_version_requirement: ^9 || ^10 || ^11 dependencies: - drupal:migrate - entity:entity + - monolog:monolog - health_check:health_check - raven:raven diff --git a/helfi_api_base.install b/helfi_api_base.install index 51a26df..224b550 100644 --- a/helfi_api_base.install +++ b/helfi_api_base.install @@ -216,8 +216,6 @@ function helfi_api_base_update_9014() : void { function helfi_api_base_update_9015() : void { /** @var \Drupal\helfi_api_base\Features\FeatureManager $service */ $service = \Drupal::service(FeatureManager::class); - $service->enableFeature(FeatureManager::LOGGER); - /** @var \Drupal\helfi_api_base\Environment\EnvironmentResolverInterface $environmentResolver */ $environmentResolver = \Drupal::service('helfi_api_base.environment_resolver'); @@ -244,3 +242,12 @@ function helfi_api_base_update_9016() : void { ->set('twig_tracing', TRUE) ->save(); } + +/** + * Enable 'monolog' module. + */ +function helfi_api_base_update_9017(): void { + Drupal::service('module_installer')->install([ + 'monolog', + ]); +} diff --git a/helfi_api_base.services.yml b/helfi_api_base.services.yml index ca418ed..e7c4e5e 100644 --- a/helfi_api_base.services.yml +++ b/helfi_api_base.services.yml @@ -1,5 +1,4 @@ parameters: - helfi_api_base.json_logger_path: '/tmp/drupal.log' helfi_api_base.environment_file: '' helfi_api_base.default_composer_lock: '%app.root%/../composer.lock' helfi_api_base.internal_domains: @@ -98,17 +97,6 @@ services: tags: - { name: event_subscriber } - helfi_api_base.logger_filesystem: - class: Symfony\Component\Filesystem\Filesystem - public: false - - Symfony\Component\Filesystem\Filesystem: - class: Symfony\Component\Filesystem\Filesystem - public: false - Drupal\helfi_api_base\Logger\JsonLog: - tags: - - { name: logger } - Drupal\helfi_api_base\Vault\VaultManager: '@helfi_api_base.vault_manager' helfi_api_base.vault_manager: class: Drupal\helfi_api_base\Vault\VaultManager diff --git a/src/Features/FeatureManager.php b/src/Features/FeatureManager.php index 1733e5e..a24055e 100644 --- a/src/Features/FeatureManager.php +++ b/src/Features/FeatureManager.php @@ -11,7 +11,6 @@ */ final class FeatureManager { - public const LOGGER = 'logger'; public const DISABLE_USER_PASSWORD = 'disable_user_password'; /** diff --git a/src/HelfiApiBaseServiceProvider.php b/src/HelfiApiBaseServiceProvider.php new file mode 100644 index 0000000..3d74326 --- /dev/null +++ b/src/HelfiApiBaseServiceProvider.php @@ -0,0 +1,65 @@ +getParameter('container.modules'); + + if (isset($modules['monolog'])) { + $container->setParameter('monolog.channel_handlers', [ + 'default' => [ + 'handlers' => [ + [ + 'name' => 'default_conditional_handler', + 'formatter' => 'drush_or_json', + ], + ], + ], + ]); + + if (!$container->has('logger.drupaltodrush')) { + $container->register('logger.drupaltodrush', DrushLog::class) + ->addArgument(new Reference('logger.log_message_parser')) + ->addTag('logger'); + } + if (!$container->has('monolog.handler.drupal.drupaltodrush')) { + $container->register('monolog.handler.drupal.drupaltodrush', DrupalHandler::class) + ->addArgument(new Reference('logger.drupaltodrush')) + ->setShared(FALSE); + } + $container->register('monolog.handler.default_conditional_handler', ConditionalHandler::class) + ->addArgument(new Reference('monolog.handler.drupal.drupaltodrush')) + ->addArgument(new Reference('monolog.handler.website')) + ->addArgument(new Reference('monolog.condition_resolver.cli')); + $container->register('monolog.handler.website', StreamHandler::class) + ->addArgument('php://stdout'); + $container->register('monolog.formatter.drush_or_json', ConditionalFormatter::class) + ->addArgument(new Reference('monolog.formatter.drush')) + ->addArgument(new Reference('monolog.formatter.json')) + ->addArgument(new Reference('monolog.condition_resolver.cli')) + ->setShared(FALSE); + } + } + +} diff --git a/src/Logger/JsonLog.php b/src/Logger/JsonLog.php deleted file mode 100644 index 11dc65e..0000000 --- a/src/Logger/JsonLog.php +++ /dev/null @@ -1,103 +0,0 @@ -filesystem - ->appendToFile($this->stream, json_encode(['message' => $message]) . PHP_EOL); - } - - /** - * Checks if the logger is enabled or not. - * - * @return bool - * TRUE if logger is enabled. - */ - private function isLoggerEnabled() : bool { - if ($this->loggerEnabled === NULL) { - $this->loggerEnabled = $this->featureManager->isEnabled(FeatureManager::LOGGER); - } - return $this->loggerEnabled; - } - - /** - * {@inheritdoc} - */ - public function log($level, $message, array $context = []) : void { - if (!$this->isLoggerEnabled()) { - return; - } - global $base_url; - $severity = RfcLogLevel::getLevels()[$level]; - - if ($severity instanceof TranslatableMarkup) { - $severity = strtolower($severity->getUntranslatedString()); - } - // Populate the message placeholders and then replace them in the message. - $variables = $this->parser->parseMessagePlaceholders($message, $context); - $message = empty($variables) ? $message : strtr((string) $message, $variables); - - $this->output([ - 'base_url' => $base_url, - 'timestamp' => $context['timestamp'], - 'severity' => $severity, - 'type' => $context['channel'], - 'message' => $message, - 'uid' => $context['uid'] ?? 0, - 'request_uri' => $context['request_uri'] ?? NULL, - 'referer' => $context['referer'] ?? NULL, - 'ip' => $context['ip'] ?? NULL, - 'link' => (string) ($context['link'] ?? NULL), - 'date' => date(\DateTimeInterface::ATOM, $context['timestamp']), - ]); - } - -} diff --git a/tests/src/Kernel/Features/FeatureToggleTest.php b/tests/src/Kernel/Features/FeatureToggleTest.php index 4ee4e90..8d98b61 100644 --- a/tests/src/Kernel/Features/FeatureToggleTest.php +++ b/tests/src/Kernel/Features/FeatureToggleTest.php @@ -80,7 +80,6 @@ public function testDefaults() : void { $this->assertEquals([ FeatureManager::DISABLE_USER_PASSWORD => TRUE, - FeatureManager::LOGGER => TRUE, ], $features); } diff --git a/tests/src/Kernel/Logger/JsonLoggerTest.php b/tests/src/Kernel/Logger/JsonLoggerTest.php deleted file mode 100644 index 75121cf..0000000 --- a/tests/src/Kernel/Logger/JsonLoggerTest.php +++ /dev/null @@ -1,79 +0,0 @@ -setParameter('helfi_api_base.json_logger_path', 'public://drupal.log'); - } - - /** - * Perform assertions against log entries. - * - * @param string $message - * The message. - * @param string $type - * The type. - */ - private function assertLogMessage(string $message, string $type) : void { - $loggerEntry = json_decode(file_get_contents('public://drupal.log')); - $this->assertEquals($message, $loggerEntry->message->message); - $this->assertEquals($type, $loggerEntry->message->type); - } - - /** - * Make sure nothing is logged when logger is disabled. - */ - public function testLoggingDisabled() : void { - $features = $this->container->get(FeatureManager::class); - $features->disableFeature(FeatureManager::LOGGER); - /** @var \Drupal\helfi_api_base\Logger\JsonLog $sut */ - $sut = $this->container->get(JsonLog::class); - $sut->warning('Test'); - $this->assertFalse(file_exists('public://drupal.log')); - } - - /** - * Make sure messages are logged when the logger is enabled. - */ - public function testLoggingEnabled() : void { - $features = $this->container->get(FeatureManager::class); - $features->enableFeature(FeatureManager::LOGGER); - - /** @var \Drupal\helfi_api_base\Logger\JsonLog $sut */ - $sut = $this->container->get(JsonLog::class); - $sut->warning('Test', [ - 'timestamp' => time(), - 'channel' => 'helfi_api_base', - ]); - $this->assertLogMessage('Test', 'helfi_api_base'); - $this->assertTrue(file_exists('public://drupal.log')); - $this->assertLogMessage('Test', 'helfi_api_base'); - } - -}