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'; } }