Skip to content

Commit 5ddedfc

Browse files
Switch to Observability Pipeline endpoints for querying metrics (#1536)
* Switch to new endpoint for querying metrics * Address lint reports
1 parent 0c12e0c commit 5ddedfc

15 files changed

+681
-736
lines changed

src/Command/Metrics/AllMetricsCommand.php

Lines changed: 140 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44

55
namespace Platformsh\Cli\Command\Metrics;
66

7+
use Platformsh\Cli\Model\Metrics\Aggregation;
8+
use Platformsh\Cli\Model\Metrics\Field;
9+
use Platformsh\Cli\Model\Metrics\Format;
10+
use Platformsh\Cli\Model\Metrics\MetricKind;
11+
use Platformsh\Cli\Model\Metrics\SourceField;
12+
use Platformsh\Cli\Model\Metrics\SourceFieldPercentage;
713
use Platformsh\Cli\Selector\SelectorConfig;
814
use Platformsh\Cli\Selector\Selector;
915
use Khill\Duration\Duration;
10-
use Platformsh\Cli\Model\Metrics\Field;
1116
use Platformsh\Cli\Service\PropertyFormatter;
1217
use Platformsh\Cli\Service\Table;
1318
use Symfony\Component\Console\Attribute\AsCommand;
@@ -19,7 +24,7 @@
1924
class AllMetricsCommand extends MetricsCommandBase
2025
{
2126
/** @var array<string, string> */
22-
private array $tableHeader = [
27+
private const TABLE_HEADER = [
2328
'timestamp' => 'Timestamp',
2429
'service' => 'Service',
2530
'type' => 'Type',
@@ -50,91 +55,167 @@ class AllMetricsCommand extends MetricsCommandBase
5055
];
5156

5257
/** @var string[] */
53-
private array $defaultColumns = ['timestamp', 'service', 'cpu_percent', 'mem_percent', 'disk_percent', 'tmp_disk_percent'];
54-
public function __construct(private readonly PropertyFormatter $propertyFormatter, private readonly Selector $selector, private readonly Table $table)
55-
{
56-
parent::__construct();
58+
private array $defaultColumns = [
59+
'timestamp',
60+
'service',
61+
62+
'cpu_percent',
63+
'mem_percent',
64+
'disk_percent',
65+
'inodes_percent',
66+
67+
'tmp_disk_percent',
68+
'tmp_inodes_percent',
69+
];
70+
71+
public function __construct(
72+
private readonly PropertyFormatter $propertyFormatter,
73+
Selector $selector,
74+
Table $table
75+
) {
76+
parent::__construct($selector, $table);
5777
}
5878

5979
protected function configure(): void
6080
{
6181
$this->addOption('bytes', 'B', InputOption::VALUE_NONE, 'Show sizes in bytes');
6282
$this->addExample('Show metrics for the last ' . (new Duration())->humanize(self::DEFAULT_RANGE));
63-
$this->addExample('Show metrics in five-minute intervals over the last hour', '-i 5m -r 1h');
83+
$this->addExample('Show metrics over the last hour', ' -r 1h');
6484
$this->addExample('Show metrics for all SQL services', '--type mariadb,%sql');
6585
$this->addMetricsOptions();
6686
$this->selector->addProjectOption($this->getDefinition());
6787
$this->selector->addEnvironmentOption($this->getDefinition());
6888
$this->addCompleter($this->selector);
69-
Table::configureInput($this->getDefinition(), $this->tableHeader, $this->defaultColumns);
89+
Table::configureInput($this->getDefinition(), self::TABLE_HEADER, $this->defaultColumns);
7090
PropertyFormatter::configureInput($this->getDefinition());
7191
}
7292

73-
/**
74-
* {@inheritdoc}
75-
*/
76-
protected function execute(InputInterface $input, OutputInterface $output): int
93+
protected function getChooseEnvFilter(): ?callable
7794
{
78-
$timeSpec = $this->validateTimeInput($input);
79-
if ($timeSpec === false) {
80-
return 1;
81-
}
82-
83-
$selection = $this->selector->getSelection($input, new SelectorConfig(selectDefaultEnv: true, chooseEnvFilter: SelectorConfig::filterEnvsMaybeActive()));
84-
85-
if (!$this->table->formatIsMachineReadable()) {
86-
$this->selector->ensurePrintedSelection($selection);
87-
}
95+
return SelectorConfig::filterEnvsMaybeActive();
96+
}
8897

89-
// Only request the metrics fields that will be displayed.
90-
//
91-
// The fields are the selected column names (according to the $table
92-
// service), filtered to only those that contain an underscore.
93-
$fieldNames = array_filter($this->table->columnsToDisplay($this->tableHeader, $this->defaultColumns), fn($c): bool => str_contains((string) $c, '_'));
94-
$values = $this->fetchMetrics($input, $timeSpec, $selection->getEnvironment(), $fieldNames);
95-
if ($values === false) {
96-
return 1;
97-
}
98+
protected function execute(InputInterface $input, OutputInterface $output): int
99+
{
100+
[$values, $environment] = $this->processQuery($input, [
101+
MetricKind::API_TYPE_CPU,
102+
MetricKind::API_TYPE_DISK,
103+
MetricKind::API_TYPE_MEMORY,
104+
MetricKind::API_TYPE_INODES,
105+
], [MetricKind::API_AGG_AVG]);
98106

99107
$bytes = $input->getOption('bytes');
100108

101109
$rows = $this->buildRows($values, [
102-
'cpu_used' => new Field('cpu_used', Field::FORMAT_ROUNDED_2DP),
103-
'cpu_limit' => new Field('cpu_limit', Field::FORMAT_ROUNDED_2DP),
104-
'cpu_percent' => new Field('cpu_percent', Field::FORMAT_PERCENT),
105-
106-
'mem_used' => new Field('mem_used', $bytes ? Field::FORMAT_ROUNDED : Field::FORMAT_MEMORY),
107-
'mem_limit' => new Field('mem_limit', $bytes ? Field::FORMAT_ROUNDED : Field::FORMAT_MEMORY),
108-
'mem_percent' => new Field('mem_percent', Field::FORMAT_PERCENT),
109-
110-
'disk_used' => new Field('disk_used', $bytes ? Field::FORMAT_ROUNDED : Field::FORMAT_DISK),
111-
'disk_limit' => new Field('disk_limit', $bytes ? Field::FORMAT_ROUNDED : Field::FORMAT_DISK),
112-
'disk_percent' => new Field('disk_percent', Field::FORMAT_PERCENT),
113-
114-
'tmp_disk_used' => new Field('tmp_disk_used', $bytes ? Field::FORMAT_ROUNDED : Field::FORMAT_DISK),
115-
'tmp_disk_limit' => new Field('tmp_disk_limit', $bytes ? Field::FORMAT_ROUNDED : Field::FORMAT_DISK),
116-
'tmp_disk_percent' => new Field('tmp_disk_percent', Field::FORMAT_PERCENT),
117-
118-
'inodes_used' => new Field('inodes_used', Field::FORMAT_ROUNDED),
119-
'inodes_limit' => new Field('inodes_used', Field::FORMAT_ROUNDED),
120-
'inodes_percent' => new Field('inodes_percent', Field::FORMAT_PERCENT),
121-
122-
'tmp_inodes_used' => new Field('tmp_inodes_used', Field::FORMAT_ROUNDED),
123-
'tmp_inodes_limit' => new Field('tmp_inodes_used', Field::FORMAT_ROUNDED),
124-
'tmp_inodes_percent' => new Field('tmp_inodes_percent', Field::FORMAT_PERCENT),
125-
], $selection->getEnvironment());
110+
'cpu_used' => new Field(
111+
Format::Rounded2p,
112+
new SourceField(MetricKind::CpuUsed, Aggregation::Avg),
113+
),
114+
'cpu_limit' => new Field(
115+
Format::Rounded2p,
116+
new SourceField(MetricKind::CpuLimit, Aggregation::Max),
117+
),
118+
'cpu_percent' => new Field(
119+
Format::Percent,
120+
new SourceFieldPercentage(
121+
new SourceField(MetricKind::CpuUsed, Aggregation::Avg),
122+
new SourceField(MetricKind::CpuLimit, Aggregation::Max)
123+
),
124+
),
125+
126+
'mem_used' => new Field(
127+
$bytes ? Format::Rounded : Format::Memory,
128+
new SourceField(MetricKind::MemoryUsed, Aggregation::Avg),
129+
),
130+
'mem_limit' => new Field(
131+
$bytes ? Format::Rounded : Format::Memory,
132+
new SourceField(MetricKind::MemoryLimit, Aggregation::Max),
133+
),
134+
'mem_percent' => new Field(
135+
Format::Percent,
136+
new SourceFieldPercentage(
137+
new SourceField(MetricKind::MemoryUsed, Aggregation::Avg),
138+
new SourceField(MetricKind::MemoryLimit, Aggregation::Max)
139+
),
140+
false,
141+
),
142+
143+
'disk_used' => new Field(
144+
$bytes ? Format::Rounded : Format::Disk,
145+
new SourceField(MetricKind::DiskUsed, Aggregation::Avg, '/mnt'),
146+
),
147+
'disk_limit' => new Field(
148+
$bytes ? Format::Rounded : Format::Disk,
149+
new SourceField(MetricKind::DiskLimit, Aggregation::Max, '/mnt'),
150+
),
151+
'disk_percent' => new Field(
152+
Format::Percent,
153+
new SourceFieldPercentage(
154+
new SourceField(MetricKind::DiskUsed, Aggregation::Avg, '/mnt'),
155+
new SourceField(MetricKind::DiskLimit, Aggregation::Max, '/mnt')
156+
),
157+
),
158+
159+
'tmp_disk_used' => new Field(
160+
$bytes ? Format::Rounded : Format::Disk,
161+
new SourceField(MetricKind::DiskUsed, Aggregation::Avg, '/tmp'),
162+
),
163+
'tmp_disk_limit' => new Field(
164+
$bytes ? Format::Rounded : Format::Disk,
165+
new SourceField(MetricKind::DiskLimit, Aggregation::Max, '/tmp'),
166+
),
167+
'tmp_disk_percent' => new Field(
168+
Format::Percent,
169+
new SourceFieldPercentage(
170+
new SourceField(MetricKind::DiskUsed, Aggregation::Avg, '/tmp'),
171+
new SourceField(MetricKind::DiskLimit, Aggregation::Max, '/tmp')
172+
),
173+
),
174+
175+
'inodes_used' => new Field(
176+
Format::Rounded,
177+
new SourceField(MetricKind::InodesUsed, Aggregation::Avg, '/mnt'),
178+
),
179+
'inodes_limit' => new Field(
180+
Format::Rounded,
181+
new SourceField(MetricKind::InodesLimit, Aggregation::Max, '/mnt'),
182+
),
183+
'inodes_percent' => new Field(
184+
Format::Percent,
185+
new SourceFieldPercentage(
186+
new SourceField(MetricKind::InodesUsed, Aggregation::Avg, '/mnt'),
187+
new SourceField(MetricKind::InodesLimit, Aggregation::Max, '/mnt')
188+
),
189+
),
190+
191+
'tmp_inodes_used' => new Field(
192+
Format::Rounded,
193+
new SourceField(MetricKind::InodesUsed, Aggregation::Avg, '/tmp'),
194+
),
195+
'tmp_inodes_limit' => new Field(
196+
Format::Rounded,
197+
new SourceField(MetricKind::InodesLimit, Aggregation::Max, '/tmp'),
198+
),
199+
'tmp_inodes_percent' => new Field(
200+
Format::Percent,
201+
new SourceFieldPercentage(
202+
new SourceField(MetricKind::InodesUsed, Aggregation::Avg, '/tmp'),
203+
new SourceField(MetricKind::InodesLimit, Aggregation::Max, '/tmp')
204+
),
205+
),
206+
], $environment);
126207

127208
if (!$this->table->formatIsMachineReadable()) {
128209
$formatter = $this->propertyFormatter;
129210
$this->stdErr->writeln(\sprintf(
130211
'Metrics at <info>%s</info> intervals from <info>%s</info> to <info>%s</info>:',
131-
(new Duration())->humanize($timeSpec->getInterval()),
132-
$formatter->formatDate($timeSpec->getStartTime()),
133-
$formatter->formatDate($timeSpec->getEndTime()),
212+
(new Duration())->humanize($values['_grain']),
213+
$formatter->formatDate($values['_from']),
214+
$formatter->formatDate($values['_to']),
134215
));
135216
}
136217

137-
$this->table->render($rows, $this->tableHeader, $this->defaultColumns);
218+
$this->table->render($rows, self::TABLE_HEADER, $this->defaultColumns);
138219

139220
if (!$this->table->formatIsMachineReadable()) {
140221
$this->explainHighMemoryServices();

src/Command/Metrics/CpuCommand.php

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55
namespace Platformsh\Cli\Command\Metrics;
66

7-
use Platformsh\Cli\Selector\SelectorConfig;
7+
use Platformsh\Cli\Model\Metrics\Aggregation;
8+
use Platformsh\Cli\Model\Metrics\Field;
9+
use Platformsh\Cli\Model\Metrics\Format;
10+
use Platformsh\Cli\Model\Metrics\MetricKind;
11+
use Platformsh\Cli\Model\Metrics\SourceField;
12+
use Platformsh\Cli\Model\Metrics\SourceFieldPercentage;
813
use Platformsh\Cli\Selector\Selector;
914
use Khill\Duration\Duration;
10-
use Platformsh\Cli\Model\Metrics\Field;
1115
use Platformsh\Cli\Service\PropertyFormatter;
1216
use Platformsh\Cli\Service\Table;
1317
use Symfony\Component\Console\Attribute\AsCommand;
@@ -18,7 +22,7 @@
1822
class CpuCommand extends MetricsCommandBase
1923
{
2024
/** @var array<string, string> */
21-
private array $tableHeader = [
25+
private const TABLE_HEADER = [
2226
'timestamp' => 'Timestamp',
2327
'service' => 'Service',
2428
'type' => 'Type',
@@ -29,9 +33,13 @@ class CpuCommand extends MetricsCommandBase
2933

3034
/** @var string[] */
3135
private array $defaultColumns = ['timestamp', 'service', 'used', 'limit', 'percent'];
32-
public function __construct(private readonly PropertyFormatter $propertyFormatter, private readonly Selector $selector, private readonly Table $table)
33-
{
34-
parent::__construct();
36+
37+
public function __construct(
38+
private readonly PropertyFormatter $propertyFormatter,
39+
Selector $selector,
40+
Table $table
41+
) {
42+
parent::__construct($selector, $table);
3543
}
3644

3745
protected function configure(): void
@@ -40,48 +48,43 @@ protected function configure(): void
4048
$this->selector->addProjectOption($this->getDefinition());
4149
$this->selector->addEnvironmentOption($this->getDefinition());
4250
$this->addCompleter($this->selector);
43-
Table::configureInput($this->getDefinition(), $this->tableHeader, $this->defaultColumns);
51+
Table::configureInput($this->getDefinition(), self::TABLE_HEADER, $this->defaultColumns);
4452
PropertyFormatter::configureInput($this->getDefinition());
4553
}
4654

47-
/**
48-
* {@inheritdoc}
49-
*/
5055
protected function execute(InputInterface $input, OutputInterface $output): int
5156
{
52-
$timeSpec = $this->validateTimeInput($input);
53-
if ($timeSpec === false) {
54-
return 1;
55-
}
56-
57-
$selection = $this->selector->getSelection($input, new SelectorConfig(selectDefaultEnv: true));
58-
59-
if (!$this->table->formatIsMachineReadable()) {
60-
$this->selector->ensurePrintedSelection($selection);
61-
}
62-
63-
$values = $this->fetchMetrics($input, $timeSpec, $selection->getEnvironment(), ['cpu_used', 'cpu_percent', 'cpu_limit']);
64-
if ($values === false) {
65-
return 1;
66-
}
57+
[$values, $environment] = $this->processQuery($input, [MetricKind::API_TYPE_CPU], [MetricKind::API_AGG_AVG]);
6758

6859
$rows = $this->buildRows($values, [
69-
'used' => new Field('cpu_used', Field::FORMAT_ROUNDED_2DP),
70-
'limit' => new Field('cpu_limit', Field::FORMAT_ROUNDED_2DP),
71-
'percent' => new Field('cpu_percent', Field::FORMAT_PERCENT),
72-
], $selection->getEnvironment());
60+
'used' => new Field(
61+
Format::Rounded2p,
62+
new SourceField(MetricKind::CpuUsed, Aggregation::Avg),
63+
),
64+
'limit' => new Field(
65+
Format::Rounded2p,
66+
new SourceField(MetricKind::CpuLimit, Aggregation::Max),
67+
),
68+
'percent' => new Field(
69+
Format::Percent,
70+
new SourceFieldPercentage(
71+
new SourceField(MetricKind::CpuUsed, Aggregation::Avg),
72+
new SourceField(MetricKind::CpuLimit, Aggregation::Max)
73+
),
74+
),
75+
], $environment);
7376

7477
if (!$this->table->formatIsMachineReadable()) {
7578
$formatter = $this->propertyFormatter;
7679
$this->stdErr->writeln(\sprintf(
7780
'Average CPU usage at <info>%s</info> intervals from <info>%s</info> to <info>%s</info>:',
78-
(new Duration())->humanize($timeSpec->getInterval()),
79-
$formatter->formatDate($timeSpec->getStartTime()),
80-
$formatter->formatDate($timeSpec->getEndTime()),
81+
(new Duration())->humanize($values['_grain']),
82+
$formatter->formatDate($values['_from']),
83+
$formatter->formatDate($values['_to']),
8184
));
8285
}
8386

84-
$this->table->render($rows, $this->tableHeader, $this->defaultColumns);
87+
$this->table->render($rows, self::TABLE_HEADER, $this->defaultColumns);
8588

8689
return 0;
8790
}

0 commit comments

Comments
 (0)