feature #27343 [Messenger][Profiler] Show dispatch caller (ogizanagi)
This PR was merged into the 4.2-dev branch.
Discussion
----------
[Messenger][Profiler] Show dispatch caller
| Q | A
| ------------- | ---
| Branch? | 4.2 <!-- 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 | N/A <!-- #-prefixed issue number(s), if any -->
| License | MIT
| Doc PR | N/A
Just something I missed on my checklist in the first PR:
![mai-22-2018 19-51-52](https://user-images.githubusercontent.com/2211145/40380514-a0ba3326-5df9-11e8-9dd6-82a42dc7ccae.gif)
Commits
-------
1c2f43f17c
[Messenger][Profiler] Show dispatch caller
This commit is contained in:
commit
59375662a3
@ -55,7 +55,8 @@
|
|||||||
|
|
||||||
.message-bus .badge.status-some-errors { line-height: 16px; border-bottom: 2px solid #B0413E; }
|
.message-bus .badge.status-some-errors { line-height: 16px; border-bottom: 2px solid #B0413E; }
|
||||||
|
|
||||||
.message-item .sf-toggle-content.sf-toggle-visible { display: table-row-group; }
|
.message-item tbody.sf-toggle-content.sf-toggle-visible { display: table-row-group; }
|
||||||
|
td.message-bus-dispatch-caller { background: #f1f2f3; }
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -100,12 +101,12 @@
|
|||||||
|
|
||||||
{% macro render_bus_messages(messages, showBus = false) %}
|
{% macro render_bus_messages(messages, showBus = false) %}
|
||||||
{% set discr = random() %}
|
{% set discr = random() %}
|
||||||
{% for i, dispatchCall in messages %}
|
{% for dispatchCall in messages %}
|
||||||
<table class="message-item">
|
<table class="message-item">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2" class="sf-toggle"
|
<th colspan="2" class="sf-toggle"
|
||||||
data-toggle-selector="#message-item-{{ discr }}-{{ i }}-details"
|
data-toggle-selector="#message-item-{{ discr }}-{{ loop.index0 }}-details"
|
||||||
data-toggle-initial="{{ loop.first ? 'display' }}"
|
data-toggle-initial="{{ loop.first ? 'display' }}"
|
||||||
>
|
>
|
||||||
<span class="dump-inline">{{ profiler_dump(dispatchCall.message.type) }}</span>
|
<span class="dump-inline">{{ profiler_dump(dispatchCall.message.type) }}</span>
|
||||||
@ -122,7 +123,31 @@
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="message-item-{{ discr }}-{{ i }}-details" class="sf-toggle-content">
|
<tbody id="message-item-{{ discr }}-{{ loop.index0 }}-details" class="sf-toggle-content">
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="message-bus-dispatch-caller">
|
||||||
|
<span class="metadata">In
|
||||||
|
{% set caller = dispatchCall.caller %}
|
||||||
|
{% if caller.line %}
|
||||||
|
{% set link = caller.file|file_link(caller.line) %}
|
||||||
|
{% if link %}
|
||||||
|
<a href="{{ link }}" title="{{ caller.file }}">{{ caller.name }}</a>
|
||||||
|
{% else %}
|
||||||
|
<abbr title="{{ caller.file }}">{{ caller.name }}</abbr>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{{ caller.name }}
|
||||||
|
{% endif %}
|
||||||
|
line <a class="text-small sf-toggle" data-toggle-selector="#sf-trace-{{ discr }}-{{ loop.index0 }}">{{ caller.line }}</a>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="hidden" id="sf-trace-{{ discr }}-{{ loop.index0 }}">
|
||||||
|
<div class="trace">
|
||||||
|
{{ caller.file|file_excerpt(caller.line) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% if showBus %}
|
{% if showBus %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-bold">Bus</td>
|
<td class="text-bold">Bus</td>
|
||||||
|
@ -914,6 +914,27 @@ table.logs .metadata {
|
|||||||
background: rgba(255, 255, 153, 0.5);
|
background: rgba(255, 255, 153, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{# Messenger panel
|
||||||
|
========================================================================= #}
|
||||||
|
|
||||||
|
#collector-content .message-bus .trace {
|
||||||
|
border: 1px solid #DDD;
|
||||||
|
background: #FFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
#collector-content .message-bus .trace {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
#collector-content .message-bus .trace li {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#collector-content .message-bus .trace li.selected {
|
||||||
|
background: rgba(255, 255, 153, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
{# Dump panel
|
{# Dump panel
|
||||||
========================================================================= #}
|
========================================================================= #}
|
||||||
#collector-content .sf-dump {
|
#collector-content .sf-dump {
|
||||||
|
@ -97,6 +97,7 @@ class MessengerDataCollector extends DataCollector implements LateDataCollectorI
|
|||||||
'type' => new ClassStub(\get_class($message)),
|
'type' => new ClassStub(\get_class($message)),
|
||||||
'value' => $message,
|
'value' => $message,
|
||||||
),
|
),
|
||||||
|
'caller' => $tracedMessage['caller'],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (array_key_exists('result', $tracedMessage)) {
|
if (array_key_exists('result', $tracedMessage)) {
|
||||||
|
@ -59,6 +59,7 @@ class MessengerDataCollectorTest extends TestCase
|
|||||||
|
|
||||||
public function getHandleTestData()
|
public function getHandleTestData()
|
||||||
{
|
{
|
||||||
|
$file = __FILE__;
|
||||||
$messageDump = <<<DUMP
|
$messageDump = <<<DUMP
|
||||||
"bus" => "default"
|
"bus" => "default"
|
||||||
"envelopeItems" => null
|
"envelopeItems" => null
|
||||||
@ -68,12 +69,17 @@ class MessengerDataCollectorTest extends TestCase
|
|||||||
-message: "dummy message"
|
-message: "dummy message"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
"caller" => array:3 [
|
||||||
|
"name" => "MessengerDataCollectorTest.php"
|
||||||
|
"file" => "$file"
|
||||||
|
"line" => %d
|
||||||
|
]
|
||||||
DUMP;
|
DUMP;
|
||||||
|
|
||||||
yield 'no returned value' => array(
|
yield 'no returned value' => array(
|
||||||
null,
|
null,
|
||||||
<<<DUMP
|
<<<DUMP
|
||||||
array:4 [
|
array:5 [
|
||||||
$messageDump
|
$messageDump
|
||||||
"result" => array:2 [
|
"result" => array:2 [
|
||||||
"type" => "NULL"
|
"type" => "NULL"
|
||||||
@ -86,7 +92,7 @@ DUMP
|
|||||||
yield 'scalar returned value' => array(
|
yield 'scalar returned value' => array(
|
||||||
'returned value',
|
'returned value',
|
||||||
<<<DUMP
|
<<<DUMP
|
||||||
array:4 [
|
array:5 [
|
||||||
$messageDump
|
$messageDump
|
||||||
"result" => array:2 [
|
"result" => array:2 [
|
||||||
"type" => "string"
|
"type" => "string"
|
||||||
@ -99,7 +105,7 @@ DUMP
|
|||||||
yield 'array returned value' => array(
|
yield 'array returned value' => array(
|
||||||
array('returned value'),
|
array('returned value'),
|
||||||
<<<DUMP
|
<<<DUMP
|
||||||
array:4 [
|
array:5 [
|
||||||
$messageDump
|
$messageDump
|
||||||
"result" => array:2 [
|
"result" => array:2 [
|
||||||
"type" => "array"
|
"type" => "array"
|
||||||
@ -124,6 +130,7 @@ DUMP
|
|||||||
$collector->registerBus('default', $bus);
|
$collector->registerBus('default', $bus);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$line = __LINE__ + 1;
|
||||||
$bus->dispatch($message);
|
$bus->dispatch($message);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Ignore.
|
// Ignore.
|
||||||
@ -134,8 +141,9 @@ DUMP
|
|||||||
$messages = $collector->getMessages();
|
$messages = $collector->getMessages();
|
||||||
$this->assertCount(1, $messages);
|
$this->assertCount(1, $messages);
|
||||||
|
|
||||||
|
$file = __FILE__;
|
||||||
$this->assertStringMatchesFormat(<<<DUMP
|
$this->assertStringMatchesFormat(<<<DUMP
|
||||||
array:4 [
|
array:5 [
|
||||||
"bus" => "default"
|
"bus" => "default"
|
||||||
"envelopeItems" => null
|
"envelopeItems" => null
|
||||||
"message" => array:2 [
|
"message" => array:2 [
|
||||||
@ -144,6 +152,11 @@ array:4 [
|
|||||||
-message: "dummy message"
|
-message: "dummy message"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
"caller" => array:3 [
|
||||||
|
"name" => "MessengerDataCollectorTest.php"
|
||||||
|
"file" => "$file"
|
||||||
|
"line" => $line
|
||||||
|
]
|
||||||
"exception" => array:2 [
|
"exception" => array:2 [
|
||||||
"type" => "RuntimeException"
|
"type" => "RuntimeException"
|
||||||
"value" => RuntimeException %A
|
"value" => RuntimeException %A
|
||||||
|
@ -28,12 +28,18 @@ class TraceableMessageBusTest extends TestCase
|
|||||||
$bus->expects($this->once())->method('dispatch')->with($message)->willReturn($result = array('foo' => 'bar'));
|
$bus->expects($this->once())->method('dispatch')->with($message)->willReturn($result = array('foo' => 'bar'));
|
||||||
|
|
||||||
$traceableBus = new TraceableMessageBus($bus);
|
$traceableBus = new TraceableMessageBus($bus);
|
||||||
|
$line = __LINE__ + 1;
|
||||||
$this->assertSame($result, $traceableBus->dispatch($message));
|
$this->assertSame($result, $traceableBus->dispatch($message));
|
||||||
$this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages());
|
$this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages());
|
||||||
$this->assertArraySubset(array(
|
$this->assertArraySubset(array(
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'result' => $result,
|
'result' => $result,
|
||||||
'envelopeItems' => null,
|
'envelopeItems' => null,
|
||||||
|
'caller' => array(
|
||||||
|
'name' => 'TraceableMessageBusTest.php',
|
||||||
|
'file' => __FILE__,
|
||||||
|
'line' => $line,
|
||||||
|
),
|
||||||
), $tracedMessages[0], true);
|
), $tracedMessages[0], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,12 +51,18 @@ class TraceableMessageBusTest extends TestCase
|
|||||||
$bus->expects($this->once())->method('dispatch')->with($envelope)->willReturn($result = array('foo' => 'bar'));
|
$bus->expects($this->once())->method('dispatch')->with($envelope)->willReturn($result = array('foo' => 'bar'));
|
||||||
|
|
||||||
$traceableBus = new TraceableMessageBus($bus);
|
$traceableBus = new TraceableMessageBus($bus);
|
||||||
|
$line = __LINE__ + 1;
|
||||||
$this->assertSame($result, $traceableBus->dispatch($envelope));
|
$this->assertSame($result, $traceableBus->dispatch($envelope));
|
||||||
$this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages());
|
$this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages());
|
||||||
$this->assertArraySubset(array(
|
$this->assertArraySubset(array(
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'result' => $result,
|
'result' => $result,
|
||||||
'envelopeItems' => array($envelopeItem),
|
'envelopeItems' => array($envelopeItem),
|
||||||
|
'caller' => array(
|
||||||
|
'name' => 'TraceableMessageBusTest.php',
|
||||||
|
'file' => __FILE__,
|
||||||
|
'line' => $line,
|
||||||
|
),
|
||||||
), $tracedMessages[0], true);
|
), $tracedMessages[0], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +76,7 @@ class TraceableMessageBusTest extends TestCase
|
|||||||
$traceableBus = new TraceableMessageBus($bus);
|
$traceableBus = new TraceableMessageBus($bus);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$line = __LINE__ + 1;
|
||||||
$traceableBus->dispatch($message);
|
$traceableBus->dispatch($message);
|
||||||
} catch (\RuntimeException $e) {
|
} catch (\RuntimeException $e) {
|
||||||
$this->assertSame($exception, $e);
|
$this->assertSame($exception, $e);
|
||||||
@ -74,6 +87,11 @@ class TraceableMessageBusTest extends TestCase
|
|||||||
'message' => $message,
|
'message' => $message,
|
||||||
'exception' => $exception,
|
'exception' => $exception,
|
||||||
'envelopeItems' => null,
|
'envelopeItems' => null,
|
||||||
|
'caller' => array(
|
||||||
|
'name' => 'TraceableMessageBusTest.php',
|
||||||
|
'file' => __FILE__,
|
||||||
|
'line' => $line,
|
||||||
|
),
|
||||||
), $tracedMessages[0], true);
|
), $tracedMessages[0], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ class TraceableMessageBus implements MessageBusInterface
|
|||||||
*/
|
*/
|
||||||
public function dispatch($message)
|
public function dispatch($message)
|
||||||
{
|
{
|
||||||
|
$caller = $this->getCaller();
|
||||||
$callTime = microtime(true);
|
$callTime = microtime(true);
|
||||||
$messageToTrace = $message instanceof Envelope ? $message->getMessage() : $message;
|
$messageToTrace = $message instanceof Envelope ? $message->getMessage() : $message;
|
||||||
$envelopeItems = $message instanceof Envelope ? array_values($message->all()) : null;
|
$envelopeItems = $message instanceof Envelope ? array_values($message->all()) : null;
|
||||||
@ -41,6 +42,7 @@ class TraceableMessageBus implements MessageBusInterface
|
|||||||
'message' => $messageToTrace,
|
'message' => $messageToTrace,
|
||||||
'result' => $result,
|
'result' => $result,
|
||||||
'callTime' => $callTime,
|
'callTime' => $callTime,
|
||||||
|
'caller' => $caller,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -50,6 +52,7 @@ class TraceableMessageBus implements MessageBusInterface
|
|||||||
'message' => $messageToTrace,
|
'message' => $messageToTrace,
|
||||||
'exception' => $e,
|
'exception' => $e,
|
||||||
'callTime' => $callTime,
|
'callTime' => $callTime,
|
||||||
|
'caller' => $caller,
|
||||||
);
|
);
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
@ -65,4 +68,40 @@ class TraceableMessageBus implements MessageBusInterface
|
|||||||
{
|
{
|
||||||
$this->dispatchedMessages = array();
|
$this->dispatchedMessages = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getCaller(): array
|
||||||
|
{
|
||||||
|
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 8);
|
||||||
|
|
||||||
|
$file = $trace[1]['file'];
|
||||||
|
$line = $trace[1]['line'];
|
||||||
|
|
||||||
|
for ($i = 2; $i < 8; ++$i) {
|
||||||
|
if (isset($trace[$i]['class'], $trace[$i]['function'])
|
||||||
|
&& 'dispatch' === $trace[$i]['function']
|
||||||
|
&& is_a($trace[$i]['class'], MessageBusInterface::class, true)
|
||||||
|
) {
|
||||||
|
$file = $trace[$i]['file'];
|
||||||
|
$line = $trace[$i]['line'];
|
||||||
|
|
||||||
|
while (++$i < 8) {
|
||||||
|
if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos(
|
||||||
|
$trace[$i]['function'],
|
||||||
|
'call_user_func'
|
||||||
|
)) {
|
||||||
|
$file = $trace[$i]['file'];
|
||||||
|
$line = $trace[$i]['line'];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = str_replace('\\', '/', $file);
|
||||||
|
$name = substr($name, strrpos($name, '/') + 1);
|
||||||
|
|
||||||
|
return compact('name', 'file', 'line');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user