TraceableMessageBus.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Messenger;
  11. /**
  12. * @author Samuel Roze <samuel.roze@gmail.com>
  13. */
  14. class TraceableMessageBus implements MessageBusInterface
  15. {
  16. private $decoratedBus;
  17. private $dispatchedMessages = [];
  18. public function __construct(MessageBusInterface $decoratedBus)
  19. {
  20. $this->decoratedBus = $decoratedBus;
  21. }
  22. /**
  23. * {@inheritdoc}
  24. */
  25. public function dispatch($message, array $stamps = []): Envelope
  26. {
  27. $envelope = Envelope::wrap($message, $stamps);
  28. $context = [
  29. 'stamps' => array_merge([], ...array_values($envelope->all())),
  30. 'message' => $envelope->getMessage(),
  31. 'caller' => $this->getCaller(),
  32. 'callTime' => microtime(true),
  33. ];
  34. try {
  35. return $envelope = $this->decoratedBus->dispatch($message, $stamps);
  36. } catch (\Throwable $e) {
  37. $context['exception'] = $e;
  38. throw $e;
  39. } finally {
  40. $this->dispatchedMessages[] = $context + ['stamps_after_dispatch' => array_merge([], ...array_values($envelope->all()))];
  41. }
  42. }
  43. public function getDispatchedMessages(): array
  44. {
  45. return $this->dispatchedMessages;
  46. }
  47. public function reset()
  48. {
  49. $this->dispatchedMessages = [];
  50. }
  51. private function getCaller(): array
  52. {
  53. $trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 8);
  54. $file = $trace[1]['file'];
  55. $line = $trace[1]['line'];
  56. $handleTraitFile = (new \ReflectionClass(HandleTrait::class))->getFileName();
  57. $found = false;
  58. for ($i = 1; $i < 8; ++$i) {
  59. if (isset($trace[$i]['file'], $trace[$i + 1]['file'], $trace[$i + 1]['line']) && $trace[$i]['file'] === $handleTraitFile) {
  60. $file = $trace[$i + 1]['file'];
  61. $line = $trace[$i + 1]['line'];
  62. $found = true;
  63. break;
  64. }
  65. }
  66. for ($i = 2; $i < 8 && !$found; ++$i) {
  67. if (isset($trace[$i]['class'], $trace[$i]['function'])
  68. && 'dispatch' === $trace[$i]['function']
  69. && is_a($trace[$i]['class'], MessageBusInterface::class, true)
  70. ) {
  71. $file = $trace[$i]['file'];
  72. $line = $trace[$i]['line'];
  73. while (++$i < 8) {
  74. if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos($trace[$i]['function'], 'call_user_func')) {
  75. $file = $trace[$i]['file'];
  76. $line = $trace[$i]['line'];
  77. break;
  78. }
  79. }
  80. break;
  81. }
  82. }
  83. $name = str_replace('\\', '/', $file);
  84. $name = substr($name, strrpos($name, '/') + 1);
  85. return compact('name', 'file', 'line');
  86. }
  87. }