Skip to content

Commit

Permalink
Add support for custom Gelf encoders in Monolog configuration
Browse files Browse the repository at this point in the history
This commit introduces the ability to specify custom encoders (`json` and `compressed_json`) for Gelf publishers in Monolog's configuration.
  • Loading branch information
Tibor Rac committed Nov 3, 2024
1 parent ed0e4a2 commit fba862a
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 1 deletion.
8 changes: 7 additions & 1 deletion DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@
* - [bubble]: bool, defaults to true
*
* - gelf:
* - publisher: {id: ...} or {hostname: ..., port: ..., chunk_size: ...}
* - publiser:
* - id: string, service id of a publisher implementation, optional if hostname is given
* - hostname: string, optional if id is given
* - [port]: int, defaults to 12201
* - [chunk_size]: int, defaults to 1420
* - [encoder]: string, its value can be 'json' or 'compressed_json'
* - [level]: level name or int value, defaults to DEBUG
* - [bubble]: bool, defaults to true
*
Expand Down Expand Up @@ -816,6 +821,7 @@ private function addGelfSection(ArrayNodeDefinition $handerNode)
->scalarNode('hostname')->end()
->scalarNode('port')->defaultValue(12201)->end()
->scalarNode('chunk_size')->defaultValue(1420)->end()
->scalarNode('encoder')->end()
->end()
->validate()
->ifTrue(function ($v) {
Expand Down
19 changes: 19 additions & 0 deletions DependencyInjection/MonologExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor;
use Symfony\Bridge\Monolog\Processor\TokenProcessor;
use Symfony\Bridge\Monolog\Processor\WebProcessor;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
Expand Down Expand Up @@ -227,10 +228,28 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler
]);
$transport->setPublic(false);

if (isset($handler['publisher']['encoder'])) {
if ('compressed_json' === $handler['publisher']['encoder']) {
$encoderClass = 'Gelf\Encoder\CompressedJsonEncoder';
} elseif ('json' === $handler['publisher']['encoder']) {
$encoderClass = 'Gelf\Encoder\JsonEncoder';
} else {
throw new InvalidConfigurationException('The gelf message encoder must be either "compressed_json" or "json".');
}

$encoder = new Definition($encoderClass);
$encoder->setPublic(false);

$transport->addMethodCall('setMessageEncoder', [$encoder]);
}

$publisher = new Definition('Gelf\Publisher', []);
$publisher->addMethodCall('addTransport', [$transport]);
$publisher->setPublic(false);
} elseif (class_exists('Gelf\MessagePublisher')) {
if (isset($handler['publisher']['encoder']) && 'compressed_json' !== $handler['publisher']['encoder']) {
throw new InvalidConfigurationException('The Gelf\MessagePublisher publisher supports only the compressed json encoding. Omit the option to use the default encoding or use "compressed_json" as the encoder option.');
}
$publisher = new Definition('Gelf\MessagePublisher', [
$handler['publisher']['hostname'],
$handler['publisher']['port'],
Expand Down
22 changes: 22 additions & 0 deletions Tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,28 @@ public function testGelfPublisherService($publisher)
$this->assertEquals('gelf.publisher', $config['handlers']['gelf']['publisher']['id']);
}

public function testGelfPublisherWithEncoder(): void
{
$configs = [
[
'handlers' => [
'gelf' => [
'type' => 'gelf',
'publisher' => [
'hostname' => 'localhost',
'encoder' => 'compressed_json',
],
],
],
],
];

$config = $this->process($configs);

$this->assertEquals('localhost', $config['handlers']['gelf']['publisher']['hostname']);
$this->assertEquals('compressed_json', $config['handlers']['gelf']['publisher']['encoder']);
}

public function testArrays()
{
$configs = [
Expand Down
91 changes: 91 additions & 0 deletions Tests/DependencyInjection/MonologExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,97 @@ public function testExceptionWhenUsingGelfWithoutPublisherHostname()
$loader->load([['handlers' => ['gelf' => ['type' => 'gelf', 'publisher' => []]]]], $container);
}

public function testExceptionWhenUsingLegacyGelfImplementationWithUnsupportedEncoder(): void
{
if (!class_exists('Gelf\MessagePublisher')) {
class_alias(\stdClass::class, 'Gelf\MessagePublisher');
}

$container = new ContainerBuilder();
$loader = new MonologExtension();

$this->expectException(InvalidConfigurationException::class);

$loader->load([['handlers' => ['gelf' => ['type' => 'gelf', 'publisher' => ['hostname' => 'localhost', 'encoder' => 'json']]]]], $container);
}

/**
* @dataProvider encoderOptionsProvider
*/
public function testLegacyGelfImplementationEncoderOption(array $config): void
{
if (!class_exists('Gelf\MessagePublisher')) {
class_alias(\stdClass::class, 'Gelf\MessagePublisher');
}

$container = $this->getContainer($config);
$this->assertTrue($container->hasDefinition('monolog.handler.gelf'));

$handler = $container->getDefinition('monolog.handler.gelf');
/** @var Definition $publisher */
$publisher = $handler->getArguments()[0];

$this->assertDICConstructorArguments($publisher, ['localhost', 12201, 1420]);
}

public function encoderOptionsProvider(): array
{
return [
[
[['handlers' => ['gelf' => ['type' => 'gelf', 'publisher' => ['hostname' => 'localhost', 'encoder' => 'compressed_json']]]]],
],
[
[['handlers' => ['gelf' => ['type' => 'gelf', 'publisher' => ['hostname' => 'localhost']]]]],
],
];
}

public function testExceptionWhenUsingGelfWithInvalidEncoder(): void
{
if (!class_exists('Gelf\Transport\UdpTransport')) {
class_alias(\stdClass::class, 'Gelf\Transport\UdpTransport');
}

$container = new ContainerBuilder();
$loader = new MonologExtension();

$this->expectException(InvalidConfigurationException::class);

$loader->load([['handlers' => ['gelf' => ['type' => 'gelf', 'publisher' => ['hostname' => 'localhost', 'encoder' => 'invalid_encoder']]]]], $container);
}

/**
* @dataProvider gelfEncoderProvider
*/
public function testGelfWithEncoder($encoderValue, $expectedClass): void
{
if (!class_exists('Gelf\Transport\UdpTransport')) {
class_alias(\stdClass::class, 'Gelf\Transport\UdpTransport');
}

$container = $this->getContainer([['handlers' => ['gelf' => ['type' => 'gelf', 'publisher' => ['hostname' => 'localhost', 'encoder' => $encoderValue]]]]]);
$this->assertTrue($container->hasDefinition('monolog.handler.gelf'));

$handler = $container->getDefinition('monolog.handler.gelf');
/** @var Definition $publisher */
$publisher = $handler->getArguments()[0];
/** @var Definition $transport */
$transport = $publisher->getMethodCalls()[0][1][0];
$encoder = $transport->getMethodCalls()[0][1][0];

$this->assertDICConstructorArguments($transport, ['localhost', 12201, 1420]);
$this->assertDICDefinitionClass($encoder, $expectedClass);
$this->assertDICConstructorArguments($handler, [$publisher, 'DEBUG', true]);
}

public function gelfEncoderProvider(): array
{
return [
['json', 'Gelf\Encoder\JsonEncoder'],
['compressed_json', 'Gelf\Encoder\CompressedJsonEncoder'],
];
}

public function testExceptionWhenUsingServiceWithoutId()
{
$container = new ContainerBuilder();
Expand Down

0 comments on commit fba862a

Please sign in to comment.