[Messenger][Profiler] Show dispatch caller

This commit is contained in:
Maxime Steinhausser 2018-05-22 19:48:15 +02:00 committed by Maxime Steinhausser
parent 7fb7cf26ad
commit 1c2f43f17c
6 changed files with 125 additions and 8 deletions

View File

@ -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>

View File

@ -913,6 +913,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 {

View File

@ -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)) {

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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');
}
} }