diff --git a/library/Perfdatagraphsprometheus/Client/Prometheus.php b/library/Perfdatagraphsprometheus/Client/Prometheus.php index 034b85f..57bc2d4 100644 --- a/library/Perfdatagraphsprometheus/Client/Prometheus.php +++ b/library/Perfdatagraphsprometheus/Client/Prometheus.php @@ -115,14 +115,19 @@ protected function getAuth(): array } /** - * calculateSteps uses the start and end timestamps to calculate the step parameter + * calculateSteps uses the start and end timestamps to calculate the step parameter. + * + * The step is never smaller than $checkInterval to avoid repeated identical + * values caused by Prometheus gap-filling within the lookback window. */ - protected function calculateSteps(int $start, int $end, int $maxDataPoints): string + protected function calculateSteps(int $start, int $end, int $maxDataPoints, int $checkInterval = 0): string { $totalSeconds = $end - $start; $stepSeconds = $totalSeconds / $maxDataPoints; - // NOTE: This means we can never get a resolution below 60s, even if Icinga2 would send data every 15s - $stepSeconds = max($stepSeconds, 60); + // Use the check interval as the minimum step so we don't over-sample. + // Fall back to 1s when no check interval is available. + $minStep = $checkInterval > 0 ? $checkInterval : 1; + $stepSeconds = max($stepSeconds, $minStep); return (int)round($stepSeconds) . 's'; } @@ -134,7 +139,8 @@ public function getMetrics( string $from, bool $isHostCheck, array $includeMetrics, - array $excludeMetrics + array $excludeMetrics, + int $checkInterval = 0 ): Response { $endTime = new DateTimeImmutable(); $startTime = $endTime->sub(new DateInterval($from)); @@ -145,7 +151,7 @@ public function getMetrics( $start = $startTime->getTimestamp(); $end = $endTime->getTimestamp(); - $step = $this->calculateSteps($start, $end, $this->maxDataPoints); + $step = $this->calculateSteps($start, $end, $this->maxDataPoints, $checkInterval); $query = [ 'query' => [ diff --git a/library/Perfdatagraphsprometheus/Client/Transformer.php b/library/Perfdatagraphsprometheus/Client/Transformer.php index 45933b0..e003e8f 100644 --- a/library/Perfdatagraphsprometheus/Client/Transformer.php +++ b/library/Perfdatagraphsprometheus/Client/Transformer.php @@ -46,8 +46,8 @@ protected static function preparePerfdataResponse(array $results, PerfdataRespon $timestamps = []; foreach ($result['values'] as $point) { - $timestamps[] = $point[0]; - $values[] = $point[1]; + $timestamps[] = (int) $point[0]; + $values[] = is_numeric($point[1]) ? (float) $point[1] : null; } $valuesSeries = new PerfdataSeries('value', $values); @@ -95,11 +95,15 @@ protected static function appendThresholds(array $results, PerfdataResponse $pfr } $ts = $dataset->getTimestamps(); - $valueMap = array_column($result['values'], 1, 0); - // Get the matching threshold value for the given timestamp otherwise use null + // Build a map of timestamp (int) => float value for fast lookup. + $valueMap = []; + foreach ($result['values'] as $point) { + $valueMap[(int) $point[0]] = is_numeric($point[1]) ? (float) $point[1] : null; + } + // Align threshold values to the stored timestamps; use null for gaps. $thresholds = []; foreach ($ts as $timestamp) { - $thresholds[] = $valueMap[$timestamp] ?? null; + $thresholds[] = $valueMap[(int) $timestamp] ?? null; } $thresholdSeries = new PerfdataSeries($thresholdType, $thresholds); diff --git a/library/Perfdatagraphsprometheus/ProvidedHook/Perfdatagraphs/PerfdataSource.php b/library/Perfdatagraphsprometheus/ProvidedHook/Perfdatagraphs/PerfdataSource.php index 45a1fa3..686e247 100644 --- a/library/Perfdatagraphsprometheus/ProvidedHook/Perfdatagraphs/PerfdataSource.php +++ b/library/Perfdatagraphsprometheus/ProvidedHook/Perfdatagraphs/PerfdataSource.php @@ -45,7 +45,8 @@ public function fetchData(PerfdataRequest $req): PerfdataResponse $req->getDuration(), $req->isHostCheck(), $req->getIncludeMetrics(), - $req->getExcludeMetrics() + $req->getExcludeMetrics(), + $req->getCheckInterval() ); } catch (ConnectException $e) { $perfdataresponse->addError($e->getMessage());