Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion prometheus-to-sd/translator/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (p *PrometheusResponse) Build(config *config.CommonConfig, metricDescriptor
}
// Convert summary metrics into metric family types we can easily import, since summary types
// map to multiple stackdriver metrics.
metrics = FlattenSummaryMetricFamilies(metrics)
metrics = SummaryMetricFamilies(metrics)
if strings.HasPrefix(config.SourceConfig.MetricsPrefix, customMetricsPrefix) {
metricDescriptorCache.UpdateMetricDescriptors(metrics, config.SourceConfig.Whitelisted)
} else {
Expand Down
44 changes: 39 additions & 5 deletions prometheus-to-sd/translator/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ func DowncaseMetricNames(metricFamilies map[string]*dto.MetricFamily) map[string
return result
}

// FlattenSummaryMetricFamilies flattens summary metric families into two counter metrics,
// one for the running sum and count, respectively
func FlattenSummaryMetricFamilies(metricFamilies map[string]*dto.MetricFamily) map[string]*dto.MetricFamily {
// SummaryMetricFamilies exports summary metric families into two counter metrics,
// one for the running sum and count, and a gauge metric labelled with different quantiles.
func SummaryMetricFamilies(metricFamilies map[string]*dto.MetricFamily) map[string]*dto.MetricFamily {
result := make(map[string]*dto.MetricFamily)
for metricName, family := range metricFamilies {
switch family.GetType() {
Expand All @@ -133,13 +133,47 @@ func FlattenSummaryMetricFamilies(metricFamilies map[string]*dto.MetricFamily) m
}
result[metricName+"_sum"] = sumMetricFromSummary(family.GetName(), family.Metric)
result[metricName+"_count"] = countMetricFromSummary(family.GetName(), family.Metric)
result[metricName] = quantilesFromSummary(family.GetName(), family.Metric)
default:
result[metricName] = family
}
}
return result
}

func stringPointer(val string) *string {
ptr := val
return &ptr
}

func quantilesFromSummary(name string, metrics []*dto.Metric) *dto.MetricFamily {
n := name
t := dto.MetricType_GAUGE
newMetrics := make([]*dto.Metric, 0, len(metrics))
for _, m := range metrics {
for _, quintile := range m.Summary.Quantile {
newLabelPair := dto.LabelPair{
Name: stringPointer("quantile"),
Value: stringPointer(fmt.Sprintf("%f", *quintile.Quantile)),
}
labelsCopy := append(m.Label, &newLabelPair)
newMetric := &dto.Metric{
Label: labelsCopy,
Gauge: &dto.Gauge{
Value: quintile.Value,
},
}
newMetrics = append(newMetrics, newMetric)
}
}
return &dto.MetricFamily{
Type: &t,
Name: &n,
Metric: newMetrics,
}
}

// this is a single metric passed in with lots of quantiles
// sumMetricFromSummary manipulates a Summary to extract out a specific sum MetricType_COUNTER metric
func sumMetricFromSummary(name string, metrics []*dto.Metric) *dto.MetricFamily {
n := name + "_sum"
Expand Down Expand Up @@ -339,8 +373,8 @@ func convertToDistributionValue(h *dto.Histogram) *v3.Distribution {
}

return &v3.Distribution{
Count: count,
Mean: mean,
Count: count,
Mean: mean,
SumOfSquaredDeviation: dev,
BucketOptions: &v3.BucketOptions{
ExplicitBuckets: &v3.Explicit{
Expand Down
100 changes: 88 additions & 12 deletions prometheus-to-sd/translator/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ process_start_time_seconds 1234567890
# TYPE int_summary_metric summary
int_summary_metric{quantile="0.5"} 4
int_summary_metric{quantile="0.9"} 8
int_summary_metric{quantile="0.99"} 8
int_summary_metric_sum 42
int_summary_metric_count 101010
`}
Expand All @@ -453,8 +452,6 @@ int_summary_metric_count 101010
process_start_time_seconds 1234567890
# TYPE float_summary_metric summary
float_summary_metric{quantile="0.5"} 4.12
float_summary_metric{quantile="0.9"} 8.123
float_summary_metric{quantile="0.99"} 8.123
float_summary_metric_sum 0.42
float_summary_metric_count 50
`}
Expand All @@ -464,10 +461,6 @@ process_start_time_seconds 1234567890
# TYPE int_summary_metric summary
int_summary_metric{quantile="0.5",label="l1"} 1
int_summary_metric{quantile="0.5",label="l2"} 2
int_summary_metric{quantile="0.9",label="l1"} 3
int_summary_metric{quantile="0.9",label="l2"} 4
int_summary_metric{quantile="0.99",label="l1"} 5
int_summary_metric{quantile="0.99",label="l2"} 6
int_summary_metric_sum{label="l1"} 7
int_summary_metric_sum{label="l2"} 8
int_summary_metric_count{label="l1"} 9
Expand Down Expand Up @@ -510,6 +503,26 @@ int_summary_metric_count{label="l2"} 10
createIntPoint(101010, start, end),
},
},
{
Metric: &v3.Metric{
Labels: map[string]string{"quantile": "0.500000"},
Type: "container.googleapis.com/master/testcomponent/int_summary_metric",
},
MetricKind: "GAUGE",
Points: []*v3.Point{
createIntPointGauge(4, end),
},
},
{
Metric: &v3.Metric{
Labels: map[string]string{"quantile": "0.900000"},
Type: "container.googleapis.com/master/testcomponent/int_summary_metric",
},
MetricKind: "GAUGE",
Points: []*v3.Point{
createIntPointGauge(8, end),
},
},
},
},
{
Expand Down Expand Up @@ -537,6 +550,17 @@ int_summary_metric_count{label="l2"} 10
createIntPoint(50, start, end),
},
},
{
Metric: &v3.Metric{
Labels: map[string]string{"quantile": "0.500000"},
Type: "container.googleapis.com/master/testcomponent/float_summary_metric",
},
MetricKind: "GAUGE",
Points: []*v3.Point{
// Like all gauges the translater assumes it is an integer, unfortunately :(
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a seperate issue that I'll look into in a separate diff.

I've seen this cause some frustrating issues before, outside of summary metric types.

createIntPointGauge(4, end),
},
},
},
},
{
Expand Down Expand Up @@ -584,15 +608,34 @@ int_summary_metric_count{label="l2"} 10
createIntPoint(10, start, end),
},
},
{
Metric: &v3.Metric{
Labels: map[string]string{"label": "l1", "quantile": "0.500000"},
Type: "container.googleapis.com/master/testcomponent/int_summary_metric",
},
MetricKind: "GAUGE",
Points: []*v3.Point{
createIntPointGauge(1, end),
},
},
{
Metric: &v3.Metric{
Labels: map[string]string{"label": "l2", "quantile": "0.500000"},
Type: "container.googleapis.com/master/testcomponent/int_summary_metric",
},
MetricKind: "GAUGE",
Points: []*v3.Point{
createIntPointGauge(2, end),
},
},
},
},
}

