Send metrics in ascending time order in stackdriver output (#5385)
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user