-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5deb40a
commit 5772752
Showing
13 changed files
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId\DependencyInjection; | ||
|
||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; | ||
use Symfony\Component\Config\Definition\ConfigurationInterface; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
class Configuration implements ConfigurationInterface | ||
{ | ||
public function getConfigTreeBuilder(): TreeBuilder | ||
{ | ||
$tree = new TreeBuilder('symfony_request_id'); | ||
|
||
$tree->getRootNode() | ||
->children() | ||
->scalarNode('request_header') | ||
->cannotBeEmpty() | ||
->defaultValue('X-Request-Id') | ||
->info('The header in which the bundle will look for and set request IDs') | ||
->end() | ||
->booleanNode('trust_request_header') | ||
->defaultValue(true) | ||
->info("Whether or not to trust the incoming request's `Request-Id` header as a real ID") | ||
->end() | ||
->scalarNode('response_header') | ||
->cannotBeEmpty() | ||
->defaultValue('X-Request-Id') | ||
->info('The header the bundle will set the request ID at in the response') | ||
->end() | ||
->scalarNode('storage_service') | ||
->info('The service name for request ID storage. Defaults to `SimpleIdStorage`') | ||
->end() | ||
->scalarNode('generator_service') | ||
->info('The service name for the request ID generator. Defaults to `symfony/uid` or `ramsey/uuid`') | ||
->end() | ||
->booleanNode('enable_monolog') | ||
->info('Whether or not to turn on the request ID processor for monolog') | ||
->defaultTrue() | ||
->end() | ||
->booleanNode('enable_console') | ||
->info('Whether or not to turn on the request ID processor for monolog') | ||
->defaultTrue() | ||
->end() | ||
->booleanNode('enable_twig') | ||
->info('Whether or not to enable the twig `request_id()` function. Only works if TwigBundle is present.') | ||
->defaultTrue() | ||
->end(); | ||
|
||
return $tree; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId\DependencyInjection; | ||
|
||
use Ramsey\Uuid\UuidFactory; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension; | ||
use DR\SymfonyRequestId\SimpleIdStorage; | ||
use DR\SymfonyRequestId\RequestIdStorage; | ||
use DR\SymfonyRequestId\RequestIdGenerator; | ||
use DR\SymfonyRequestId\Generator\RamseyUuid4Generator; | ||
use DR\SymfonyRequestId\EventListener\RequestIdListener; | ||
use DR\SymfonyRequestId\Monolog\RequestIdProcessor; | ||
use DR\SymfonyRequestId\Twig\RequestIdExtension; | ||
|
||
/** | ||
* Registers some container configuration with the application. | ||
* @internal | ||
*/ | ||
final class SymfonyRequestIdExtension extends ConfigurableExtension | ||
{ | ||
/** | ||
* @param array{ | ||
* request_header: string, | ||
* trust_request_header: bool, | ||
* response_header: string, | ||
* storage_service: ?string, | ||
* generator_service: ?string, | ||
* enable_monolog: bool, | ||
* enable_console: bool, | ||
* enable_twig: bool, | ||
* } $config | ||
*/ | ||
protected function loadInternal(array $config, ContainerBuilder $container) : void | ||
{ | ||
$container->register(SimpleIdStorage::class) | ||
->setPublic(false); | ||
$container->register(RamseyUuid4Generator::class) | ||
->setPublic(false); | ||
|
||
$storeId = empty($config['storage_service']) ? SimpleIdStorage::class : $config['storage_service']; | ||
$genId = empty($config['generator_service']) ? RamseyUuid4Generator::class : $config['generator_service']; | ||
|
||
$container->setAlias(RequestIdStorage::class, $storeId) | ||
->setPublic(true); | ||
$container->setAlias(RequestIdGenerator::class, $genId) | ||
->setPublic(true); | ||
|
||
$container->register(RequestIdListener::class) | ||
->setArguments([ | ||
$config['request_header'], | ||
$config['response_header'], | ||
$config['trust_request_header'], | ||
new Reference($storeId), | ||
new Reference($genId), | ||
]) | ||
->setPublic(false) | ||
->addTag('kernel.event_subscriber'); | ||
|
||
if (!empty($config['enable_monolog'])) { | ||
$container->register(RequestIdProcessor::class) | ||
->addArgument(new Reference($storeId)) | ||
->setPublic(false) | ||
->addTag('monolog.processor'); | ||
} | ||
|
||
if (class_exists('Twig\Extension\AbstractExtension') && !empty($config['enable_twig'])) { | ||
$container->register(RequestIdExtension::class) | ||
->addArgument(new Reference($storeId)) | ||
->setPublic(false) | ||
->addTag('twig.extension'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId\EventListener; | ||
|
||
use DR\SymfonyRequestId\RequestIdGenerator; | ||
use DR\SymfonyRequestId\RequestIdStorage; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\HttpKernel\Event\RequestEvent; | ||
use Symfony\Component\HttpKernel\Event\ResponseEvent; | ||
use Symfony\Component\HttpKernel\KernelEvents; | ||
|
||
/** | ||
* Listens for requests and responses and sets up the request ID on each. | ||
* @internal | ||
*/ | ||
final class RequestIdListener implements EventSubscriberInterface | ||
{ | ||
/** | ||
* @param string $requestHeader The header to inspect for the incoming request ID. | ||
* @param string $responseHeader The header that will contain the request ID in the response. | ||
* @param bool $trustRequest Trust the value from the request? Or generate? | ||
* @param RequestIdStorage $idStorage The request ID storage, used to store the ID from the request or a newly generated ID. | ||
* @param RequestIdGenerator $idGenerator Used to generate a request ID if one isn't present. | ||
*/ | ||
public function __construct( | ||
private readonly string $requestHeader, | ||
private readonly string $responseHeader, | ||
private readonly bool $trustRequest, | ||
private readonly RequestIdStorage $idStorage, | ||
private readonly RequestIdGenerator $idGenerator | ||
) { | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public static function getSubscribedEvents(): array | ||
{ | ||
return [ | ||
KernelEvents::REQUEST => ['onRequest', 100], | ||
KernelEvents::RESPONSE => ['onResponse', -99], | ||
]; | ||
} | ||
|
||
public function onRequest(RequestEvent $event): void | ||
{ | ||
if ($event->isMainRequest() === false) { | ||
return; | ||
} | ||
|
||
$req = $event->getRequest(); | ||
|
||
// always give the incoming request priority. If it has the ID in | ||
// its headers already put that into our ID storage. | ||
if ($this->trustRequest && $req->headers->get($this->requestHeader) !== null) { | ||
$this->idStorage->setRequestId($req->headers->get($this->requestHeader)); | ||
|
||
return; | ||
} | ||
|
||
// similarly, if the request ID storage already has an ID set we | ||
// don't need to do anything other than put it into the request headers | ||
if ($this->idStorage->getRequestId() !== null) { | ||
$req->headers->set($this->requestHeader, $this->idStorage->getRequestId()); | ||
|
||
return; | ||
} | ||
|
||
$id = $this->idGenerator->generate(); | ||
$req->headers->set($this->requestHeader, $id); | ||
$this->idStorage->setRequestId($id); | ||
} | ||
|
||
public function onResponse(ResponseEvent $event): void | ||
{ | ||
if ($event->isMainRequest() === false) { | ||
return; | ||
} | ||
|
||
if ($this->idStorage->getRequestId() !== null) { | ||
$event->getResponse()->headers->set($this->responseHeader, $this->idStorage->getRequestId()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId\Generator; | ||
|
||
use DR\SymfonyRequestId\RequestIdGenerator; | ||
use Ramsey\Uuid\UuidFactory; | ||
use Ramsey\Uuid\UuidFactoryInterface; | ||
|
||
/** | ||
* Uses `ramsey/uuid` to generator v4 UUIDs for request ids. | ||
*/ | ||
final class RamseyUuid4Generator implements RequestIdGenerator | ||
{ | ||
public function __construct(private readonly UuidFactoryInterface $factory = new UuidFactory()) | ||
{ | ||
} | ||
|
||
public function generate(): string | ||
{ | ||
return (string)$this->factory->uuid4(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId\Generator; | ||
|
||
use DR\SymfonyRequestId\RequestIdGenerator; | ||
use Symfony\Component\Uid\Factory\UuidFactory; | ||
use Symfony\Component\Uid\UuidV4; | ||
|
||
/** | ||
* Uses symfony/uid to generate a UUIDv4 request ID. | ||
*/ | ||
final class SymfonyUuid4Generator implements RequestIdGenerator | ||
{ | ||
public function __construct(private readonly UuidFactory $factory = new UuidFactory(UuidV4::class, UuidV4::class, UuidV4::class, UuidV4::class)) | ||
{ | ||
} | ||
|
||
public function generate(): string | ||
{ | ||
return (string)$this->factory->create(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId\Monolog; | ||
|
||
use DR\SymfonyRequestId\RequestIdStorage; | ||
use Monolog\LogRecord; | ||
use Monolog\Processor\ProcessorInterface; | ||
|
||
/** | ||
* Adds the request ID to the Monolog record's `extra` key, so it can be used in formatters, etc. | ||
* @internal | ||
*/ | ||
final class RequestIdProcessor implements ProcessorInterface | ||
{ | ||
public function __construct(private readonly RequestIdStorage $storage) | ||
{ | ||
} | ||
|
||
public function __invoke(LogRecord $record): LogRecord | ||
{ | ||
$id = $this->storage->getRequestId(); | ||
if ($id !== null) { | ||
$record->extra['request_id'] = $id; | ||
} | ||
|
||
return $record; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId; | ||
|
||
use Symfony\Component\HttpKernel\Bundle\Bundle; | ||
|
||
final class RequestIdBundle extends Bundle | ||
{ | ||
// noop | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId; | ||
|
||
/** | ||
* Generates new (hopefully) unique request ID's for incoming requests if they | ||
* lack an ID. | ||
*/ | ||
interface RequestIdGenerator | ||
{ | ||
/** | ||
* Create a new request ID. | ||
*/ | ||
public function generate(): string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId; | ||
|
||
/** | ||
* Stores the identifiers for the request. | ||
*/ | ||
interface RequestIdStorage | ||
{ | ||
/** | ||
* @return string|null Null if the request does not have an identifier | ||
*/ | ||
public function getRequestId() : ?string; | ||
|
||
public function setRequestId(?string $id) : void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace DR\SymfonyRequestId; | ||
|
||
/** | ||
* And ID storage backed by a property, simple. | ||
*/ | ||
final class SimpleIdStorage implements RequestIdStorage | ||
{ | ||
private ?string $requestId = null; | ||
|
||
public function getRequestId(): ?string | ||
{ | ||
return $this->requestId; | ||
} | ||
|
||
public function setRequestId(?string $id): void | ||
{ | ||
$this->requestId = $id; | ||
} | ||
} |
Oops, something went wrong.