Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #27321 [Messenger][Profiler] Trace middleware execution (ogiz…
…anagi) This PR was merged into the 4.2-dev branch. Discussion ---------- [Messenger][Profiler] Trace middleware execution | Q | A | ------------- | --- | Branch? | master <!-- see below --> | Bug fix? | no | New feature? | yes <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | part of #27262 <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | N/A This is a start for #27262 with: - traceable Messenger middlewares - ~~a dedicated category for http kernel controller args resolvers~~ => See #28387 <img width="1071" alt="screenshot 2018-05-20 a 12 23 55" src="https://user-images.githubusercontent.com/2211145/40278071-98c04924-5c2a-11e8-9770-d78ac62d2c16.PNG"> Messenger middleware are traced, with bus info (if not shared accros buses): <img width="1069" alt="screenshot 2018-05-20 a 12 28 15" src="https://user-images.githubusercontent.com/2211145/40278073-9e6979f4-5c2a-11e8-9657-ee3aa057a5be.PNG"> Another possibility is to use the middleware id instead of the class (with or without extra bus info?): <img width="1074" alt="screenshot 2018-05-20 a 12 32 24" src="https://user-images.githubusercontent.com/2211145/40278074-9e85f43a-5c2a-11e8-9f13-ad41de342079.PNG"> (_of course, collected times are faked here using `usleep` in the traceable middleware_) Commits ------- e974f67 [Messenger][Profiler] Trace middleware execution
- Loading branch information
Showing
6 changed files
with
230 additions
and
2 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
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/Component/Messenger/Middleware/Enhancers/TraceableMiddleware.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\Component\Messenger\Middleware\Enhancers; | ||
|
||
use Symfony\Component\Messenger\Envelope; | ||
use Symfony\Component\Messenger\EnvelopeAwareInterface; | ||
use Symfony\Component\Messenger\Middleware\MiddlewareInterface; | ||
use Symfony\Component\Stopwatch\Stopwatch; | ||
|
||
/** | ||
* Collects some data about a middleware. | ||
* | ||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com> | ||
*/ | ||
class TraceableMiddleware implements MiddlewareInterface, EnvelopeAwareInterface | ||
{ | ||
private $inner; | ||
private $stopwatch; | ||
private $busName; | ||
private $eventCategory; | ||
|
||
public function __construct(MiddlewareInterface $inner, Stopwatch $stopwatch, string $busName = null, string $eventCategory = 'messenger.middleware') | ||
{ | ||
$this->inner = $inner; | ||
$this->stopwatch = $stopwatch; | ||
$this->busName = $busName; | ||
$this->eventCategory = $eventCategory; | ||
} | ||
|
||
/** | ||
* @param Envelope $envelope | ||
*/ | ||
public function handle($envelope, callable $next) | ||
{ | ||
$class = \get_class($this->inner); | ||
$eventName = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; | ||
|
||
if ($this->busName) { | ||
$eventName .= " (bus: {$this->busName})"; | ||
} | ||
|
||
$this->stopwatch->start($eventName, $this->eventCategory); | ||
|
||
try { | ||
$result = $this->inner->handle($envelope->getMessageFor($this->inner), function ($message) use ($next, $eventName) { | ||
$this->stopwatch->stop($eventName); | ||
$result = $next($message); | ||
$this->stopwatch->start($eventName, $this->eventCategory); | ||
|
||
return $result; | ||
}); | ||
} finally { | ||
if ($this->stopwatch->isStarted($eventName)) { | ||
$this->stopwatch->stop($eventName); | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
} |
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
104 changes: 104 additions & 0 deletions
104
src/Symfony/Component/Messenger/Tests/Middleware/Enhancers/TraceableMiddlewareTest.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,104 @@ | ||
<?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\Component\Messenger\Tests\Middleware\Enhancers; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Symfony\Component\Messenger\Envelope; | ||
use Symfony\Component\Messenger\Middleware\Enhancers\TraceableMiddleware; | ||
use Symfony\Component\Messenger\Middleware\MiddlewareInterface; | ||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; | ||
use Symfony\Component\Stopwatch\Stopwatch; | ||
|
||
/** | ||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com> | ||
*/ | ||
class TraceableMiddlewareTest extends TestCase | ||
{ | ||
public function testHandle() | ||
{ | ||
$busId = 'command_bus'; | ||
$envelope = Envelope::wrap($message = new DummyMessage('Hello')); | ||
|
||
$middleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); | ||
$middleware->expects($this->once()) | ||
->method('handle') | ||
->with($message, $this->anything()) | ||
->will($this->returnCallback(function ($message, callable $next) { | ||
return $next($message); | ||
})) | ||
; | ||
|
||
$next = $this->createPartialMock(\stdClass::class, array('__invoke')); | ||
$next | ||
->expects($this->once()) | ||
->method('__invoke') | ||
->with($message) | ||
->willReturn($expectedReturnedValue = 'Hello') | ||
; | ||
|
||
$stopwatch = $this->createMock(Stopwatch::class); | ||
$stopwatch->expects($this->once())->method('isStarted')->willReturn(true); | ||
$stopwatch->expects($this->exactly(2)) | ||
->method('start') | ||
->with($this->matches('%sMiddlewareInterface%s (bus: command_bus)'), 'messenger.middleware') | ||
; | ||
$stopwatch->expects($this->exactly(2)) | ||
->method('stop') | ||
->with($this->matches('%sMiddlewareInterface%s (bus: command_bus)')) | ||
; | ||
|
||
$traced = new TraceableMiddleware($middleware, $stopwatch, $busId); | ||
|
||
$this->assertSame($expectedReturnedValue, $traced->handle($envelope, $next)); | ||
} | ||
|
||
/** | ||
* @expectedException \RuntimeException | ||
* @expectedExceptionMessage Foo exception from next callable | ||
*/ | ||
public function testHandleWithException() | ||
{ | ||
$busId = 'command_bus'; | ||
$envelope = Envelope::wrap($message = new DummyMessage('Hello')); | ||
|
||
$middleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); | ||
$middleware->expects($this->once()) | ||
->method('handle') | ||
->with($message, $this->anything()) | ||
->will($this->returnCallback(function ($message, callable $next) { | ||
return $next($message); | ||
})) | ||
; | ||
|
||
$next = $this->createPartialMock(\stdClass::class, array('__invoke')); | ||
$next | ||
->expects($this->once()) | ||
->method('__invoke') | ||
->willThrowException(new \RuntimeException('Foo exception from next callable')) | ||
; | ||
|
||
$stopwatch = $this->createMock(Stopwatch::class); | ||
$stopwatch->expects($this->once())->method('isStarted')->willReturn(true); | ||
// Start is only expected to be called once, as an exception is thrown by the next callable: | ||
$stopwatch->expects($this->exactly(1)) | ||
->method('start') | ||
->with($this->matches('%sMiddlewareInterface%s (bus: command_bus)'), 'messenger.middleware') | ||
; | ||
$stopwatch->expects($this->exactly(2)) | ||
->method('stop') | ||
->with($this->matches('%sMiddlewareInterface%s (bus: command_bus)')) | ||
; | ||
|
||
$traced = new TraceableMiddleware($middleware, $stopwatch, $busId); | ||
$traced->handle($envelope, $next); | ||
} | ||
} |
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