From e40b82618ad4adf7e6b705038f010022cc19888f Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 24 Jul 2025 09:57:34 +0200 Subject: [PATCH] Allow logs format to be configured as console or JSON --- CHANGELOG.md | 1 + composer.json | 4 ++-- config/autoload/installer.global.php | 1 + config/autoload/logger.global.php | 18 +++++++++++------- config/roadrunner/.rr.dev.yml | 4 ++++ config/roadrunner/.rr.test.yml | 5 +++-- config/roadrunner/.rr.yml | 3 +++ module/Core/src/Config/EnvVars.php | 3 +++ 8 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9671fa9..7673c67e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this * `mobile`: Will match any mobile devices with either Android or iOS. * [#2093](https://github.com/shlinkio/shlink/issues/2093) Add `REDIRECT_CACHE_LIFETIME` env var and corresponding config option, so that it is possible to set the `Cache-Control` visibility directive (`public` or `private`) when the `REDIRECT_STATUS_CODE` has been set to `301` or `308`. +* [#2323](https://github.com/shlinkio/shlink/issues/2323) Add `LOGS_FORMAT` env var and corresponding config option, to allow the logs generated by Shlink to be in console or JSON formats. ### Changed * [#2406](https://github.com/shlinkio/shlink/issues/2406) Remove references to bootstrap from error templates, and instead inline the very minimum required styles. diff --git a/composer.json b/composer.json index 85ad757b..b410da3a 100644 --- a/composer.json +++ b/composer.json @@ -43,11 +43,11 @@ "pagerfanta/core": "^3.8", "ramsey/uuid": "^4.7", "shlinkio/doctrine-specification": "^2.2", - "shlinkio/shlink-common": "dev-main#7469270 as 7.1", + "shlinkio/shlink-common": "dev-main#2c9387c as 7.1", "shlinkio/shlink-config": "^4.0", "shlinkio/shlink-event-dispatcher": "^4.2", "shlinkio/shlink-importer": "^5.6", - "shlinkio/shlink-installer": "dev-develop#7f9147b as 9.6", + "shlinkio/shlink-installer": "dev-develop#1c775a9 as 9.6", "shlinkio/shlink-ip-geolocation": "^4.3", "shlinkio/shlink-json": "^1.2", "spiral/roadrunner": "^2025.1", diff --git a/config/autoload/installer.global.php b/config/autoload/installer.global.php index 21d16bb3..7f9e8900 100644 --- a/config/autoload/installer.global.php +++ b/config/autoload/installer.global.php @@ -13,6 +13,7 @@ return [ 'enabled_options' => [ Option\Server\RuntimeConfigOption::class, Option\Server\MemoryLimitConfigOption::class, + Option\Server\LogsFormatConfigOption::class, Option\Database\DatabaseDriverConfigOption::class, Option\Database\DatabaseNameConfigOption::class, Option\Database\DatabaseHostConfigOption::class, diff --git a/config/autoload/logger.global.php b/config/autoload/logger.global.php index 56ba42bb..c81fe45d 100644 --- a/config/autoload/logger.global.php +++ b/config/autoload/logger.global.php @@ -23,11 +23,16 @@ use function Shlinkio\Shlink\Config\runningInRoadRunner; return (static function (): array { $isDev = EnvVars::isDevEnv(); - $common = [ + $format = EnvVars::LOGS_FORMAT->loadFromEnv(); + $buildCommonConfig = static fn (bool $addNewLine = false) => [ 'level' => $isDev ? Level::Debug->value : Level::Info->value, 'processors' => [RequestIdMiddleware::class], - 'line_format' => - '[%datetime%] [%extra.' . RequestIdMiddleware::ATTRIBUTE . '%] %channel%.%level_name% - %message%', + 'formatter' => [ + 'type' => $format, + 'add_new_line' => $addNewLine, + 'line_format' => + '[%datetime%] [%extra.' . RequestIdMiddleware::ATTRIBUTE . '%] %channel%.%level_name% - %message%', + ], ]; // In dev env or the docker container, stream Shlink logs to stderr, otherwise send them to a file @@ -39,16 +44,15 @@ return (static function (): array { 'Shlink' => $useStreamForShlinkLogger ? [ 'type' => LoggerType::STREAM->value, 'destination' => 'php://stderr', - ...$common, + ...$buildCommonConfig(), ] : [ 'type' => LoggerType::FILE->value, - ...$common, + ...$buildCommonConfig(), ], 'Access' => [ 'type' => LoggerType::STREAM->value, 'destination' => 'php://stderr', - 'add_new_line' => ! runningInRoadRunner(), - ...$common, + ...$buildCommonConfig(! runningInRoadRunner()), ], ], diff --git a/config/roadrunner/.rr.dev.yml b/config/roadrunner/.rr.dev.yml index 24c3a2fc..594b65e3 100644 --- a/config/roadrunner/.rr.dev.yml +++ b/config/roadrunner/.rr.dev.yml @@ -30,13 +30,17 @@ jobs: prefetch: 10 logs: + encoding: console mode: development channels: http: mode: 'off' # Disable logging as Shlink handles it internally server: + encoding: console level: info metrics: + encoding: console level: debug jobs: + encoding: console level: debug diff --git a/config/roadrunner/.rr.test.yml b/config/roadrunner/.rr.test.yml index f3e8bb78..c97e5414 100644 --- a/config/roadrunner/.rr.test.yml +++ b/config/roadrunner/.rr.test.yml @@ -35,15 +35,16 @@ jobs: prefetch: 10 logs: - encoding: json + encoding: console mode: development channels: http: mode: 'off' # Disable logging as Shlink handles it internally server: - encoding: json + encoding: console level: info metrics: level: panic jobs: + encoding: console level: panic diff --git a/config/roadrunner/.rr.yml b/config/roadrunner/.rr.yml index 901291b2..328a3a60 100644 --- a/config/roadrunner/.rr.yml +++ b/config/roadrunner/.rr.yml @@ -28,11 +28,14 @@ jobs: prefetch: 10 logs: + encoding: ${LOGS_FORMAT:-console} mode: production channels: http: mode: 'off' # Disable logging as Shlink handles it internally server: + encoding: ${LOGS_FORMAT:-console} level: info jobs: + encoding: ${LOGS_FORMAT:-console} level: debug diff --git a/module/Core/src/Config/EnvVars.php b/module/Core/src/Config/EnvVars.php index c99635da..bf5acc3e 100644 --- a/module/Core/src/Config/EnvVars.php +++ b/module/Core/src/Config/EnvVars.php @@ -91,6 +91,7 @@ enum EnvVars: string case CORS_ALLOW_CREDENTIALS = 'CORS_ALLOW_CREDENTIALS'; case CORS_MAX_AGE = 'CORS_MAX_AGE'; case TRUSTED_PROXIES = 'TRUSTED_PROXIES'; + case LOGS_FORMAT = 'LOGS_FORMAT'; /** @deprecated Use REDIRECT_EXTRA_PATH */ case REDIRECT_APPEND_EXTRA_PATH = 'REDIRECT_APPEND_EXTRA_PATH'; @@ -196,6 +197,8 @@ enum EnvVars: string self::CORS_ALLOW_CREDENTIALS => false, self::CORS_MAX_AGE => 3600, + self::LOGS_FORMAT => 'console', + default => null, }; }