Skip to content

Commit

Permalink
add request identifier processor for monolog
Browse files Browse the repository at this point in the history
  • Loading branch information
denis-rendler-evozon committed Sep 3, 2018
1 parent 75ebca8 commit f8360b6
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 3 deletions.
28 changes: 28 additions & 0 deletions DependencyInjection/Compiler/RequestIdentifierPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php declare(strict_types=1);

namespace KoderHut\OnelogBundle\DependencyInjection\Compiler;

use KoderHut\OnelogBundle\Monolog\RequestIdProcessor;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Class RequestIdentifierInjectorPass
*
* @author Denis-Florin Rendler <[email protected]>
*/
class RequestIdentifierPass implements CompilerPassInterface
{

/**
* @inheritdoc
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasParameter('onelog.enable_request_id') || true === $container->getParameter('onelog.enable_request_id')) {
return;
}

$container->removeDefinition(RequestIdProcessor::class);
}
}
5 changes: 5 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public function getConfigTreeBuilder()
->defaultFalse()
->treatNullLike(false)
->end()
->booleanNode('enable_request_id')
->info('Add a request identifier to all log entries. Allows for easier tracking of logs during a request')
->defaultTrue()
->treatNullLike(true)
->end()
->end();

return $treeBuilder;
Expand Down
1 change: 1 addition & 0 deletions DependencyInjection/OnelogExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('onelog.logger_service', $config['logger_service']);
$container->setParameter('onelog.register_global', $config['register_global']);
$container->setParameter('onelog.register_monolog_channels', $config['register_monolog_channels']);
$container->setParameter('onelog.enable_request_id', $config['enable_request_id']);
}
}
50 changes: 50 additions & 0 deletions Monolog/RequestIdProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php declare(strict_types=1);

namespace KoderHut\OnelogBundle\Monolog;

use KoderHut\OnelogBundle\Request\IdentifierInterface;
use KoderHut\OnelogBundle\Request\Identifier as RequestId;

/**
* Class RequestIdProcessor
*
* @author Denis-Florin Rendler <[email protected]>
*/
class RequestIdProcessor
{

/**
* @var int
*/
private $logCount = 1;

/**
* @var RequestId
*/
private $requestId;

/**
* RequestIdProcessor constructor.
*
* @param IdentifierInterface $requestId
*/
public function __construct(IdentifierInterface $requestId = null)
{
$this->requestId = $requestId ?? RequestId::generate();
}

/**
* Add the request id to the log entry
*
* @param array $record
*
* @return array
*/
public function __invoke(array $record): array
{
$record['extra']['request_id'] = $this->requestId->identifier() . '.' . $this->logCount;
$this->logCount++;

return $record;
}
}
2 changes: 2 additions & 0 deletions OnelogBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use KoderHut\OnelogBundle\DependencyInjection\Compiler\LoggerWrapPass;
use KoderHut\OnelogBundle\DependencyInjection\Compiler\RegisterMonologChannels;
use KoderHut\OnelogBundle\DependencyInjection\Compiler\RequestIdentifierPass;
use KoderHut\OnelogBundle\Helper\GlobalNamespaceRegister;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
Expand All @@ -29,6 +30,7 @@ public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new LoggerWrapPass());
$container->addCompilerPass(new RegisterMonologChannels());
$container->addCompilerPass(new RequestIdentifierPass());
}

}
55 changes: 55 additions & 0 deletions Request/Identifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php declare(strict_types=1);

namespace KoderHut\OnelogBundle\Request;

/**
* Class Identifier
*
* @author Denis-Florin Rendler <[email protected]>
*/
class Identifier implements IdentifierInterface
{

/**
* @var string
*/
private $identifier;

/**
* Identifier constructor.
*
* @param string $identifier
*/
public function __construct(string $identifier)
{
$this->identifier = $identifier;
}

/**
* It will generate an instance based on the current date
* using the format YmdHis.u
*
* @param string ...$salts
*
* @return Identifier
*/
public static function generate(string ...$salts)
{
$hashData = (string) (new \DateTime())->format('Ymd.His.u');

if (!empty($salts)) {
$hashData .= '.' . implode('.', $salts);
}

return new self($hashData);
}

/**
* @inheritdoc
*/
public function identifier(): string
{
return $this->identifier;
}

}
19 changes: 19 additions & 0 deletions Request/IdentifierInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace KoderHut\OnelogBundle\Request;

/**
* Interface IdentifierInterface
*
* @author Denis-Florin Rendler <[email protected]>
*/
interface IdentifierInterface
{

/**
* Return the current identifier
*
* @return string
*/
public function identifier(): string;
}
4 changes: 4 additions & 0 deletions Resources/config/onelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<service class="KoderHut\OnelogBundle\Helper\NullLogger" public="false" />
</argument>
</service>

<service id="KoderHut\OnelogBundle\Monolog\RequestIdProcessor" class="KoderHut\OnelogBundle\Monolog\RequestIdProcessor" public="false">
<tag name="monolog.processor" />
</service>
</services>

