<?phpdeclare(strict_types=1);namespace Sentry\SentryBundle\EventListener;use Sentry\State\HubInterface;use Sentry\Tracing\Span;use Sentry\Tracing\SpanContext;use Sentry\Tracing\Transaction;use Sentry\Tracing\TransactionContext;use Sentry\Tracing\TransactionSource;use Symfony\Component\Console\Command\Command;use Symfony\Component\Console\Event\ConsoleCommandEvent;use Symfony\Component\Console\Event\ConsoleTerminateEvent;/** * This listener either starts a {@see Transaction} or a child {@see Span} when * a console command is executed to allow measuring the application performances. */final class TracingConsoleListener{    /**     * @var HubInterface The current hub     */    private $hub;    /**     * @var string[] The list of commands for which distributed tracing must be skipped     */    private $excludedCommands;    /**     * Constructor.     *     * @param HubInterface $hub              The current hub     * @param string[]     $excludedCommands The list of commands for which distributed tracing must be skipped     */    public function __construct(HubInterface $hub, array $excludedCommands = [])    {        $this->hub = $hub;        $this->excludedCommands = $excludedCommands;    }    /**     * Handles the execution of a console command by starting a new {@see Transaction}     * if it doesn't exists, or a child {@see Span} if it does.     *     * @param ConsoleCommandEvent $event The event     */    public function handleConsoleCommandEvent(ConsoleCommandEvent $event): void    {        $command = $event->getCommand();        if ($this->isCommandExcluded($command)) {            return;        }        $currentSpan = $this->hub->getSpan();        if (null === $currentSpan) {            $transactionContext = new TransactionContext();            $transactionContext->setOp('console.command');            $transactionContext->setName($this->getSpanName($command));            $transactionContext->setSource(TransactionSource::task());            $span = $this->hub->startTransaction($transactionContext);        } else {            $spanContext = new SpanContext();            $spanContext->setOp('console.command');            $spanContext->setDescription($this->getSpanName($command));            $span = $currentSpan->startChild($spanContext);        }        $this->hub->setSpan($span);    }    /**     * Handles the termination of a console command by stopping the active {@see Span}     * or {@see Transaction}.     *     * @param ConsoleTerminateEvent $event The event     */    public function handleConsoleTerminateEvent(ConsoleTerminateEvent $event): void    {        if ($this->isCommandExcluded($event->getCommand())) {            return;        }        $span = $this->hub->getSpan();        if (null !== $span) {            $span->finish();        }    }    private function getSpanName(?Command $command): string    {        if (null === $command || null === $command->getName()) {            return '<unnamed command>';        }        return $command->getName();    }    private function isCommandExcluded(?Command $command): bool    {        if (null === $command) {            return true;        }        return \in_array($command->getName(), $this->excludedCommands, true);    }}