Skip to content

Commit 62ee940

Browse files
trakosPiotr Stankowski
authored and
Piotr Stankowski
committed
[MonologBridge] Add ConsoleCommandProcessor and RouteProcessor
1 parent bc45a0e commit 62ee940

File tree

5 files changed

+302
-0
lines changed

5 files changed

+302
-0
lines changed

src/Symfony/Bridge/Monolog/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ CHANGELOG
55
-----
66

77
* added `ProcessorInterface`: an optional interface to allow autoconfiguration of Monolog processors
8+
* added `ConsoleCommandProcessor`: monolog processor that adds command name and arguments
9+
* added `RouteProcessor`: monolog processor that adds route name, controller::action and route params
810

911
4.1.0
1012
-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Monolog\Processor;
13+
14+
use Symfony\Component\Console\ConsoleEvents;
15+
use Symfony\Component\Console\Event\ConsoleEvent;
16+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17+
18+
/**
19+
* Adds the current console command information to the log entry.
20+
*
21+
* @author Piotr Stankowski <git@trakos.pl>
22+
*/
23+
class ConsoleCommandProcessor implements ProcessorInterface, EventSubscriberInterface
24+
{
25+
private $commandData;
26+
private $includeArguments;
27+
private $includeOptions;
28+
29+
public function __construct(bool $includeArguments = true, bool $includeOptions = false)
30+
{
31+
$this->includeArguments = $includeArguments;
32+
$this->includeOptions = $includeOptions;
33+
}
34+
35+
public static function getSubscribedEvents()
36+
{
37+
return array(
38+
ConsoleEvents::COMMAND => array('onCommand', 1),
39+
);
40+
}
41+
42+
public function __invoke(array $records)
43+
{
44+
if (null !== $this->commandData && !isset($records['extra']['command'])) {
45+
$records['extra']['command'] = $this->commandData;
46+
}
47+
48+
return $records;
49+
}
50+
51+
public function onCommand(ConsoleEvent $event)
52+
{
53+
$this->commandData = array(
54+
'name' => $event->getCommand()->getName(),
55+
);
56+
if ($this->includeArguments) {
57+
$this->commandData['arguments'] = $event->getInput()->getArguments();
58+
}
59+
if ($this->includeOptions) {
60+
$this->commandData['options'] = $event->getInput()->getOptions();
61+
}
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Monolog\Processor;
13+
14+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
16+
use Symfony\Component\HttpKernel\KernelEvents;
17+
18+
/**
19+
* Adds the current route information to the log entry.
20+
*
21+
* @author Piotr Stankowski <git@trakos.pl>
22+
*/
23+
class RouteProcessor implements ProcessorInterface, EventSubscriberInterface
24+
{
25+
private $routeData;
26+
private $includeParams;
27+
28+
public function __construct(bool $includeParams = true)
29+
{
30+
$this->includeParams = $includeParams;
31+
}
32+
33+
public function __invoke(array $records)
34+
{
35+
if (null !== $this->routeData && !isset($records['extra']['route'])) {
36+
$records['extra']['route'] = $this->routeData;
37+
}
38+
39+
return $records;
40+
}
41+
42+
public function onKernelRequest(GetResponseEvent $event)
43+
{
44+
$request = $event->getRequest();
45+
46+
if (!$request->attributes->has('_controller')) {
47+
return;
48+
}
49+
50+
$this->routeData = array(
51+
'controller' => $request->attributes->get('_controller'),
52+
'route' => $request->attributes->get('_route'),
53+
);
54+
55+
if ($this->includeParams) {
56+
$this->routeData['route_params'] = $request->attributes->get('_route_params');
57+
}
58+
}
59+
60+
public static function getSubscribedEvents()
61+
{
62+
return array(
63+
KernelEvents::REQUEST => array('onKernelRequest', 1),
64+
);
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Monolog\Tests\Processor;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\Monolog\Processor\ConsoleCommandProcessor;
16+
use Symfony\Component\Console\Command\Command;
17+
use Symfony\Component\Console\Event\ConsoleEvent;
18+
use Symfony\Component\Console\Input\InputInterface;
19+
20+
class ConsoleCommandProcessorTest extends TestCase
21+
{
22+
const TEST_ARGUMENTS = array('test' => 'argument');
23+
const TEST_OPTIONS = array('test' => 'option');
24+
const TEST_NAME = 'some:test';
25+
26+
public function testProcessor()
27+
{
28+
$processor = new ConsoleCommandProcessor();
29+
$processor->onCommand($this->getConsoleEvent());
30+
31+
$record = $processor(array('extra' => array()));
32+
33+
$this->assertArrayHasKey('command', $record['extra']);
34+
$this->assertEquals(
35+
array('name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS),
36+
$record['extra']['command']
37+
);
38+
}
39+
40+
public function testProcessorWithOptions()
41+
{
42+
$processor = new ConsoleCommandProcessor(true, true);
43+
$processor->onCommand($this->getConsoleEvent());
44+
45+
$record = $processor(array('extra' => array()));
46+
47+
$this->assertArrayHasKey('command', $record['extra']);
48+
$this->assertEquals(
49+
array('name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS, 'options' => self::TEST_OPTIONS),
50+
$record['extra']['command']
51+
);
52+
}
53+
54+
public function testProcessorDoesNothingWhenNotInConsole()
55+
{
56+
$processor = new ConsoleCommandProcessor(true, true);
57+
58+
$record = $processor(array('extra' => array()));
59+
$this->assertEquals(array('extra' => array()), $record);
60+
}
61+
62+
private function getConsoleEvent(): ConsoleEvent
63+
{
64+
$input = $this->getMockBuilder(InputInterface::class)->getMock();
65+
$input->method('getArguments')->willReturn(self::TEST_ARGUMENTS);
66+
$input->method('getOptions')->willReturn(self::TEST_OPTIONS);
67+
$command = $this->getMockBuilder(Command::class)->disableOriginalConstructor()->getMock();
68+
$command->method('getName')->willReturn(self::TEST_NAME);
69+
$consoleEvent = $this->getMockBuilder(ConsoleEvent::class)->disableOriginalConstructor()->getMock();
70+
$consoleEvent->method('getCommand')->willReturn($command);
71+
$consoleEvent->method('getInput')->willReturn($input);
72+
73+
return $consoleEvent;
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Monolog\Tests\Processor;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\Monolog\Processor\RouteProcessor;
16+
use Symfony\Component\HttpFoundation\ParameterBag;
17+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
18+
19+
class RouteProcessorTest extends TestCase
20+
{
21+
const TEST_CONTROLLER = 'App\Controller\SomeController::someMethod';
22+
const TEST_ROUTE = 'someRouteName';
23+
const TEST_PARAMS = array('param1' => 'value1');
24+
25+
public function testProcessor()
26+
{
27+
$processor = new RouteProcessor();
28+
$processor->onKernelRequest($this->getFilledRequestEvent());
29+
30+
$record = $processor(array('extra' => array()));
31+
32+
$this->assertArrayHasKey('route', $record['extra']);
33+
$this->assertEquals(
34+
array('controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE, 'route_params' => self::TEST_PARAMS),
35+
$record['extra']['route']
36+
);
37+
}
38+
39+
public function testProcessorWithoutParams()
40+
{
41+
$processor = new RouteProcessor(false);
42+
$processor->onKernelRequest($this->getFilledRequestEvent());
43+
44+
$record = $processor(array('extra' => array()));
45+
46+
$this->assertArrayHasKey('route', $record['extra']);
47+
$this->assertEquals(
48+
array('controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE),
49+
$record['extra']['route']
50+
);
51+
}
52+
53+
public function testProcessorWithEmptyRequest()
54+
{
55+
$processor = new RouteProcessor();
56+
$processor->onKernelRequest($this->getEmptyRequestEvent());
57+
58+
$record = $processor(array('extra' => array()));
59+
$this->assertEquals(array('extra' => array()), $record);
60+
}
61+
62+
public function testProcessorDoesNothingWhenNoRequest()
63+
{
64+
$processor = new RouteProcessor();
65+
66+
$record = $processor(array('extra' => array()));
67+
$this->assertEquals(array('extra' => array()), $record);
68+
}
69+
70+
private function getRequestEvent(array $attributes): GetResponseEvent
71+
{
72+
$request = new \stdClass();
73+
$request->attributes = new ParameterBag($attributes);
74+
75+
$event = $this->getMockBuilder(GetResponseEvent::class)->disableOriginalConstructor()->getMock();
76+
$event->method('getRequest')->willReturn($request);
77+
78+
return $event;
79+
}
80+
81+
private function getEmptyRequestEvent(): GetResponseEvent
82+
{
83+
return $this->getRequestEvent(array());
84+
}
85+
86+
private function getFilledRequestEvent(): GetResponseEvent
87+
{
88+
return $this->getRequestEvent(
89+
array(
90+
'_controller' => self::TEST_CONTROLLER,
91+
'_route' => self::TEST_ROUTE,
92+
'_route_params' => self::TEST_PARAMS,
93+
)
94+
);
95+
}
96+
}

0 commit comments

Comments
 (0)