Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuration overrides #6

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
10 changes: 10 additions & 0 deletions config/logging.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

return [
'driver' => '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'),
];
76 changes: 0 additions & 76 deletions src/LagoonLoggerFactory.php

This file was deleted.

121 changes: 121 additions & 0 deletions src/LagoonLogsFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace amazeeio\LagoonLogs;

use Monolog\Formatter\LogstashFormatter;
use Monolog\Handler\FallbackGroupHandler;
use Monolog\Handler\SocketHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\LogRecord;

/**
* Class LagoonLoggerFactory
*
* @package amazeeio\LagoonLogs
*/
class LagoonLogsFactory
{

/**
* Default chunk size in bytes.
*
* @var int
*/
const LAGOON_LOGS_DEFAULT_CHUNK_SIZE_BYTES = 15000;

/**
* Default identifier.
*
* @var string
*/
const LAGOON_LOGS_MONOLOG_CHANNEL_NAME = 'LagoonLogs';

/**
* Default identifier.
*
* @var string
*/
const LAGOON_LOGS_DEFAULT_IDENTIFIER = 'laravel';

/**
* Default name.
*
* @var string
*/
const LAGOON_LOGS_DEFAULT_HOSTNAME = "application-logs.lagoon.svc";

/**
* Default host port.
*
* @var int
*/
const LAGOON_LOGS_DEFAULT_HOSTPORT = 5140;

/**
* Create a custom Monolog instance.
*/
public function __invoke(array $config): Logger
{

$logger = new Logger(self::LAGOON_LOGS_MONOLOG_CHANNEL_NAME);

$connectionString = sprintf(
"udp://%s:%s",
$config['host'] ?? self::LAGOON_LOGS_DEFAULT_HOSTNAME,
$config['port'] ?? self::LAGOON_LOGS_DEFAULT_HOSTPORT
);
$udpHandler = new SocketHandler($connectionString);
$udpHandler->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;
}
}
60 changes: 60 additions & 0 deletions src/LagoonLogsFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace amazeeio\LagoonLogs;

use Monolog\Formatter\LogstashFormatter;
use Monolog\Formatter\NormalizerFormatter;
use Monolog\Logger;
use Monolog\LogRecord;

/**
* Lagoon Logs Formatter.
*/
class LagoonLogsFormatter extends LogstashFormatter
{

/**
* {@inheritDoc}
*/
public function format(array $record): string
{
$normalized = $this->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";
}
}
17 changes: 8 additions & 9 deletions src/LagoonLogsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
class LagoonLogsServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
* Register our package services and configuration.
*/
public function boot()
public function register(): void
{
$this->app->make('config')->set('logging.channels.LagoonLogs', [
"driver" => "custom",
"via" => "amazeeio\LagoonLogs\LagoonLoggerFactory",
]);
// Merge our package config with existing config to allow overrides.
$this->mergeConfigFrom(
__DIR__.'/../config/logging.php',
'logging.channels.lagoon'
);
}
}
}