Send metrics in ascending time order in stackdriver output (#5385)

This commit is contained in:
Daniel Nelson
2019-02-06 14:17:51 -08:00
committed by GitHub
parent e65ab593b5
commit 7f54ae18b5
3 changed files with 175 additions and 8 deletions

View File

@@ -5,6 +5,8 @@ import (
"fmt"
"log"
"path"
"sort"
"strings"
monitoring "cloud.google.com/go/monitoring/apiv3" // Imports the Stackdriver Monitoring client package.
googlepb "github.com/golang/protobuf/ptypes/timestamp"
@@ -38,6 +40,10 @@ const (
StartTime = int64(1)
// MaxInt is the max int64 value.
MaxInt = int(^uint(0) >> 1)
errStringPointsOutOfOrder = "One or more of the points specified had an older end time than the most recent point"
errStringPointsTooOld = "Data points cannot be written more than 24h in the past"
errStringPointsTooFrequent = "One or more points were written more frequently than the maximum sampling period configured for the metric"
)
var sampleConfig = `
@@ -70,17 +76,33 @@ func (s *Stackdriver) Connect() error {
return nil
}
// Sorted returns a copy of the metrics in time ascending order. A copy is
// made to avoid modifying the input metric slice since doing so is not
// allowed.
func sorted(metrics []telegraf.Metric) []telegraf.Metric {
batch := make([]telegraf.Metric, 0, len(metrics))
for i := len(metrics) - 1; i >= 0; i-- {
batch = append(batch, metrics[i])
}
sort.Slice(batch, func(i, j int) bool {
return batch[i].Time().Before(batch[j].Time())
})
return batch
}
// Write the metrics to Google Cloud Stackdriver.
func (s *Stackdriver) Write(metrics []telegraf.Metric) error {
ctx := context.Background()
for _, m := range metrics {
batch := sorted(metrics)
for _, m := range batch {
timeSeries := []*monitoringpb.TimeSeries{}
for _, f := range m.FieldList() {
value, err := getStackdriverTypedValue(f.Value)
if err != nil {
log.Printf("E! [output.stackdriver] get type failed: %s", err)
log.Printf("E! [outputs.stackdriver] get type failed: %s", err)
continue
}
@@ -90,13 +112,13 @@ func (s *Stackdriver) Write(metrics []telegraf.Metric) error {
metricKind, err := getStackdriverMetricKind(m.Type())
if err != nil {
log.Printf("E! [output.stackdriver] get metric failed: %s", err)
log.Printf("E! [outputs.stackdriver] get metric failed: %s", err)
continue
}
timeInterval, err := getStackdriverTimeInterval(metricKind, StartTime, m.Time().Unix())
if err != nil {
log.Printf("E! [output.stackdriver] get time interval failed: %s", err)
log.Printf("E! [outputs.stackdriver] get time interval failed: %s", err)
continue
}
@@ -139,7 +161,13 @@ func (s *Stackdriver) Write(metrics []telegraf.Metric) error {
// Create the time series in Stackdriver.
err := s.client.CreateTimeSeries(ctx, timeSeriesRequest)
if err != nil {
log.Printf("E! [output.stackdriver] unable to write to Stackdriver: %s", err)
if strings.Contains(err.Error(), errStringPointsOutOfOrder) ||
strings.Contains(err.Error(), errStringPointsTooOld) ||
strings.Contains(err.Error(), errStringPointsTooFrequent) {
log.Printf("D! [outputs.stackdriver] unable to write to Stackdriver: %s", err)
return nil
}
log.Printf("E! [outputs.stackdriver] unable to write to Stackdriver: %s", err)
return err
}
}
@@ -239,7 +267,7 @@ func getStackdriverLabels(tags []*telegraf.Tag) map[string]string {
for k, v := range labels {
if len(k) > QuotaStringLengthForLabelKey {
log.Printf(
"W! [output.stackdriver] removing tag [%s] key exceeds string length for label key [%d]",
"W! [outputs.stackdriver] removing tag [%s] key exceeds string length for label key [%d]",
k,
QuotaStringLengthForLabelKey,
)
@@ -248,7 +276,7 @@ func getStackdriverLabels(tags []*telegraf.Tag) map[string]string {
}
if len(v) > QuotaStringLengthForLabelValue {
log.Printf(
"W! [output.stackdriver] removing tag [%s] value exceeds string length for label value [%d]",
"W! [outputs.stackdriver] removing tag [%s] value exceeds string length for label value [%d]",
k,
QuotaStringLengthForLabelValue,
)
@@ -259,7 +287,7 @@ func getStackdriverLabels(tags []*telegraf.Tag) map[string]string {
if len(labels) > QuotaLabelsPerMetricDescriptor {
excess := len(labels) - QuotaLabelsPerMetricDescriptor
log.Printf(
"W! [output.stackdriver] tag count [%d] exceeds quota for stackdriver labels [%d] removing [%d] random tags",
"W! [outputs.stackdriver] tag count [%d] exceeds quota for stackdriver labels [%d] removing [%d] random tags",
len(labels),
QuotaLabelsPerMetricDescriptor,
excess,