From 80ed55ec4d6003ab43a8b2f896dd89eef8afa321 Mon Sep 17 00:00:00 2001 From: Roman Barbun Date: Wed, 2 Oct 2024 14:52:36 +1000 Subject: [PATCH 1/2] Added config merge. --- src/LagoonLogsServiceProvider.php | 15 ++++++--------- src/config/logging.php | 11 +++++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 src/config/logging.php diff --git a/src/LagoonLogsServiceProvider.php b/src/LagoonLogsServiceProvider.php index 11e5f96..12edc0e 100644 --- a/src/LagoonLogsServiceProvider.php +++ b/src/LagoonLogsServiceProvider.php @@ -7,15 +7,12 @@ class LagoonLogsServiceProvider extends ServiceProvider { /** - * Bootstrap any application services. - * - * @return void + * Register any application services. */ - public function boot() + public function register(): void { - $this->app->make('config')->set('logging.channels.LagoonLogs', [ - "driver" => "custom", - "via" => "amazeeio\LagoonLogs\LagoonLoggerFactory", - ]); + $this->mergeConfigFrom( + __DIR__.'/config/logging.php', 'logging' + ); } -} \ No newline at end of file +} diff --git a/src/config/logging.php b/src/config/logging.php new file mode 100644 index 0000000..2116b73 --- /dev/null +++ b/src/config/logging.php @@ -0,0 +1,11 @@ + [ + 'LagoonLogs' => [ + 'driver' => 'custom', + 'via' => 'amazeeio\LagoonLogs\LagoonLoggerFactory', + ] + ], + +]; From 62766c31a6377299eba16dc1e176e4d6feb20a8d Mon Sep 17 00:00:00 2001 From: Roman Barbun Date: Thu, 3 Oct 2024 12:01:55 +1000 Subject: [PATCH 2/2] Allowed config overrides. Added code formatting. Swapped factory for custom handler. Changed namespace. Removed handler. Refactored defaults. iFixed a return type. Committed out problematic code. Added Lagoon logs formatter. Revised code format. Updated Readme. --- README.md | 32 +++++++- config/logging.php | 10 +++ src/LagoonLoggerFactory.php | 76 ------------------- src/LagoonLogsFactory.php | 121 ++++++++++++++++++++++++++++++ src/LagoonLogsFormatter.php | 60 +++++++++++++++ src/LagoonLogsServiceProvider.php | 6 +- src/config/logging.php | 11 --- 7 files changed, 223 insertions(+), 93 deletions(-) create mode 100644 config/logging.php delete mode 100644 src/LagoonLoggerFactory.php create mode 100644 src/LagoonLogsFactory.php create mode 100644 src/LagoonLogsFormatter.php delete mode 100644 src/config/logging.php diff --git a/README.md b/README.md index 55ee9ce..e68eb23 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,37 @@ Monolog channel and formatter for Laravel logging into Lagoon. ## Basic Usage -Installing this package makes the channel "LagoonLogs" available in your logging config. +Installing this package makes the channel `lagoon` available in your logging config. You can install the package by simply running `composer require amazeeio/lagoon-logs` - the package should be installed and autodiscovered by Laravel. It's important to note that this is essentially a wrapper around a Monolog Logger with a specifically set UDP SocketHandler and LogstashFormatter - therefore, it really only makes sense to use this _when_ deployed to a Lagoon instance. -In a vanilla Laravel 6 installation, this is most easily done by setting the environment variable `LOG_CHANNEL` to `LagoonLogs`. +In a vanilla Laravel installation, this is most easily done by setting the environment variable `LOG_CHANNEL` to `lagoon`. -If you need more control over your logging stack, you can simply add `LagoonLogs` in the appropriate places (such as a stack) in your `./config/logging.php` file. -See [the Laravel 6 docs](https://laravel.com/docs/6.x/logging) for more on customizing logging. +## Advanced Usage + +This package provides a default configuration via `./config/logging.php` that will be merged with your application's +`./config/logging.php`. If you need more control over your logging stack, you can simply override the default config by +adding `lagoon` channel in your `./config/logging.php` file. + +For instance, if you need to configure a custom formatter, you can add: +``` +'lagoon' => [ + 'tap' => [App\Logging\CustomizeFormatter::class], +], +``` + +See [the Laravel docs](https://laravel.com/docs/11.x/logging) for more on customizing logging. + +Additionally, the following environmental variables are available: + +``` +LOG_LEVEL=debug +LAGOON_LOGS_HOST="application-logs.lagoon.svc" +LAGOON_LOGS_PORT=5140 +LAGOON_LOGS_IDENTIFIER="my-application" +``` + +Note, if `LAGOON_LOGS_IDENTIFIER` value is not provided then this package will attempt to create it by looking up Lagoon +environment details using a combination `LAGOON_PROJECT` and `LAGOON_GIT_SAFE_BRANCH`. diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 0000000..28bd942 --- /dev/null +++ b/config/logging.php @@ -0,0 +1,10 @@ + 'custom', + 'via' => 'amazeeio\LagoonLogs\LagoonLogsFactory', + 'level' => env('LOG_LEVEL', 'debug'), + 'host' => env('LAGOON_LOGS_HOST', 'application-logs.lagoon.svc'), + 'port' => env('LAGOON_LOGS_PORT', 5140), + 'identifier' => env('LAGOON_LOGS_IDENTIFIER'), +]; diff --git a/src/LagoonLoggerFactory.php b/src/LagoonLoggerFactory.php deleted file mode 100644 index e301bd3..0000000 --- a/src/LagoonLoggerFactory.php +++ /dev/null @@ -1,76 +0,0 @@ -setChunkSize(self::LAGOON_LOGS_DEFAULT_CHUNK_SIZE_BYTES); - $udpHandler->setFormatter(new LogstashFormatter(self::getHostProcessIndex(), - NULL, 'extra', self::DEFAULT_EXTRA_KEY_FOR_FORMATTER, 1)); - - // We want to wrap the group in a failure handler so that if - // the logstash instance isn't available, it pushes to std - // which will be available via the docker logs - $fallbackHandler = new StreamHandler('php://stdout'); - - $failureGroupHandler = new FallbackGroupHandler([$udpHandler, $fallbackHandler]); - - $logger->pushHandler($failureGroupHandler); - - return $logger; - } - - - /** - * Interrogates environment to get the correct process index for logging - * - * @return string - */ - public static function getHostProcessIndex() { - return implode('-', [ - getenv('LAGOON_PROJECT') ?: self::LAGOON_LOGS_DEFAULT_LAGOON_PROJECT, - getenv('LAGOON_GIT_SAFE_BRANCH') ?: self::LAGOON_LOGS_DEFAULT_SAFE_BRANCH, - ]); - } - -} diff --git a/src/LagoonLogsFactory.php b/src/LagoonLogsFactory.php new file mode 100644 index 0000000..331b7a4 --- /dev/null +++ b/src/LagoonLogsFactory.php @@ -0,0 +1,121 @@ +setChunkSize(self::LAGOON_LOGS_DEFAULT_CHUNK_SIZE_BYTES); + $udpHandler->setFormatter( + new LagoonLogsFormatter( + $config['identifier'] ?? self::getDefaultIdentifier() + ) + ); + + // We want to wrap the group in a failure handler so that if + // the logstash instance isn't available, it pushes to std + // which will be available via the docker logs + $fallbackHandler = new StreamHandler('php://stdout'); + + $failureGroupHandler = new FallbackGroupHandler([ + $udpHandler, + $fallbackHandler, + ]); + + $logger->pushHandler($failureGroupHandler); + $logger->pushProcessor([$this, 'addExtraFields']); + + return $logger; + } + + /** + * Add extra fields to the log record. + */ + public function addExtraFields(array $record): array + { + $record['extra']['application'] = self::LAGOON_LOGS_DEFAULT_IDENTIFIER; + $record['extra']['environment'] = $_SERVER['LAGOON_ENVIRONMENT'] ?? ''; + $record['extra']['project'] = $_SERVER['LAGOON_PROJECT'] ?? ''; + return $record; + } + + /** + * Interrogates environment to get the correct process index for logging + */ + public static function getDefaultIdentifier(): string + { + + $defaultIdentifier = self::LAGOON_LOGS_DEFAULT_IDENTIFIER; + + // Attempt to parse Lagoon instance details as a better alternative. + if (getenv('LAGOON_PROJECT') && getenv('LAGOON_GIT_SAFE_BRANCH')) { + $defaultIdentifier = implode('-', [ + getenv('LAGOON_PROJECT'), + getenv('LAGOON_GIT_SAFE_BRANCH'), + ]); + } + + return $defaultIdentifier; + } +} diff --git a/src/LagoonLogsFormatter.php b/src/LagoonLogsFormatter.php new file mode 100644 index 0000000..ea093ec --- /dev/null +++ b/src/LagoonLogsFormatter.php @@ -0,0 +1,60 @@ +normalize($record); + + $message = [ + '@timestamp' => $normalized['datetime'], + '@version' => 1, + 'host' => $this->systemName, + ]; + + if (isset($normalized['message'])) { + $message['message'] = $normalized['message']; + } + if (isset($normalized['channel'])) { + $message['type'] = $normalized['channel']; + $message['channel'] = $normalized['channel']; + } + if (isset($normalized['level_name'])) { + $message['level'] = $normalized['level_name']; + } + if (isset($normalized['level'])) { + $message['monolog_level'] = $normalized['level']; + } + if ($this->applicationName) { + $message['type'] = $this->applicationName; + } + + if (isset($normalized['extra'])) { + foreach ($normalized['extra'] as $key => $val) { + $message[$key] = $val; + } + } + + if (!empty($record['context'])) { + foreach ($record['context'] as $key => $val) { + $message[$key] = $val; + } + } + + return $this->toJson($message) . "\n"; + } +} diff --git a/src/LagoonLogsServiceProvider.php b/src/LagoonLogsServiceProvider.php index 12edc0e..adf54cf 100644 --- a/src/LagoonLogsServiceProvider.php +++ b/src/LagoonLogsServiceProvider.php @@ -7,12 +7,14 @@ class LagoonLogsServiceProvider extends ServiceProvider { /** - * Register any application services. + * Register our package services and configuration. */ public function register(): void { + // Merge our package config with existing config to allow overrides. $this->mergeConfigFrom( - __DIR__.'/config/logging.php', 'logging' + __DIR__.'/../config/logging.php', + 'logging.channels.lagoon' ); } } diff --git a/src/config/logging.php b/src/config/logging.php deleted file mode 100644 index 2116b73..0000000 --- a/src/config/logging.php +++ /dev/null @@ -1,11 +0,0 @@ - [ - 'LagoonLogs' => [ - 'driver' => 'custom', - 'via' => 'amazeeio\LagoonLogs\LagoonLoggerFactory', - ] - ], - -];