Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #28330 [MonologBridge] Add monolog processors adding route an…
…d command info (trakos) This PR was squashed before being merged into the 4.3-dev branch (closes #28330). Discussion ---------- [MonologBridge] Add monolog processors adding route and command info | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | symfony/symfony-docs#10244 This PR adds two simple processors that add context to every log entry. RouteProcessor adds routing information: `app.INFO: Some log text {"someContext":"ctx"} {"route":{"controller":"App\\Controller\\SomeController::number","route":"index","route_params":[]}` ConsoleCommandProcessors adds current command information: `app.INFO: Some log text {"someContext":"ctx"} {"command":{"name":"app:some-command","arguments":{"command":"app:some-command","some-argument":10}}}` For ConsoleCommandProcessor I've decided against including command options by default, because there's a lot of default ones: `"options":{"help":false,"quiet":false,"verbose":false,"version":false,"ansi":false,"no-ansi":false,"no-interaction":false,"env":"dev","no-debug":false}`. This behavior can be changed with a constructor argument. Commits ------- 669f6b2 [MonologBridge] Add monolog processors adding route and command info
- Loading branch information
Showing
5 changed files
with
398 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
69 changes: 69 additions & 0 deletions
69
src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php
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,69 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bridge\Monolog\Processor; | ||
|
||
use Symfony\Component\Console\ConsoleEvents; | ||
use Symfony\Component\Console\Event\ConsoleEvent; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Contracts\Service\ResetInterface; | ||
|
||
/** | ||
* Adds the current console command information to the log entry. | ||
* | ||
* @author Piotr Stankowski <git@trakos.pl> | ||
*/ | ||
class ConsoleCommandProcessor implements EventSubscriberInterface, ResetInterface | ||
{ | ||
private $commandData; | ||
private $includeArguments; | ||
private $includeOptions; | ||
|
||
public function __construct(bool $includeArguments = true, bool $includeOptions = false) | ||
{ | ||
$this->includeArguments = $includeArguments; | ||
$this->includeOptions = $includeOptions; | ||
} | ||
|
||
public function __invoke(array $records) | ||
{ | ||
if (null !== $this->commandData && !isset($records['extra']['command'])) { | ||
$records['extra']['command'] = $this->commandData; | ||
} | ||
|
||
return $records; | ||
} | ||
|
||
public function reset() | ||
{ | ||
$this->commandData = null; | ||
} | ||
|
||
public function addCommandData(ConsoleEvent $event) | ||
{ | ||
$this->commandData = array( | ||
'name' => $event->getCommand()->getName(), | ||
); | ||
if ($this->includeArguments) { | ||
$this->commandData['arguments'] = $event->getInput()->getArguments(); | ||
} | ||
if ($this->includeOptions) { | ||
$this->commandData['options'] = $event->getInput()->getOptions(); | ||
} | ||
} | ||
|
||
public static function getSubscribedEvents() | ||
{ | ||
return array( | ||
ConsoleEvents::COMMAND => array('addCommandData', 1), | ||
); | ||
} | ||
} |
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 | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bridge\Monolog\Processor; | ||
|
||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\HttpKernel\Event\FinishRequestEvent; | ||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
use Symfony\Component\HttpKernel\KernelEvents; | ||
use Symfony\Contracts\Service\ResetInterface; | ||
|
||
/** | ||
* Adds the current route information to the log entry. | ||
* | ||
* @author Piotr Stankowski <git@trakos.pl> | ||
*/ | ||
class RouteProcessor implements EventSubscriberInterface, ResetInterface | ||
{ | ||
private $routeData; | ||
private $includeParams; | ||
|
||
public function __construct(bool $includeParams = true) | ||
{ | ||
$this->includeParams = $includeParams; | ||
$this->reset(); | ||
} | ||
|
||
public function __invoke(array $records) | ||
{ | ||
if ($this->routeData && !isset($records['extra']['requests'])) { | ||
$records['extra']['requests'] = array_values($this->routeData); | ||
} | ||
|
||
return $records; | ||
} | ||
|
||
public function reset() | ||
{ | ||
$this->routeData = array(); | ||
} | ||
|
||
public function addRouteData(GetResponseEvent $event) | ||
{ | ||
if ($event->isMasterRequest()) { | ||
$this->reset(); | ||
} | ||
|
||
$request = $event->getRequest(); | ||
if (!$request->attributes->has('_controller')) { | ||
return; | ||
} | ||
|
||
$currentRequestData = array( | ||
'controller' => $request->attributes->get('_controller'), | ||
'route' => $request->attributes->get('_route'), | ||
); | ||
|
||
if ($this->includeParams) { | ||
$currentRequestData['route_params'] = $request->attributes->get('_route_params'); | ||
} | ||
|
||
$this->routeData[spl_object_id($request)] = $currentRequestData; | ||
} | ||
|
||
public function removeRouteData(FinishRequestEvent $event) | ||
{ | ||
$requestId = spl_object_id($event->getRequest()); | ||
unset($this->routeData[$requestId]); | ||
} | ||
|
||
public static function getSubscribedEvents() | ||
{ | ||
return array( | ||
KernelEvents::REQUEST => array('addRouteData', 1), | ||
KernelEvents::FINISH_REQUEST => array('removeRouteData', 1), | ||
); | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php
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,75 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bridge\Monolog\Tests\Processor; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Symfony\Bridge\Monolog\Processor\ConsoleCommandProcessor; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Event\ConsoleEvent; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
|
||
class ConsoleCommandProcessorTest extends TestCase | ||
{ | ||
private const TEST_ARGUMENTS = array('test' => 'argument'); | ||
private const TEST_OPTIONS = array('test' => 'option'); | ||
private const TEST_NAME = 'some:test'; | ||
|
||
public function testProcessor() | ||
{ | ||
$processor = new ConsoleCommandProcessor(); | ||
$processor->addCommandData($this->getConsoleEvent()); | ||
|
||
$record = $processor(array('extra' => array())); | ||
|
||
$this->assertArrayHasKey('command', $record['extra']); | ||
$this->assertEquals( | ||
array('name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS), | ||
$record['extra']['command'] | ||
); | ||
} | ||
|
||
public function testProcessorWithOptions() | ||
{ | ||
$processor = new ConsoleCommandProcessor(true, true); | ||
$processor->addCommandData($this->getConsoleEvent()); | ||
|
||
$record = $processor(array('extra' => array())); | ||
|
||
$this->assertArrayHasKey('command', $record['extra']); | ||
$this->assertEquals( | ||
array('name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS, 'options' => self::TEST_OPTIONS), | ||
$record['extra']['command'] | ||
); | ||
} | ||
|
||
public function testProcessorDoesNothingWhenNotInConsole() | ||
{ | ||
$processor = new ConsoleCommandProcessor(true, true); | ||
|
||
$record = $processor(array('extra' => array())); | ||
$this->assertEquals(array('extra' => array()), $record); | ||
} | ||
|
||
private function getConsoleEvent(): ConsoleEvent | ||
{ | ||
$input = $this->getMockBuilder(InputInterface::class)->getMock(); | ||
$input->method('getArguments')->willReturn(self::TEST_ARGUMENTS); | ||
$input->method('getOptions')->willReturn(self::TEST_OPTIONS); | ||
$command = $this->getMockBuilder(Command::class)->disableOriginalConstructor()->getMock(); | ||
$command->method('getName')->willReturn(self::TEST_NAME); | ||
$consoleEvent = $this->getMockBuilder(ConsoleEvent::class)->disableOriginalConstructor()->getMock(); | ||
$consoleEvent->method('getCommand')->willReturn($command); | ||
$consoleEvent->method('getInput')->willReturn($input); | ||
|
||
return $consoleEvent; | ||
} | ||
} |
Oops, something went wrong.