DaemonCommand::configure()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 7
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 10
rs 10
1
<?php
2
3
/**
4
 * This file is part of the sj-i/php-profiler package.
5
 *
6
 * (c) sji <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace PhpProfiler\Command\Inspector;
15
16
use Amp\Loop;
0 ignored issues
show
Bug introduced by
The type Amp\Loop was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Amp\Promise;
0 ignored issues
show
Bug introduced by
The type Amp\Promise was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use PhpProfiler\Inspector\Daemon\Dispatcher\DispatchTable;
19
use PhpProfiler\Inspector\Daemon\Reader\Protocol\Message\TraceMessage;
20
use PhpProfiler\Inspector\Daemon\Dispatcher\WorkerPool;
21
use PhpProfiler\Inspector\Daemon\Reader\Context\PhpReaderContextCreator;
22
use PhpProfiler\Inspector\Daemon\Searcher\Context\PhpSearcherContextCreator;
23
use PhpProfiler\Inspector\Output\TraceFormatter\CallTraceFormatter;
24
use PhpProfiler\Inspector\Output\TraceFormatter\Templated\TemplatedTraceFormatterFactory;
25
use PhpProfiler\Inspector\Settings\DaemonSettings\DaemonSettingsFromConsoleInput;
26
use PhpProfiler\Inspector\Settings\GetTraceSettings\GetTraceSettingsFromConsoleInput;
27
use PhpProfiler\Inspector\Settings\TargetPhpSettings\TargetPhpSettingsFromConsoleInput;
28
use PhpProfiler\Inspector\Settings\TemplatedTraceFormatterSettings\TemplateSettingsFromConsoleInput;
29
use PhpProfiler\Inspector\Settings\TraceLoopSettings\TraceLoopSettingsFromConsoleInput;
30
use PhpProfiler\Lib\Console\EchoBackCanceller;
31
use PhpProfiler\Lib\Log\Log;
32
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
use Symfony\Component\Console\Input\InputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use Symfony\Component\Console\Output\OutputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Output\OutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
36
use function Amp\call;
0 ignored issues
show
introduced by
The function Amp\call was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
37
use function fread;
38
39
use const STDIN;
40
41
final class DaemonCommand extends Command
42
{
43
    public function __construct(
44
        private PhpSearcherContextCreator $php_searcher_context_creator,
45
        private PhpReaderContextCreator $php_reader_context_creator,
46
        private DaemonSettingsFromConsoleInput $daemon_settings_from_console_input,
47
        private GetTraceSettingsFromConsoleInput $get_trace_settings_from_console_input,
48
        private TargetPhpSettingsFromConsoleInput $target_php_settings_from_console_input,
49
        private TraceLoopSettingsFromConsoleInput $trace_loop_settings_from_console_input,
50
        private TemplateSettingsFromConsoleInput $template_settings_from_console_input,
51
        private TemplatedTraceFormatterFactory $templated_trace_formatter_factory,
52
    ) {
53
        parent::__construct();
54
    }
55
56
    public function configure(): void
57
    {
58
        $this->setName('inspector:daemon')
59
            ->setDescription('concurrently get call traces from processes whose command-lines match a given regex')
60
        ;
61
        $this->daemon_settings_from_console_input->setOptions($this);
62
        $this->get_trace_settings_from_console_input->setOptions($this);
63
        $this->trace_loop_settings_from_console_input->setOptions($this);
64
        $this->target_php_settings_from_console_input->setOptions($this);
65
        $this->template_settings_from_console_input->setOptions($this);
66
    }
67
68
    public function execute(InputInterface $input, OutputInterface $output): int
69
    {
70
        $get_trace_settings = $this->get_trace_settings_from_console_input->createSettings($input);
71
        $daemon_settings = $this->daemon_settings_from_console_input->createSettings($input);
72
        $target_php_settings = $this->target_php_settings_from_console_input->createSettings($input);
73
        $loop_settings = $this->trace_loop_settings_from_console_input->createSettings($input);
74
        $template_settings = $this->template_settings_from_console_input->createSettings($input);
75
        $formatter = $this->templated_trace_formatter_factory->createFromSettings($template_settings);
76
77
        $searcher_context = $this->php_searcher_context_creator->create();
78
        Promise\wait($searcher_context->start());
0 ignored issues
show
Bug introduced by
The function wait was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
        /** @scrutinizer ignore-call */ 
79
        Promise\wait($searcher_context->start());
Loading history...
79
        Promise\wait($searcher_context->sendTargetRegex($daemon_settings->target_regex));
80
81
        $worker_pool = WorkerPool::create(
82
            $this->php_reader_context_creator,
83
            $daemon_settings->threads,
84
            $target_php_settings,
85
            $loop_settings,
86
            $get_trace_settings
87
        );
88
89
        $dispatch_table = new DispatchTable(
90
            $worker_pool,
91
        );
92
93
        $_echo_back_canceler = new EchoBackCanceller();
0 ignored issues
show
Unused Code introduced by
The assignment to $_echo_back_canceler is dead and can be removed.
Loading history...
94
95
        Loop::onReadable(
96
            STDIN,
97
            /** @param resource $stream */
98
            function (string $watcher_id, $stream) {
99
                $key = fread($stream, 1);
100
                if ($key === 'q') {
101
                    Loop::cancel($watcher_id);
102
                    Loop::stop();
103
                }
104
            }
105
        );
106
        Loop::run(function () use ($dispatch_table, $searcher_context, $worker_pool, $output, $formatter) {
107
            $promises = [];
108
            $promises[] = call(function () use ($searcher_context, $dispatch_table) {
0 ignored issues
show
Bug introduced by
The function call was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

108
            $promises[] = /** @scrutinizer ignore-call */ call(function () use ($searcher_context, $dispatch_table) {
Loading history...
109
                while (1) {
110
                    Log::debug('receiving pid List');
111
                    $update_target_message = yield $searcher_context->receivePidList();
112
                    Log::debug('update targets', [
113
                        'update' => $update_target_message->target_process_list->getArray(),
114
                        'current' => $dispatch_table->worker_pool->debugDump(),
115
                    ]);
116
                    $dispatch_table->updateTargets($update_target_message->target_process_list);
117
                    Log::debug('target updated', [$dispatch_table->worker_pool->debugDump()]);
118
                }
119
            });
120
            foreach ($worker_pool->getWorkers() as $reader) {
121
                $promises[] = call(
122
                    function () use ($reader, $dispatch_table, $output, $formatter) {
123
                        while (1) {
124
                            $result = yield $reader->receiveTraceOrDetachWorker();
125
                            if ($result instanceof TraceMessage) {
126
                                $this->outputTrace($output, $formatter, $result);
127
                            } else {
128
                                Log::debug('releaseOne', [$result]);
129
                                $dispatch_table->releaseOne($result->pid);
130
                            }
131
                        }
132
                    }
133
                );
134
            }
135
            yield $promises;
136
        });
137
138
        return 0;
139
    }
140
141
    private function outputTrace(
142
        OutputInterface $output,
143
        CallTraceFormatter $formatter,
144
        TraceMessage $message
145
    ): void {
146
        $output->write(
147
            $formatter->format($message->trace)
148
        );
149
    }
150
}
151