Completed
Push — master ( 496e6f...9f6541 )
by Shinji
21s queued 11s
created

DaemonCommand::outputTrace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 4
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\Settings\DaemonSettings\DaemonSettingsFromConsoleInput;
24
use PhpProfiler\Inspector\Settings\GetTraceSettings\GetTraceSettingsFromConsoleInput;
25
use PhpProfiler\Inspector\Settings\TargetPhpSettings\TargetPhpSettingsFromConsoleInput;
26
use PhpProfiler\Inspector\Settings\TraceLoopSettings\TraceLoopSettingsFromConsoleInput;
27
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...
28
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...
29
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...
30
31
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...
32
33
final class DaemonCommand extends Command
34
{
35
    private PhpSearcherContextCreator $php_searcher_context_creator;
36
    private PhpReaderContextCreator $php_reader_context_creator;
37
    private DaemonSettingsFromConsoleInput $daemon_settings_from_console_input;
38
    private GetTraceSettingsFromConsoleInput $get_trace_settings_from_console_input;
39
    private TargetPhpSettingsFromConsoleInput $target_php_settings_from_console_input;
40
    private TraceLoopSettingsFromConsoleInput $trace_loop_settings_from_console_input;
41
42
    public function __construct(
43
        PhpSearcherContextCreator $php_searcher_context_creator,
44
        PhpReaderContextCreator $php_reader_context_creator,
45
        DaemonSettingsFromConsoleInput $daemon_settings_from_console_input,
46
        GetTraceSettingsFromConsoleInput $get_trace_settings_from_console_input,
47
        TargetPhpSettingsFromConsoleInput $target_php_settings_from_console_input,
48
        TraceLoopSettingsFromConsoleInput $trace_loop_settings_from_console_input
49
    ) {
50
        $this->php_reader_context_creator = $php_reader_context_creator;
51
        $this->php_searcher_context_creator = $php_searcher_context_creator;
52
        $this->daemon_settings_from_console_input = $daemon_settings_from_console_input;
53
        $this->get_trace_settings_from_console_input = $get_trace_settings_from_console_input;
54
        $this->target_php_settings_from_console_input = $target_php_settings_from_console_input;
55
        $this->trace_loop_settings_from_console_input = $trace_loop_settings_from_console_input;
56
        parent::__construct();
57
    }
58
59
    public function configure(): void
60
    {
61
        $this->setName('inspector:daemon')
62
            ->setDescription('concurrently get call traces from processes whose command-lines match a given regex')
63
        ;
64
        $this->daemon_settings_from_console_input->setOptions($this);
65
        $this->get_trace_settings_from_console_input->setOptions($this);
66
        $this->trace_loop_settings_from_console_input->setOptions($this);
67
        $this->target_php_settings_from_console_input->setOptions($this);
68
    }
69
70
    /**
71
     * @param InputInterface $input
72
     * @param OutputInterface $output
73
     * @return int
74
     */
75
    public function execute(InputInterface $input, OutputInterface $output): int
76
    {
77
        $get_trace_settings = $this->get_trace_settings_from_console_input->createSettings($input);
78
        $daemon_settings = $this->daemon_settings_from_console_input->createSettings($input);
79
        $target_php_settings = $this->target_php_settings_from_console_input->createSettings($input);
80
        $loop_settings = $this->trace_loop_settings_from_console_input->createSettings($input);
81
82
        $searcher_context = $this->php_searcher_context_creator->create();
83
        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

83
        /** @scrutinizer ignore-call */ 
84
        Promise\wait($searcher_context->start());
Loading history...
84
        Promise\wait($searcher_context->sendTargetRegex($daemon_settings->target_regex));
85
86
        $worker_pool = WorkerPool::create(
87
            $this->php_reader_context_creator,
88
            $daemon_settings->threads,
89
            $target_php_settings,
90
            $loop_settings,
91
            $get_trace_settings
92
        );
93
94
        $dispatch_table = new DispatchTable(
95
            $worker_pool,
96
            $target_php_settings,
97
            $loop_settings,
98
            $get_trace_settings
99
        );
100
101
        exec('stty -icanon -echo');
102
103
        Loop::onReadable(
104
            STDIN,
105
            /** @param resource $stream */
106
            function (string $watcher_id, $stream) {
107
                $key = fread($stream, 1);
108
                if ($key === 'q') {
109
                    Loop::cancel($watcher_id);
110
                    Loop::stop();
111
                }
112
            }
113
        );
114
        Loop::run(function () use ($dispatch_table, $searcher_context, $worker_pool, $output) {
115
            $promises = [];
116
            $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

116
            $promises[] = /** @scrutinizer ignore-call */ call(function () use ($searcher_context, $dispatch_table) {
Loading history...
117
                while (1) {
118
                    $update_target_message = yield $searcher_context->receivePidList();
119
                    $dispatch_table->updateTargets($update_target_message->target_process_list);
120
                }
121
            });
122
            foreach ($worker_pool->getWorkers() as $reader) {
123
                $promises[] = call(
124
                    function () use ($reader, $dispatch_table, $output) {
125
                        while (1) {
126
                            $result = yield $reader->receiveTraceOrDetachWorker();
127
                            if ($result instanceof TraceMessage) {
128
                                $this->outputTrace($output, $result);
129
                            } else {
130
                                $dispatch_table->releaseOne($result->pid);
131
                            }
132
                        }
133
                    }
134
                );
135
            }
136
            yield $promises;
137
        });
138
139
        return 0;
140
    }
141
142
    private function outputTrace(OutputInterface $output, TraceMessage $message): void
143
    {
144
        $output->writeln(
145
            join(PHP_EOL, $message->trace) . PHP_EOL
146
        );
147
    }
148
}
149