Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bdcdc6e

Browse files
committed
feature#9170 Decoupled TraceableEventDispatcher from the Profiler (fabpot)
This PR was merged into the master branch. Discussion ---------- Decoupled TraceableEventDispatcher from the Profiler | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | n/a This PR removes the Profiler dependency on the TraceableEventDispatcher. That makes things more decoupled and cleaner. This PR also cleans up how profiles are stored; a Profile is now always stored only once. I've created a `LateDataCollectorInterface` that is implemented for data collector that needs to get information from data that are available very late in the request process (when the request and the response are not even available anymore). The `lateCollect()` method is called just before the profile is stored. We have 3 data collectors that implement that interface: * Time: As the traceable event dipsatcher gets inject timing information via the stopwatch about all events (including the `terminate` one), we need to get events from the stopwatch as late as possible. * Event: The traceable event dispatcher gathers all called listeners to determine non-called ones. To be able to accurately do that for all events (including the `terminate` one), we need to get the data as late as possible. * Memory: We want to get the memory as late as possible to get the most accurate number as possible I'm not very happy with the name and as always, better suggestions would be much appreciated. This is an extract from #9168 Commits ------- 5cedea2 [HttpKernel] added LateDataCollectorInterface 9c4bc9a [HttpKernel] decoupled TraceableEventDispatcher and Profiler
2 parents 0f80916 + 5cedea2 commit bdcdc6e

File tree

11 files changed

+145
-119
lines changed

11 files changed

+145
-119
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
<service id="data_collector.events" class="%data_collector.events.class%" public="false">
3636
<tag name="data_collector" template="@WebProfiler/Collector/events.html.twig" id="events" priority="255" />
37+
<argument type="service" id="event_dispatcher" on-invalid="ignore" />
3738
</service>
3839

3940
<service id="data_collector.logger" class="%data_collector.logger.class%" public="false">
@@ -45,6 +46,7 @@
4546
<service id="data_collector.time" class="%data_collector.time.class%" public="false">
4647
<tag name="data_collector" template="@WebProfiler/Collector/time.html.twig" id="time" priority="255" />
4748
<argument type="service" id="kernel" on-invalid="ignore" />
49+
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
4850
</service>
4951

5052
<service id="data_collector.memory" class="%data_collector.memory.class%" public="false">

src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
<argument type="service" id="event_dispatcher" />
2020
<argument type="service" id="debug.stopwatch" />
2121
<argument type="service" id="logger" on-invalid="null" />
22-
<call method="setProfiler"><argument type="service" id="profiler" on-invalid="null" /></call>
2322
</service>
2423

2524
<service id="debug.controller_resolver" class="%debug.controller_resolver.class%">

src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<argument type="service" id="profiler.request_matcher" on-invalid="null" />
3030
<argument>%profiler_listener.only_exceptions%</argument>
3131
<argument>%profiler_listener.only_master_requests%</argument>
32+
<argument type="service" id="request_stack" />
3233
</service>
3334
</services>
3435
</container>

src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,26 @@
1111

1212
namespace Symfony\Component\HttpKernel\DataCollector;
1313

14+
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
1415
use Symfony\Component\HttpFoundation\Request;
1516
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1618
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface;
1719

1820
/**
1921
* EventDataCollector.
2022
*
2123
* @author Fabien Potencier <[email protected]>
2224
*/
23-
class EventDataCollector extends DataCollector
25+
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
2426
{
27+
protected $dispatcher;
28+
29+
public function __construct(EventDispatcherInterface $dispatcher = null)
30+
{
31+
$this->dispatcher = $dispatcher;
32+
}
33+
2534
/**
2635
* {@inheritdoc}
2736
*/
@@ -33,6 +42,14 @@ public function collect(Request $request, Response $response, \Exception $except
3342
);
3443
}
3544

45+
public function lateCollect()
46+
{
47+
if ($this->dispatcher instanceof TraceableEventDispatcherInterface) {
48+
$this->setCalledListeners($this->dispatcher->getCalledListeners());
49+
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners());
50+
}
51+
}
52+
3653
/**
3754
* Sets the called listeners.
3855
*
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Component\HttpKernel\DataCollector;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
17+
/**
18+
* LateDataCollectorInterface.
19+
*
20+
* @author Fabien Potencier <[email protected]>
21+
*/
22+
interface LateDataCollectorInterface
23+
{
24+
/**
25+
* Collects data as late as possible.
26+
*/
27+
public function lateCollect();
28+
}