for _, tt := range sts {
t.Run(tt.description, func(t *testing.T) {
cache := buildCacheForTesting()

tsb := NewTimeSeriesBuilder(CommonConfigWithMetrics([]string{tt.summaryMetricName + "_sum", tt.summaryMetricName + "_count"}), cache)
tsb := NewTimeSeriesBuilder(CommonConfigWithMetrics([]string{tt.summaryMetricName + "_sum", tt.summaryMetricName + "_count", tt.summaryMetricName}), cache)
tsb.Update(tt.prometheusResponse, end)
tss, err := tsb.Build()
sort.Sort(ByMetricTypeReversed(tss))
Expand All @@ -607,12 +650,27 @@ int_summary_metric_count{label="l2"} 10
expectedTs := tt.expectedTimeSeries[i]
if expectedTs.MetricKind != ts.MetricKind {
t.Errorf("Got %v, expecting %v", ts.MetricKind, expectedTs.MetricKind)
continue
}
if !reflect.DeepEqual(expectedTs.Metric, ts.Metric) {
t.Errorf("Got %v, wanted %v as our metric", ts.Metric, expectedTs.Metric)
t.Errorf("Got %+v, wanted %v as our metric", ts.Metric, expectedTs.Metric)
continue
}
if len(ts.Points) != 1 || 1 != len(expectedTs.Points) {
t.Errorf("Got %v, wanted %v as our points' lengths", len(ts.Points), len(expectedTs.Points))
continue
}
if !reflect.DeepEqual(ts.Points[0].Value, expectedTs.Points[0].Value) {
t.Errorf("Got %+v, wanted %+v as our points' values", ts.Points[0].Value, expectedTs.Points[0].Value)
continue
}
if !reflect.DeepEqual(ts.Points[0].Interval, expectedTs.Points[0].Interval) {
t.Errorf("Got %+v, wanted %+v as our points' intervals", ts.Points[0].Interval, expectedTs.Points[0].Interval)
continue
}
if !reflect.DeepEqual(ts.Points, expectedTs.Points) {
t.Errorf("Got %v, wanted %v as our points", ts.Points, expectedTs.Points)
if !reflect.DeepEqual(ts.Points[0].ForceSendFields, expectedTs.Points[0].ForceSendFields) {
t.Errorf("Got %+v, wanted %+v as our points' force send fields", ts.Points[0].ForceSendFields, expectedTs.Points[0].ForceSendFields)
continue
}
}
})
Expand Down Expand Up @@ -642,6 +700,16 @@ func createDoubleValue(double float64) *v3.TypedValue {
}
}

func createPointGauge(value *v3.TypedValue, valueTypeString string, end time.Time) *v3.Point {
return &v3.Point{
Interval: &v3.TimeInterval{
EndTime: end.UTC().Format(time.RFC3339),
},
Value: value,
ForceSendFields: []string{valueTypeString},
}
}

func createPoint(value *v3.TypedValue, valueTypeString string, start time.Time, end time.Time) *v3.Point {
return &v3.Point{
Interval: createInterval(start, end),
Expand All @@ -650,10 +718,18 @@ func createPoint(value *v3.TypedValue, valueTypeString string, start time.Time,
}
}

func createIntPointGauge(num int, end time.Time) *v3.Point {
return createPointGauge(createIntValue(num), "Int64Value", end)
}

func createIntPoint(num int, start time.Time, end time.Time) *v3.Point {
return createPoint(createIntValue(num), "Int64Value", start, end)
}

func createDoublePointGauge(d float64, end time.Time) *v3.Point {
return createPointGauge(createDoubleValue(d), "DoubleValue", end)
}

func createDoublePoint(d float64, start time.Time, end time.Time) *v3.Point {
return createPoint(createDoubleValue(d), "DoubleValue", start, end)
}
Expand Down