Passed
Push — add-option-to-change-output ( 0c1513 )
by Shinji
03:29
created

DaemonCommand::outputTrace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
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 3
dl 0
loc 7
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\TraceOutput\TraceOutputFactory;
24
use PhpProfiler\Inspector\Settings\DaemonSettings\DaemonSettingsFromConsoleInput;
25
use PhpProfiler\Inspector\Settings\GetTraceSettings\GetTraceSettingsFromConsoleInput;
26
use PhpProfiler\Inspector\Settings\OutputSettings\OutputSettingsFromConsoleInput;
27
use PhpProfiler\Inspector\Settings\TargetPhpSettings\TargetPhpSettingsFromConsoleInput;
28
use PhpProfiler\Inspector\Settings\TraceLoopSettings\TraceLoopSettingsFromConsoleInput;
29
use PhpProfiler\Lib\Console\EchoBackCanceller;
30
use PhpProfiler\Lib\Log\Log;
31
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...
32
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...
33
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...
34
35
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...
36
use function fread;
37
38
use const STDIN;
39
40
final class DaemonCommand extends Command
41
{
42
    public function __construct(
43
        private PhpSearcherContextCreator $php_searcher_context_creator,
44
        private PhpReaderContextCreator $php_reader_context_creator,
45
        private DaemonSettingsFromConsoleInput $daemon_settings_from_console_input,
46
        private GetTraceSettingsFromConsoleInput $get_trace_settings_from_console_input,
47
        private TargetPhpSettingsFromConsoleInput $target_php_settings_from_console_input,
48
        private TraceLoopSettingsFromConsoleInput $trace_loop_settings_from_console_input,
49
        private OutputSettingsFromConsoleInput $output_settings_from_console_input,
50
        private TraceOutputFactory $trace_output_factory,
51
    ) {
52
        parent::__construct();
53
    }
54
55
    public function configure(): void
56
    {
57
        $this->setName('inspector:daemon')
58
            ->setDescription('concurrently get call traces from processes whose command-lines match a given regex')
59
        ;
60
        $this->daemon_settings_from_console_input->setOptions($this);
61
        $this->get_trace_settings_from_console_input->setOptions($this);
62
        $this->trace_loop_settings_from_console_input->setOptions($this);
63
        $this->target_php_settings_from_console_input->setOptions($this);
64
        $this->output_settings_from_console_input->setOptions($this);
65
    }
66
67
    public function execute(InputInterface $input, OutputInterface $output): int
68
    {
69
        $get_trace_settings = $this->get_trace_settings_from_console_input->createSettings($input);
70
        $daemon_settings = $this->daemon_settings_from_console_input->createSettings($input);
71
        $target_php_settings = $this->target_php_settings_from_console_input->createSettings($input);
72
        $loop_settings = $this->trace_loop_settings_from_console_input->createSettings($input);
73
        $trace_output = $this->trace_output_factory->fromSettingsAndConsoleOutput(
74
            $output,
75
            $this->output_settings_from_console_input->createSettings($input),
76
        );
77
78
        $searcher_context = $this->php_searcher_context_creator->create();
79
        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

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

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