src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ public function __construct($logger = null)
3232
}
3333
}
3434

35+
/**
36+
* {@inheritdoc}
37+
*/
38+
public function collect(Request $request, Response $response, \Exception $exception = null)
39+
{
40+
// everything is done as late as possible
41+
}
42+
3543
/**
3644
* {@inheritdoc}
3745
*/

src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\HttpKernel\DataCollector;
1313

14+
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
1415
use Symfony\Component\HttpFoundation\Request;
1516
use Symfony\Component\HttpFoundation\Response;
1617

@@ -19,7 +20,7 @@
1920
*
2021
* @author Fabien Potencier <[email protected]>
2122
*/
22-
class MemoryDataCollector extends DataCollector
23+
class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface
2324
{
2425
public function __construct()
2526
{
@@ -37,6 +38,14 @@ public function collect(Request $request, Response $response, \Exception $except
3738
$this->updateMemoryUsage();
3839
}
3940

41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function lateCollect()
45+
{
46+
$this->updateMemoryUsage();
47+
}
48+
4049
/**
4150
* Gets the memory.
4251
*

src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,26 @@
1212
namespace Symfony\Component\HttpKernel\DataCollector;
1313

1414
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
15+
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
1516
use Symfony\Component\HttpKernel\KernelInterface;
1617
use Symfony\Component\HttpFoundation\Request;
1718
use Symfony\Component\HttpFoundation\Response;
19+
use Symfony\Component\Stopwatch\Stopwatch;
1820

1921
/**
2022
* TimeDataCollector.
2123
*
2224
* @author Fabien Potencier <[email protected]>
2325
*/
24-
class TimeDataCollector extends DataCollector
26+
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
2527
{
2628
protected $kernel;
29+
protected $stopwatch;
2730

28-
public function __construct(KernelInterface $kernel = null)
31+
public function __construct(KernelInterface $kernel = null, $stopwatch = null)
2932
{
3033
$this->kernel = $kernel;
34+
$this->stopwatch = $stopwatch;
3135
}
3236

3337
/**
@@ -42,11 +46,23 @@ public function collect(Request $request, Response $response, \Exception $except
4246
}
4347

4448
$this->data = array(
49+
'token' => $response->headers->get('X-Debug-Token'),
4550
'start_time' => $startTime * 1000,
4651
'events' => array(),
4752
);
4853
}
4954

55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function lateCollect()
59+
{
60+
if (null !== $this->stopwatch && isset($this->data['token'])) {
61+
$this->setEvents($this->stopwatch->getSectionEvents($this->data['token']));
62+
}
63+
unset($this->data['token']);
64+
}
65+
5066
/**
5167
* Sets the request events.
5268
*

src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php

Lines changed: 13 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
use Symfony\Component\Stopwatch\Stopwatch;
1515
use Symfony\Component\HttpKernel\KernelEvents;
1616
use Psr\Log\LoggerInterface;
17-
use Symfony\Component\HttpKernel\Profiler\Profile;
18-
use Symfony\Component\HttpKernel\Profiler\Profiler;
1917
use Symfony\Component\EventDispatcher\Event;
2018
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2119
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -33,7 +31,6 @@ class TraceableEventDispatcher implements EventDispatcherInterface, TraceableEve
3331
private $logger;
3432
private $called;
3533
private $stopwatch;
36-
private $profiler;
3734
private $dispatcher;
3835
private $wrappedListeners;
3936
private $firstCalledEvent;
@@ -59,11 +56,16 @@ public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $sto
5956
/**
6057
* Sets the profiler.
6158
*
59+
* The traceable event dispatcher does not use the profiler anymore.
60+
* The job is now done directly by the Profiler listener and the
61+
* data collectors themselves.
62+
*
6263
* @param Profiler|null $profiler A Profiler instance
64+
*
65+
* @deprecated Deprecated since version 2.4, to be removed in 3.0.
6366
*/
6467
public function setProfiler(Profiler $profiler = null)
6568
{
66-
$this->profiler = $profiler;
6769
}
6870

6971
/**
@@ -142,7 +144,9 @@ public function dispatch($eventName, Event $event = null)
142144

143145
unset($this->firstCalledEvent[$eventName]);
144146

145-
$e->stop();
147+
if ($e->isStarted()) {
148+
$e->stop();
149+
}
146150

147151
$this->postDispatch($eventName, $event);
148152

@@ -312,57 +316,6 @@ private function getListenerInfo($listener, $eventName)
312316
return $info;
313317
}
314318

315-
/**
316-
* Updates the stopwatch data in the profile hierarchy.
317-
*
318-
* @param string $token Profile token
319-
* @param Boolean $updateChildren Whether to update the children altogether
320-
*/
321-
private function updateProfiles($token, $updateChildren)
322-
{
323-
if (!$this->profiler || !$profile = $this->profiler->loadProfile($token)) {
324-
return;
325-
}
326-
327-
$this->saveInfoInProfile($profile, $updateChildren);
328-
}
329-
330-
/**
331-
* Update the profiles with the timing and events information and saves them.
332-
*
333-
* @param Profile $profile The root profile
334-
* @param Boolean $updateChildren Whether to update the children altogether
335-
*/
336-
private function saveInfoInProfile(Profile $profile, $updateChildren)
337-
{
338-
try {
339-
$collector = $profile->getCollector('memory');
340-
$collector->updateMemoryUsage();
341-
} catch (\InvalidArgumentException $e) {
342-
}
343-
344-
try {
345-
$collector = $profile->getCollector('time');
346-
$collector->setEvents($this->stopwatch->getSectionEvents($profile->getToken()));
347-
} catch (\InvalidArgumentException $e) {
348-
}
349-
350-
try {
351-
$collector = $profile->getCollector('events');
352-
$collector->setCalledListeners($this->getCalledListeners());
353-
$collector->setNotCalledListeners($this->getNotCalledListeners());
354-
} catch (\InvalidArgumentException $e) {
355-
}
356-
357-
$this->profiler->saveProfile($profile);
358-
359-
if ($updateChildren) {
360-
foreach ($profile->getChildren() as $child) {
361-
$this->saveInfoInProfile($child, true);
362-
}
363-
}
364-
}
365-
366319
private function preDispatch($eventName, Event $event)
367320
{
368321
// wrap all listeners before they are called
@@ -411,23 +364,14 @@ private function postDispatch($eventName, Event $event)
411364
case KernelEvents::RESPONSE:
412365
$token = $event->getResponse()->headers->get('X-Debug-Token');
413366
$this->stopwatch->stopSection($token);
414-
if ($event->isMasterRequest()) {
415-
// The profiles can only be updated once they have been created
416-
// that is after the 'kernel.response' event of the main request
417-
$this->updateProfiles($token, true);
418-
}
419367
break;
420368
case KernelEvents::TERMINATE:
421-
$token = $event->getResponse()->headers->get('X-Debug-Token');
422369
// In the special case described in the `preDispatch` method above, the `$token` section
423370
// does not exist, then closing it throws an exception which must be caught.
371+
$token = $event->getResponse()->headers->get('X-Debug-Token');
424372
try {
425373
$this->stopwatch->stopSection($token);
426374
} catch (\LogicException $e) {}
427-
// The children profiles have been updated by the previous 'kernel.response'
428-
// event. Only the root profile need to be updated with the 'kernel.terminate'
429-
// timing informations.
430-
$this->updateProfiles($token, false);
431375
break;
432376
}
433377

@@ -448,7 +392,9 @@ private function wrapListener($eventName, $listener)
448392

449393
call_user_func($listener, $event, $eventName, $self);
450394

451-
$e->stop();
395+
if ($e->isStarted()) {
396+
$e->stop();
397+
}
452398

453399
if ($event->isPropagationStopped()) {
454400
$self->logSkippedListeners($eventName, $event, $listener);

0 commit comments

Comments
 (0)