Sanitise values before sending to CloudWatch (#17)

Throw away data points with known invalid values
to avoid the whole batch being rejected by CloudWatch API.

Signed-off-by: Sergei Ivanov <sergei_ivanov@mail.ru>
This commit is contained in:
Sergei Ivanov 2019-06-25 03:34:34 +01:00 committed by Andriy Knysh
parent 3aaeeb6523
commit 5ae48bd09a
3 changed files with 42 additions and 6 deletions

View File

@ -134,8 +134,8 @@ docker run -i --rm \
-e CERT_PATH="" \
-e KEY_PATH="" \
-e ACCEPT_INVALID_CERT=true \
-e INCLUDE_METRICS='' \
-e EXCLUDE_METRICS='' \
-e INCLUDE_METRICS="" \
-e EXCLUDE_METRICS="" \
prometheus-to-cloudwatch
```

View File

@ -124,8 +124,8 @@ examples: |-
-e CERT_PATH="" \
-e KEY_PATH="" \
-e ACCEPT_INVALID_CERT=true \
-e INCLUDE_METRICS='' \
-e EXCLUDE_METRICS='' \
-e INCLUDE_METRICS="" \
-e EXCLUDE_METRICS="" \
prometheus-to-cloudwatch
```

View File

@ -16,6 +16,7 @@ import (
"github.com/prometheus/common/model"
"io"
"log"
"math"
"mime"
"net/http"
"sort"
@ -253,11 +254,17 @@ func appendDatum(data []*cloudwatch.MetricDatum, name string, s *model.Sample, b
return data
}
// Check value before adding the datum
value := float64(s.Value)
if !validValue(value) {
return data
}
datum := &cloudwatch.MetricDatum{}
kubeStateDimensions, replacedDimensions := getDimensions(metric, 10-len(b.additionalDimensions), b)
datum.SetMetricName(name).
SetValue(float64(s.Value)).
SetValue(value).
SetTimestamp(s.Timestamp.Time()).
SetDimensions(append(kubeStateDimensions, getAdditionalDimensions(b)...)).
SetStorageResolution(getResolution(metric)).
@ -268,7 +275,7 @@ func appendDatum(data []*cloudwatch.MetricDatum, name string, s *model.Sample, b
if replacedDimensions != nil && len(replacedDimensions) > 0 {
replacedDimensionDatum := &cloudwatch.MetricDatum{}
replacedDimensionDatum.SetMetricName(name).
SetValue(float64(s.Value)).
SetValue(value).
SetTimestamp(s.Timestamp.Time()).
SetDimensions(append(replacedDimensions, getAdditionalDimensions(b)...)).
SetStorageResolution(getResolution(metric)).
@ -279,6 +286,35 @@ func appendDatum(data []*cloudwatch.MetricDatum, name string, s *model.Sample, b
return data
}
var (
valueTooSmall = math.Pow(2, -260)
valueTooLarge = math.Pow(2, 260)
)
// According to the documentation:
// "CloudWatch rejects values that are either too small or too large.
// Values must be in the range of 8.515920e-109 to 1.174271e+108 (Base 10)
// or 2e-360 to 2e360 (Base 2).
// In addition, special values (for example, NaN, +Infinity, -Infinity) are not supported."
func validValue(v float64) bool {
if math.IsInf(v, 0) {
return false
}
if math.IsNaN(v) {
return false
}
// Check for zero first to avoid tripping on "value too small"
if v == 0.0 {
return true
}
// Check that a non-zero value is within the range of accepted values
a := math.Abs(v)
if a <= valueTooSmall || a >= valueTooLarge {
return false
}
return true
}
func getName(m model.Metric) string {
if n, ok := m[model.MetricNameLabel]; ok {
return string(n)