</container>
69 changes: 69 additions & 0 deletions Tests/DependencyInjection/Compiler/RequestIdentifierPassTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php declare(strict_types=1);

namespace KoderHut\OneLogBundle\Tests\DependencyInjection\Compiler;

use KoderHut\OnelogBundle\DependencyInjection\Compiler\RequestIdentifierPass;
use KoderHut\OnelogBundle\Monolog\RequestIdProcessor;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class RequestIdentifierPassTest extends TestCase
{

/**
* @test
*/
public function testExitEarlyIfRequestIdentifierIsEnabled()
{
$container = $this->prophesize(ContainerBuilder::class);
$container->hasParameter('onelog.enable_request_id')
->shouldBeCalled()
->willReturn(false)
;

$instance = new RequestIdentifierPass();

$instance->process($container->reveal());
}

/**
* @test
*/
public function testExitEarlyIfConfigParamIsMissing()
{
$container = $this->prophesize(ContainerBuilder::class);
$container->hasParameter('onelog.enable_request_id')
->shouldBeCalled()
->willReturn(true)
;
$container->getParameter('onelog.enable_request_id')
->shouldBeCalled()
->willReturn(true)
;

$instance = new RequestIdentifierPass();

$instance->process($container->reveal());
}

/**
* @test
*/
public function testRemoveRequestIdServiceIfConfigIsSetToFalse()
{
$container = $this->prophesize(ContainerBuilder::class);
$container->hasParameter('onelog.enable_request_id')
->shouldBeCalled()
->willReturn(true)
;
$container->getParameter('onelog.enable_request_id')
->shouldBeCalled()
->willReturn(false)
;
$container->removeDefinition(RequestIdProcessor::class)->shouldBeCalled();

$instance = new RequestIdentifierPass();

$instance->process($container->reveal());
}
}
20 changes: 17 additions & 3 deletions Tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,26 @@ public function optionsProvider()
{
return [
'all_configs' => [
['onelog' => ['logger_service' => 'monolog', 'register_global' => true, 'register_monolog_channels' => false]],
['logger_service' => 'monolog', 'register_global' => true, 'register_monolog_channels' => false],
['onelog' => [
'logger_service' => 'monolog',
'register_global' => true,
'register_monolog_channels' => false,
]],
[
'logger_service' => 'monolog',
'register_global' => true,
'register_monolog_channels' => false,
'enable_request_id' => true,
],
],
'default_configs' => [
['onelog' => ['logger_service' => null]],
['logger_service' => 'logger', 'register_global' => false, 'register_monolog_channels' => false],
[
'logger_service' => 'logger',
'register_global' => false,
'register_monolog_channels' => false,
'enable_request_id' => true,
],
],
];
}
Expand Down
65 changes: 65 additions & 0 deletions Tests/Monolog/RequestIdProcessorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php declare(strict_types=1);

namespace KoderHut\OneLogBundle\Tests\Monolog;

use KoderHut\OnelogBundle\Monolog\RequestIdProcessor;
use KoderHut\OnelogBundle\Request\IdentifierInterface;
use PHPUnit\Framework\TestCase;

class RequestIdProcessorTest extends TestCase
{

/**
* @test
*/
public function testInstanceCreatesDateTimeBasedIdWhenNotProvided()
{
$dateTime = new \DateTime();
$date = $dateTime->format('Ymd');
$time = $dateTime->format('Hi');
$format = "${date}\.${time}[0-5]{1}[0-9]{1}\.[0-9]{6}\.1";

$instance = new RequestIdProcessor();

$result = $instance([]);

$this->assertArrayHasKey('extra', $result);
$this->assertArrayHasKey('request_id', $result['extra']);
$this->assertRegExp("/${format}/", $result['extra']['request_id']);
}

/**
* @test
*/
public function testInstanceAcceptSpecificIdentifier()
{
$identifier = $this->prophesize(IdentifierInterface::class);
$identifier->identifier()->shouldBeCalled()->willReturn('test');
$instance = new RequestIdProcessor($identifier->reveal());

$result = $instance([]);
$this->assertArrayHasKey('extra', $result);
$this->assertArrayHasKey('request_id', $result['extra']);
$this->assertEquals('test.1', $result['extra']['request_id']);
}

/**
* @test
*/
public function testMultipleLogEntriesWillBeMarkedIncrementally()
{
$identifier = $this->prophesize(IdentifierInterface::class);
$identifier->identifier()->shouldBeCalled()->willReturn('test');
$instance = new RequestIdProcessor($identifier->reveal());

$result = $instance([]);
$this->assertArrayHasKey('extra', $result);
$this->assertArrayHasKey('request_id', $result['extra']);
$this->assertEquals('test.1', $result['extra']['request_id']);

$result = $instance([]);
$this->assertArrayHasKey('extra', $result);
$this->assertArrayHasKey('request_id', $result['extra']);
$this->assertEquals('test.2', $result['extra']['request_id']);
}
}
Loading

0 comments on commit f8360b6

Please sign in to comment.