- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
127 lines
3.7 KiB
PHP
127 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Metrics\Formatters;
|
|
|
|
use App\Framework\Metrics\Metric;
|
|
use App\Framework\Metrics\MetricsCollection;
|
|
use App\Framework\Metrics\MetricSuffix;
|
|
use App\Framework\Metrics\MetricType;
|
|
|
|
/**
|
|
* Formats metrics in OpenMetrics format
|
|
* OpenMetrics is a CNCF standard that extends Prometheus format
|
|
* @see https://openmetrics.io/
|
|
*/
|
|
final readonly class OpenMetricsFormatter implements MetricsFormatter
|
|
{
|
|
public function format(MetricsCollection $metrics): string
|
|
{
|
|
$output = [];
|
|
$processedMetrics = [];
|
|
|
|
foreach ($metrics->getMetrics() as $metricName => $metricGroup) {
|
|
// Skip if already processed
|
|
if (isset($processedMetrics[$metricName])) {
|
|
continue;
|
|
}
|
|
|
|
$firstMetric = $metricGroup[0];
|
|
$baseName = MetricSuffix::getBaseName($metricName);
|
|
|
|
// HELP line (required in OpenMetrics)
|
|
$help = $firstMetric->help ?? 'No description provided';
|
|
$output[] = sprintf('# HELP %s %s', $baseName, $help);
|
|
|
|
// TYPE line (required in OpenMetrics)
|
|
$type = $this->determineMetricType($metricName, $firstMetric->type);
|
|
$output[] = sprintf('# TYPE %s %s', $baseName, $type->value);
|
|
|
|
// UNIT line (OpenMetrics specific, optional)
|
|
if ($firstMetric->unit !== null) {
|
|
$output[] = sprintf('# UNIT %s %s', $baseName, $firstMetric->unit);
|
|
}
|
|
|
|
// Add metric values
|
|
foreach ($metricGroup as $metric) {
|
|
$output[] = $this->formatMetric($metric);
|
|
}
|
|
|
|
$processedMetrics[$metricName] = true;
|
|
|
|
// Mark related metrics as processed
|
|
if ($type === MetricType::HISTOGRAM) {
|
|
foreach (MetricSuffix::histogramSuffixes() as $suffix) {
|
|
$processedMetrics[$suffix->addTo($baseName)] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OpenMetrics requires EOF marker
|
|
$output[] = '# EOF';
|
|
|
|
return implode("\n", $output) . "\n";
|
|
}
|
|
|
|
private function formatMetric(Metric $metric): string
|
|
{
|
|
$labels = $metric->getFormattedLabels();
|
|
$name = $metric->name;
|
|
|
|
// OpenMetrics doesn't append unit to metric name (uses UNIT metadata instead)
|
|
|
|
$line = sprintf('%s%s %s', $name, $labels, $this->formatValue($metric->value));
|
|
|
|
// Add timestamp if present (seconds with fractional part for OpenMetrics)
|
|
if ($metric->timestamp !== null) {
|
|
$line .= ' ' . number_format($metric->timestamp->toFloat(), 3, '.', '');
|
|
}
|
|
|
|
return $line;
|
|
}
|
|
|
|
private function formatValue(float $value): string
|
|
{
|
|
// Handle special float values (OpenMetrics spec)
|
|
if (is_infinite($value)) {
|
|
return $value > 0 ? '+Inf' : '-Inf';
|
|
}
|
|
|
|
if (is_nan($value)) {
|
|
return 'NaN';
|
|
}
|
|
|
|
// Use scientific notation for very large/small numbers
|
|
if (abs($value) >= 1e10 || (abs($value) < 1e-10 && $value != 0)) {
|
|
return sprintf('%e', $value);
|
|
}
|
|
|
|
// Regular formatting
|
|
$formatted = sprintf('%.10f', $value);
|
|
$formatted = rtrim($formatted, '0');
|
|
$formatted = rtrim($formatted, '.');
|
|
|
|
return $formatted;
|
|
}
|
|
|
|
private function determineMetricType(string $name, MetricType $type): MetricType
|
|
{
|
|
if (MetricSuffix::hasHistogramSuffix($name)) {
|
|
return MetricType::HISTOGRAM;
|
|
}
|
|
|
|
return $type;
|
|
}
|
|
|
|
public function getContentType(): string
|
|
{
|
|
return 'application/openmetrics-text; version=1.0.0; charset=utf-8';
|
|
}
|
|
|
|
public function getName(): string
|
|
{
|
|
return 'openmetrics';
|
|
}
|
|
}
|