-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: suppress metrics for unreachable devices instead reporting NaN
- Loading branch information
Showing
4 changed files
with
108 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...rter/src/main/kotlin/click/dobel/tado/exporter/metrics/ValueFilteringCollectorRegistry.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package click.dobel.tado.exporter.metrics | ||
|
||
import io.prometheus.client.Collector.MetricFamilySamples | ||
import io.prometheus.client.CollectorRegistry | ||
import io.prometheus.client.Predicate | ||
import java.util.Enumeration | ||
|
||
class ValueFilteringCollectorRegistry( | ||
private val blockedValue: Double, | ||
autoDescribe: Boolean = false, | ||
) : CollectorRegistry(autoDescribe) { | ||
|
||
private val blockNaNs = blockedValue.isNaN() | ||
private val blockInfinite = blockedValue.isInfinite() | ||
internal val isValid: (Double) -> Boolean = { | ||
// special cases for NaN and Infinity: can't be compared using equality. | ||
!(blockInfinite && it.isInfinite()) && | ||
!(blockNaNs && it.isNaN()) && | ||
(blockedValue != it) | ||
} | ||
|
||
override fun metricFamilySamples(): Enumeration<MetricFamilySamples> { | ||
return super.metricFamilySamples().filterValidValues() | ||
} | ||
|
||
override fun filteredMetricFamilySamples(includedNames: MutableSet<String>?): Enumeration<MetricFamilySamples> { | ||
return super.filteredMetricFamilySamples(includedNames).filterValidValues() | ||
} | ||
|
||
override fun filteredMetricFamilySamples(sampleNameFilter: Predicate<String>?): Enumeration<MetricFamilySamples> { | ||
return super.filteredMetricFamilySamples(sampleNameFilter).filterValidValues() | ||
} | ||
|
||
private fun Enumeration<MetricFamilySamples>.filterValidValues(): Enumeration<MetricFamilySamples> { | ||
val iterator = asSequence() | ||
.map { MetricFamilySamples(it.name, it.unit, it.type, it.help, it.samples.filterValid()) } | ||
.filterNonEmpty() | ||
.iterator() | ||
|
||
return object : Enumeration<MetricFamilySamples> { | ||
override fun hasMoreElements(): Boolean { | ||
return iterator.hasNext() | ||
} | ||
|
||
override fun nextElement(): MetricFamilySamples { | ||
return iterator.next() | ||
} | ||
} | ||
} | ||
|
||
private fun Sequence<MetricFamilySamples>.filterNonEmpty(): Sequence<MetricFamilySamples> { | ||
return this.filter { | ||
it.samples.isNotEmpty() | ||
} | ||
} | ||
|
||
private fun List<MetricFamilySamples.Sample>.filterValid(): List<MetricFamilySamples.Sample> { | ||
return this.filter { | ||
isValid(it.value) | ||
} | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
.../src/test/kotlin/click/dobel/tado/exporter/metrics/ValueFilteringCollectorRegistryTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package click.dobel.tado.exporter.metrics | ||
|
||
import io.kotest.core.spec.style.FreeSpec | ||
import io.kotest.matchers.shouldBe | ||
|
||
class ValueFilteringCollectorRegistryTest : FreeSpec({ | ||
|
||
"ValueFilteringCollectorRegistry" - { | ||
|
||
"configured with NaN as invalid value" - { | ||
val registry = ValueFilteringCollectorRegistry(Double.NaN) | ||
|
||
"should not accept NaN" { registry.isValid(Double.NaN) shouldBe false } | ||
"should accept 0.0" { registry.isValid(0.0) shouldBe true } | ||
"should accept 5.0" { registry.isValid(5.0) shouldBe true } | ||
"should accept Infinity" { registry.isValid(Double.POSITIVE_INFINITY) shouldBe true } | ||
"should accept -Infinity" { registry.isValid(Double.NEGATIVE_INFINITY) shouldBe true } | ||
} | ||
|
||
"configured with 0.0 as invalid value" - { | ||
val registry = ValueFilteringCollectorRegistry(0.0) | ||
|
||
"should not accept 0.0" { registry.isValid(0.0) shouldBe false } | ||
"should accept 5.0" { registry.isValid(5.0) shouldBe true } | ||
"should accept NaN" { registry.isValid(Double.NaN) shouldBe true } | ||
"should accept Infinity" { registry.isValid(Double.POSITIVE_INFINITY) shouldBe true } | ||
"should accept -Infinity" { registry.isValid(Double.NEGATIVE_INFINITY) shouldBe true } | ||
} | ||
"configured with Infinity as invalid value" - { | ||
val registry = ValueFilteringCollectorRegistry(Double.NEGATIVE_INFINITY) | ||
|
||
"should not accept Infinity" { registry.isValid(Double.POSITIVE_INFINITY) shouldBe false } | ||
"should not accept -Infinity" { registry.isValid(Double.NEGATIVE_INFINITY) shouldBe false } | ||
"should accept 0.0" { registry.isValid(0.0) shouldBe true } | ||
"should accept 5.0" { registry.isValid(5.0) shouldBe true } | ||
"should accept NaN" { registry.isValid(Double.NaN) shouldBe true } | ||
} | ||
} | ||
}) |