From b9813eba5fd947f1e1eae71f7e8f4f6fe31121c1 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Thu, 17 Jan 2019 16:54:51 -0800 Subject: [PATCH] stats, metrics: deduplicate TimeSeries with non-unique Metric.Type Since existence, the stats exporter was sending Stackdriver Metrics only split up by chunks of maxUploadSize of 200, but Metric-s with the exact same Type were still uploaded in the same CreateTimeSeriesRequest which would cause: err: rpc error: code = InvalidArgument desc = One or more TimeSeries could not be written: Field timeSeries[?] had an invalid value: Duplicate TimeSeries encountered. Only one point can be written per TimeSeries per request.: timeSeries[?] and the previous remedy just relied on a synchronization of SetReportingPeriod of 60+s which would aggregate stats/view.Data. This change now splits up such Metrics so even if uploads are made in less than 60s, CreateTimeSeriesRequest-s will be uniquely uploaded and won't cause Stackdriver's backend to trip up. Fixes #73 --- equivalence_test.go | 2 +- metrics.go | 77 +++- metrics_test.go | 153 ++++++-- stats.go | 37 +- stats_test.go | 918 +++++++++++++++++++++++--------------------- 5 files changed, 703 insertions(+), 484 deletions(-) diff --git a/equivalence_test.go b/equivalence_test.go index 8ec2cbc..924d57d 100644 --- a/equivalence_test.go +++ b/equivalence_test.go @@ -111,7 +111,7 @@ func TestStatsAndMetricsEquivalence(t *testing.T) { vdl := []*view.Data{vd} sctreql := se.makeReq(vdl, maxTimeSeriesPerUpload) tsl, _ := se.protoMetricToTimeSeries(ctx, last.Node, last.Resource, last.Metrics[0]) - pctreql := []*monitoringpb.CreateTimeSeriesRequest{se.combineTimeSeriesToCreateTimeSeriesRequest(tsl)} + pctreql := se.combineTimeSeriesToCreateTimeSeriesRequest(tsl) if !reflect.DeepEqual(sctreql, pctreql) { t.Errorf("#%d: TimeSeries Mismatch\nStats CreateTimeSeriesRequest:\n\t%v\nProto CreateTimeSeriesRequest:\n\t%v\n", i, sctreql, pctreql) diff --git a/metrics.go b/metrics.go index 84a2a0e..e6b520f 100644 --- a/metrics.go +++ b/metrics.go @@ -101,25 +101,78 @@ func (se *statsExporter) handleMetricsUpload(payloads []*metricPayload) error { end = len(allTimeSeries) } batch := allTimeSeries[start:end] - ctsreq := se.combineTimeSeriesToCreateTimeSeriesRequest(batch) - if err := createTimeSeries(ctx, se.c, ctsreq); err != nil { - // span.SetStatus(trace.Status{Code: 2, Message: err.Error()}) - // TODO(@odeke-em, @jbd): Don't fail fast here, perhaps batch errors? - // return err + ctsreql := se.combineTimeSeriesToCreateTimeSeriesRequest(batch) + for _, ctsreq := range ctsreql { + if err := createTimeSeries(ctx, se.c, ctsreq); err != nil { + span.SetStatus(trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()}) + // TODO(@odeke-em): Don't fail fast here, perhaps batch errors? + // return err + } } } return nil } -func (se *statsExporter) combineTimeSeriesToCreateTimeSeriesRequest(ts []*monitoringpb.TimeSeries) *monitoringpb.CreateTimeSeriesRequest { +func (se *statsExporter) combineTimeSeriesToCreateTimeSeriesRequest(ts []*monitoringpb.TimeSeries) (ctsreql []*monitoringpb.CreateTimeSeriesRequest) { if len(ts) == 0 { return nil } - return &monitoringpb.CreateTimeSeriesRequest{ - Name: monitoring.MetricProjectPath(se.o.ProjectID), - TimeSeries: ts, + + // Since there are scenarios in which Metrics with the same Type + // can be bunched in the same TimeSeries, we have to ensure that + // we create a unique CreateTimeSeriesRequest with entirely unique Metrics + // per TimeSeries, lest we'll encounter: + // + // err: rpc error: code = InvalidArgument desc = One or more TimeSeries could not be written: + // Field timeSeries[2] had an invalid value: Duplicate TimeSeries encountered. + // Only one point can be written per TimeSeries per request.: timeSeries[2] + // + // This scenario happens when we are using the OpenCensus Agent in which multiple metrics + // are streamed by various client applications. + // See https://github.com/census-ecosystem/opencensus-go-exporter-stackdriver/issues/73 + uniqueTimeSeries := make([]*monitoringpb.TimeSeries, 0, len(ts)) + nonUniqueTimeSeries := make([]*monitoringpb.TimeSeries, 0, len(ts)) + seenMetrics := make(map[string]struct{}) + + for _, tti := range ts { + signature := tti.Metric.GetType() + if _, alreadySeen := seenMetrics[signature]; !alreadySeen { + uniqueTimeSeries = append(uniqueTimeSeries, tti) + seenMetrics[signature] = struct{}{} + } else { + nonUniqueTimeSeries = append(nonUniqueTimeSeries, tti) + } } + + // UniqueTimeSeries can be bunched up together + // While for each nonUniqueTimeSeries, we have + // to make a unique CreateTimeSeriesRequest. + ctsreql = append(ctsreql, &monitoringpb.CreateTimeSeriesRequest{ + Name: monitoring.MetricProjectPath(se.o.ProjectID), + TimeSeries: uniqueTimeSeries, + }) + + // Now recursively also combine the non-unique TimeSeries + // that were singly added to nonUniqueTimeSeries. + // The reason is that we need optimal combinations + // for optimal combinations because: + // * "a/b/c" + // * "a/b/c" + // * "x/y/z" + // * "a/b/c" + // * "x/y/z" + // * "p/y/z" + // * "d/y/z" + // + // should produce: + // CreateTimeSeries(uniqueTimeSeries) :: ["a/b/c", "x/y/z", "p/y/z", "d/y/z"] + // CreateTimeSeries(nonUniqueTimeSeries) :: ["a/b/c"] + // CreateTimeSeries(nonUniqueTimeSeries) :: ["a/b/c", "x/y/z"] + nonUniqueRequests := se.combineTimeSeriesToCreateTimeSeriesRequest(nonUniqueTimeSeries) + ctsreql = append(ctsreql, nonUniqueRequests...) + + return ctsreql } // protoMetricToTimeSeries converts a metric into a Stackdriver Monitoring v3 API CreateTimeSeriesRequest @@ -468,8 +521,12 @@ func protoResourceToMonitoredResource(rsp *resourcepb.Resource) *monitoredrespb. Type: "global", } } + typ := rsp.Type + if typ == "" { + typ = "global" + } mrsp := &monitoredrespb.MonitoredResource{ - Type: rsp.Type, + Type: type_, } if rsp.Labels != nil { mrsp.Labels = make(map[string]string, len(rsp.Labels)) diff --git a/metrics_test.go b/metrics_test.go index 5345d74..9f9dce9 100644 --- a/metrics_test.go +++ b/metrics_test.go @@ -21,6 +21,7 @@ import ( "strings" "testing" + monitoring "cloud.google.com/go/monitoring/apiv3" "github.com/golang/protobuf/ptypes/timestamp" distributionpb "google.golang.org/genproto/googleapis/api/distribution" googlemetricpb "google.golang.org/genproto/googleapis/api/metric" @@ -37,7 +38,7 @@ func TestProtoResourceToMonitoringResource(t *testing.T) { want *monitoredrespb.MonitoredResource }{ {in: nil, want: &monitoredrespb.MonitoredResource{Type: "global"}}, - {in: &resourcepb.Resource{}, want: &monitoredrespb.MonitoredResource{}}, + {in: &resourcepb.Resource{}, want: &monitoredrespb.MonitoredResource{Type: "global"}}, { in: &resourcepb.Resource{ Type: "foo", @@ -91,7 +92,7 @@ func TestProtoMetricToCreateTimeSeriesRequest(t *testing.T) { tests := []struct { in *metricspb.Metric - want *monitoringpb.CreateTimeSeriesRequest + want []*monitoringpb.CreateTimeSeriesRequest wantErr string statsExporter *statsExporter }{ @@ -135,33 +136,35 @@ func TestProtoMetricToCreateTimeSeriesRequest(t *testing.T) { statsExporter: &statsExporter{ o: Options{ProjectID: "foo"}, }, - want: &monitoringpb.CreateTimeSeriesRequest{ - Name: "projects/foo", - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &googlemetricpb.Metric{ - Type: "custom.googleapis.com/opencensus/with_metric_descriptor", - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: startTimestamp, - EndTime: endTimestamp, - }, - Value: &monitoringpb.TypedValue{ - Value: &monitoringpb.TypedValue_DistributionValue{ - DistributionValue: &distributionpb.Distribution{ - Count: 1, - Mean: 11.9, - SumOfSquaredDeviation: 0, - BucketCounts: []int64{0, 1, 0, 0, 0}, - BucketOptions: &distributionpb.Distribution_BucketOptions{ - Options: &distributionpb.Distribution_BucketOptions_ExplicitBuckets{ - ExplicitBuckets: &distributionpb.Distribution_BucketOptions_Explicit{ - Bounds: []float64{0, 10, 20, 30, 40}, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: "projects/foo", + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &googlemetricpb.Metric{ + Type: "custom.googleapis.com/opencensus/with_metric_descriptor", + }, + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: startTimestamp, + EndTime: endTimestamp, + }, + Value: &monitoringpb.TypedValue{ + Value: &monitoringpb.TypedValue_DistributionValue{ + DistributionValue: &distributionpb.Distribution{ + Count: 1, + Mean: 11.9, + SumOfSquaredDeviation: 0, + BucketCounts: []int64{0, 1, 0, 0, 0}, + BucketOptions: &distributionpb.Distribution_BucketOptions{ + Options: &distributionpb.Distribution_BucketOptions_ExplicitBuckets{ + ExplicitBuckets: &distributionpb.Distribution_BucketOptions_Explicit{ + Bounds: []float64{0, 10, 20, 30, 40}, + }, }, }, }, @@ -404,6 +407,98 @@ func TestProtoMetricsToMonitoringMetrics_fromProtoPoint(t *testing.T) { } } +func TestCombineTimeSeriesAndDeduplication(t *testing.T) { + se := new(statsExporter) + + tests := []struct { + in []*monitoringpb.TimeSeries + want []*monitoringpb.CreateTimeSeriesRequest + }{ + { + in: []*monitoringpb.TimeSeries{ + { + Metric: &googlemetricpb.Metric{ + Type: "a/b/c", + }, + }, + { + Metric: &googlemetricpb.Metric{ + Type: "a/b/c", + }, + }, + { + Metric: &googlemetricpb.Metric{ + Type: "A/b/c", + }, + }, + { + Metric: &googlemetricpb.Metric{ + Type: "a/b/c", + }, + }, + { + Metric: &googlemetricpb.Metric{ + Type: "X/Y/Z", + }, + }, + }, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath(se.o.ProjectID), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &googlemetricpb.Metric{ + Type: "a/b/c", + }, + }, + { + Metric: &googlemetricpb.Metric{ + Type: "A/b/c", + }, + }, + { + Metric: &googlemetricpb.Metric{ + Type: "X/Y/Z", + }, + }, + }, + }, + { + Name: monitoring.MetricProjectPath(se.o.ProjectID), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &googlemetricpb.Metric{ + Type: "a/b/c", + }, + }, + }, + }, + { + Name: monitoring.MetricProjectPath(se.o.ProjectID), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &googlemetricpb.Metric{ + Type: "a/b/c", + }, + }, + }, + }, + }, + }, + } + + for i, tt := range tests { + got := se.combineTimeSeriesToCreateTimeSeriesRequest(tt.in) + want := tt.want + if !reflect.DeepEqual(got, want) { + gj, wj := serializeAsJSON(got), serializeAsJSON(want) + if gj != wj { + t.Errorf("#%d: Unmatched JSON\nGot:\n\t%s\nWant:\n\t%s", i, gj, wj) + } + } + } +} + func serializeAsJSON(v interface{}) string { blob, _ := json.MarshalIndent(v, "", " ") return string(blob) diff --git a/stats.go b/stats.go index 9ea264b..0ede83a 100644 --- a/stats.go +++ b/stats.go @@ -208,35 +208,38 @@ func (e *statsExporter) uploadStats(vds []*view.Data) error { return nil } -func (e *statsExporter) makeReq(vds []*view.Data, limit int) []*monitoringpb.CreateTimeSeriesRequest { +func (se *statsExporter) makeReq(vds []*view.Data, limit int) []*monitoringpb.CreateTimeSeriesRequest { var reqs []*monitoringpb.CreateTimeSeriesRequest - var timeSeries []*monitoringpb.TimeSeries + + var allTimeSeries []*monitoringpb.TimeSeries for _, vd := range vds { for _, row := range vd.Rows { - tags, resource := e.getMonitoredResource(vd.View, append([]tag.Tag(nil), row.Tags...)) + tags, resource := se.getMonitoredResource(vd.View, append([]tag.Tag(nil), row.Tags...)) ts := &monitoringpb.TimeSeries{ Metric: &metricpb.Metric{ - Type: e.metricType(vd.View), - Labels: newLabels(e.defaultLabels, tags), + Type: se.metricType(vd.View), + Labels: newLabels(se.defaultLabels, tags), }, Resource: resource, Points: []*monitoringpb.Point{newPoint(vd.View, row, vd.Start, vd.End)}, } - timeSeries = append(timeSeries, ts) - if len(timeSeries) == limit { - reqs = append(reqs, &monitoringpb.CreateTimeSeriesRequest{ - Name: monitoring.MetricProjectPath(e.o.ProjectID), - TimeSeries: timeSeries, - }) - timeSeries = []*monitoringpb.TimeSeries{} - } + allTimeSeries = append(allTimeSeries, ts) } } + + var timeSeries []*monitoringpb.TimeSeries + for _, ts := range allTimeSeries { + timeSeries = append(timeSeries, ts) + if len(timeSeries) == limit { + ctsreql := se.combineTimeSeriesToCreateTimeSeriesRequest(timeSeries) + reqs = append(reqs, ctsreql...) + timeSeries = timeSeries[:0] + } + } + if len(timeSeries) > 0 { - reqs = append(reqs, &monitoringpb.CreateTimeSeriesRequest{ - Name: monitoring.MetricProjectPath(e.o.ProjectID), - TimeSeries: timeSeries, - }) + ctsreql := se.combineTimeSeriesToCreateTimeSeriesRequest(timeSeries) + reqs = append(reqs, ctsreql...) } return reqs } diff --git a/stats_test.go b/stats_test.go index 174d96a..4f0a28a 100644 --- a/stats_test.go +++ b/stats_test.go @@ -105,69 +105,76 @@ func TestExporter_makeReq(t *testing.T) { name: "count agg + timeline", projID: "proj-id", vd: newTestViewData(v, start, end, count1, count2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/example.com/views/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - opencensusTaskKey: taskValue, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/example.com/views/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 10, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 10, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/example.com/views/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - opencensusTaskKey: taskValue, + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/example.com/views/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 16, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 16, - }}, }, }, }, }, - }}, + }, }, { name: "metric type formatter", @@ -178,197 +185,218 @@ func TestExporter_makeReq(t *testing.T) { return fmt.Sprintf("external.googleapis.com/%s", v.Name) }, }, - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "external.googleapis.com/example.com/views/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - opencensusTaskKey: taskValue, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "external.googleapis.com/example.com/views/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ + DoubleValue: 5.5, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ - DoubleValue: 5.5, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "external.googleapis.com/example.com/views/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - opencensusTaskKey: taskValue, + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "external.googleapis.com/example.com/views/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ + DoubleValue: -11.1, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ - DoubleValue: -11.1, - }}, }, }, }, }, - }}, + }, }, { name: "sum agg + timeline", projID: "proj-id", vd: newTestViewData(v, start, end, sum1, sum2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/example.com/views/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - opencensusTaskKey: taskValue, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/example.com/views/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ + DoubleValue: 5.5, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ - DoubleValue: 5.5, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/example.com/views/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - opencensusTaskKey: taskValue, + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/example.com/views/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ + DoubleValue: -11.1, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ - DoubleValue: -11.1, - }}, }, }, }, }, - }}, + }, }, { name: "last value agg", projID: "proj-id", vd: newTestViewData(lastValueView, start, end, &last1, &last2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/lasttestview", - Labels: map[string]string{ - "test_key": "test-value-1", - opencensusTaskKey: taskValue, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/lasttestview", + Labels: map[string]string{ + "test_key": "test-value-1", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ + DoubleValue: 100, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ - DoubleValue: 100, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/lasttestview", - Labels: map[string]string{ - "test_key": "test-value-2", - opencensusTaskKey: taskValue, + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/lasttestview", + Labels: map[string]string{ + "test_key": "test-value-2", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: &monitoredrespb.MonitoredResource{ - Type: "global", - }, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: &monitoredrespb.MonitoredResource{ + Type: "global", + }, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ + DoubleValue: 200, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ - DoubleValue: 200, - }}, }, }, }, }, - }}, + }, }, { name: "dist agg + time window", @@ -417,6 +445,7 @@ func TestExporter_makeReq(t *testing.T) { }}, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { opts := tt.opts @@ -467,21 +496,21 @@ func TestExporter_makeReq_batching(t *testing.T) { name: "4 vds; 3 limit", iter: 2, limit: 3, - wantReqs: 2, + wantReqs: 4, wantTotal: 4, }, { name: "4 vds; 4 limit", iter: 2, limit: 4, - wantReqs: 1, + wantReqs: 4, wantTotal: 4, }, { name: "4 vds; 5 limit", iter: 2, limit: 5, - wantReqs: 1, + wantReqs: 4, wantTotal: 4, }, } @@ -501,7 +530,7 @@ func TestExporter_makeReq_batching(t *testing.T) { } resps := e.makeReq(vds, tt.limit) if len(resps) != tt.wantReqs { - t.Errorf("%v: got %v; want %d requests", tt.name, resps, tt.wantReqs) + t.Errorf("%v:\ngot %d:: %v;\n\nwant %d requests\n\n", tt.name, len(resps), resps, tt.wantReqs) } var total int @@ -890,65 +919,72 @@ func TestExporter_makeReq_withCustomMonitoredResource(t *testing.T) { name: "count agg timeline", opts: Options{Resource: resource}, vd: newTestViewData(v, start, end, count1, count2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - opencensusTaskKey: taskValue, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 10, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 10, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - opencensusTaskKey: taskValue, + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 16, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 16, - }}, }, }, }, }, - }}, + }, }, { name: "with MonitoredResource and labels", @@ -961,65 +997,72 @@ func TestExporter_makeReq_withCustomMonitoredResource(t *testing.T) { } }(), vd: newTestViewData(v, start, end, count1, count2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - "pid": "1234", + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + "pid": "1234", + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 10, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 10, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - "pid": "1234", + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + "pid": "1234", + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 16, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 16, - }}, }, }, }, }, - }}, + }, }, { name: "GetMonitoredResource and labels", @@ -1034,65 +1077,72 @@ func TestExporter_makeReq_withCustomMonitoredResource(t *testing.T) { } }(), vd: newTestViewData(v, start, end, count1, count2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - "pid": "1234", + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + "pid": "1234", + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 10, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 10, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - "pid": "1234", + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + "pid": "1234", + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 16, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 16, - }}, }, }, }, }, - }}, + }, }, { name: "custom default monitoring labels", @@ -1105,129 +1155,143 @@ func TestExporter_makeReq_withCustomMonitoredResource(t *testing.T) { } }(), vd: newTestViewData(v, start, end, count1, count2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - "pid": "1234", + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + "pid": "1234", + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 10, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 10, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - "pid": "1234", + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + "pid": "1234", + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 16, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 16, - }}, }, }, }, }, - }}, + }, }, { name: "count agg timeline", opts: Options{Resource: resource}, vd: newTestViewData(v, start, end, count1, count2), - want: []*monitoringpb.CreateTimeSeriesRequest{{ - Name: monitoring.MetricProjectPath("proj-id"), - TimeSeries: []*monitoringpb.TimeSeries{ - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-1", - opencensusTaskKey: taskValue, + want: []*monitoringpb.CreateTimeSeriesRequest{ + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-1", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 10, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 10, - }}, }, }, }, - { - Metric: &metricpb.Metric{ - Type: "custom.googleapis.com/opencensus/testview", - Labels: map[string]string{ - "test_key": "test-value-2", - opencensusTaskKey: taskValue, + }, + { + Name: monitoring.MetricProjectPath("proj-id"), + TimeSeries: []*monitoringpb.TimeSeries{ + { + Metric: &metricpb.Metric{ + Type: "custom.googleapis.com/opencensus/testview", + Labels: map[string]string{ + "test_key": "test-value-2", + opencensusTaskKey: taskValue, + }, }, - }, - Resource: resource, - Points: []*monitoringpb.Point{ - { - Interval: &monitoringpb.TimeInterval{ - StartTime: ×tamp.Timestamp{ - Seconds: start.Unix(), - Nanos: int32(start.Nanosecond()), - }, - EndTime: ×tamp.Timestamp{ - Seconds: end.Unix(), - Nanos: int32(end.Nanosecond()), + Resource: resource, + Points: []*monitoringpb.Point{ + { + Interval: &monitoringpb.TimeInterval{ + StartTime: ×tamp.Timestamp{ + Seconds: start.Unix(), + Nanos: int32(start.Nanosecond()), + }, + EndTime: ×tamp.Timestamp{ + Seconds: end.Unix(), + Nanos: int32(end.Nanosecond()), + }, }, + Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ + Int64Value: 16, + }}, }, - Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ - Int64Value: 16, - }}, }, }, }, }, - }}, + }, }, } for _, tt := range tests { @@ -1304,7 +1368,7 @@ func TestExporter_customContext(t *testing.T) { if ctx.Err() != context.DeadlineExceeded { t.Errorf("expected context to time out; got %v", ctx.Err()) } - if timedOut != 2 { + if timedOut != 3 { t.Errorf("expected two functions to time out; got %d", timedOut) } }