From 99399511c1760b202ecd6f2d367780ba1da2a5d7 Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Wed, 27 Nov 2019 00:19:20 -0500 Subject: [PATCH] internal/telemetry: lift the tests up to the request level rather than testing events or metrics directly, we test them in the context of a full message that would get sent to the agent Change-Id: I238a7f9ab7b1456d1b4b2bac2519d814928f2283 Reviewed-on: https://go-review.googlesource.com/c/tools/+/209098 Reviewed-by: Emmanuel Odeke --- .../telemetry/export/ocagent/metrics_test.go | 46 ++++----- internal/telemetry/export/ocagent/ocagent.go | 28 +++--- .../telemetry/export/ocagent/ocagent_test.go | 95 ++++++++++++++++--- 3 files changed, 118 insertions(+), 51 deletions(-) diff --git a/internal/telemetry/export/ocagent/metrics_test.go b/internal/telemetry/export/ocagent/metrics_test.go index 48f9cd0801..38ffa7813d 100644 --- a/internal/telemetry/export/ocagent/metrics_test.go +++ b/internal/telemetry/export/ocagent/metrics_test.go @@ -10,18 +10,18 @@ import ( ) func TestEncodeMetric(t *testing.T) { - start, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:00Z") end, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:30Z") - + const prefix = testNodeStr + ` + "metrics":[` + const suffix = `]}` tests := []struct { - name string - data telemetry.MetricData - start time.Time - want string + name string + data telemetry.MetricData + want string }{ { name: "nil data", - want: `null`, + want: prefix + `null` + suffix, }, { name: "Int64Data cumulative", @@ -38,8 +38,7 @@ func TestEncodeMetric(t *testing.T) { }, EndTime: &end, }, - start: start, - want: `{ + want: prefix + `{ "metric_descriptor": { "name": "int", "description": "int metric", @@ -79,7 +78,7 @@ func TestEncodeMetric(t *testing.T) { ] } ] - }`, + }` + suffix, }, { name: "Int64Data gauge", @@ -91,8 +90,7 @@ func TestEncodeMetric(t *testing.T) { }, IsGauge: true, }, - start: start, - want: `{ + want: prefix + `{ "metric_descriptor": { "name": "int-gauge", "description": "int metric gauge", @@ -103,7 +101,7 @@ func TestEncodeMetric(t *testing.T) { } ] } - }`, + }` + suffix, }, { name: "Float64Data cumulative", @@ -119,8 +117,7 @@ func TestEncodeMetric(t *testing.T) { }, EndTime: &end, }, - start: start, - want: `{ + want: prefix + `{ "metric_descriptor": { "name": "float", "description": "float metric", @@ -151,7 +148,7 @@ func TestEncodeMetric(t *testing.T) { ] } ] - }`, + }` + suffix, }, { name: "Float64Data gauge", @@ -163,8 +160,7 @@ func TestEncodeMetric(t *testing.T) { }, IsGauge: true, }, - start: start, - want: `{ + want: prefix + `{ "metric_descriptor": { "name": "float-gauge", "description": "float metric gauge", @@ -175,7 +171,7 @@ func TestEncodeMetric(t *testing.T) { } ] } - }`, + }` + suffix, }, { name: "HistogramInt64", @@ -201,8 +197,7 @@ func TestEncodeMetric(t *testing.T) { }, EndTime: &end, }, - start: start, - want: `{ + want: prefix + `{ "metric_descriptor": { "name": "histogram int", "description": "histogram int metric", @@ -247,7 +242,7 @@ func TestEncodeMetric(t *testing.T) { ] } ] - }`, + }` + suffix, }, { name: "HistogramFloat64", @@ -272,8 +267,7 @@ func TestEncodeMetric(t *testing.T) { }, EndTime: &end, }, - start: start, - want: `{ + want: prefix + `{ "metric_descriptor": { "name": "histogram float", "description": "histogram float metric", @@ -314,13 +308,13 @@ func TestEncodeMetric(t *testing.T) { ] } ] - }`, + }` + suffix, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := ocagent.EncodeMetric(tt.data, tt.start) + got, err := ocagent.EncodeMetric(cfg, tt.data) if err != nil { t.Fatal(err) } diff --git a/internal/telemetry/export/ocagent/ocagent.go b/internal/telemetry/export/ocagent/ocagent.go index a42155ab56..14511d8451 100644 --- a/internal/telemetry/export/ocagent/ocagent.go +++ b/internal/telemetry/export/ocagent/ocagent.go @@ -117,26 +117,26 @@ func (e *exporter) Flush() { if len(spans) > 0 { e.send("/v1/trace", &wire.ExportTraceServiceRequest{ - Node: e.buildNode(), + Node: e.config.buildNode(), Spans: spans, //TODO: Resource? }) } if len(metrics) > 0 { e.send("/v1/metrics", &wire.ExportMetricsServiceRequest{ - Node: e.buildNode(), + Node: e.config.buildNode(), Metrics: metrics, //TODO: Resource? }) } } -func (e *exporter) buildNode() *wire.Node { +func (cfg *Config) buildNode() *wire.Node { return &wire.Node{ Identifier: &wire.ProcessIdentifier{ - HostName: e.config.Host, - Pid: e.config.Process, - StartTimestamp: convertTimestamp(e.config.Start), + HostName: cfg.Host, + Pid: cfg.Process, + StartTimestamp: convertTimestamp(cfg.Start), }, LibraryInfo: &wire.LibraryInfo{ Language: wire.LanguageGo, @@ -144,17 +144,23 @@ func (e *exporter) buildNode() *wire.Node { CoreLibraryVersion: "x/tools", }, ServiceInfo: &wire.ServiceInfo{ - Name: e.config.Service, + Name: cfg.Service, }, } } -func EncodeAnnotation(a telemetry.Event) ([]byte, error) { - return json.Marshal(convertAnnotation(a)) +func EncodeSpan(cfg Config, span *telemetry.Span) ([]byte, error) { + return json.Marshal(&wire.ExportTraceServiceRequest{ + Node: cfg.buildNode(), + Spans: []*wire.Span{convertSpan(span)}, + }) } -func EncodeMetric(m telemetry.MetricData, at time.Time) ([]byte, error) { - return json.Marshal(convertMetric(m, at)) +func EncodeMetric(cfg Config, m telemetry.MetricData) ([]byte, error) { + return json.Marshal(&wire.ExportMetricsServiceRequest{ + Node: cfg.buildNode(), + Metrics: []*wire.Metric{convertMetric(m, cfg.Start)}, + }) } func (e *exporter) send(endpoint string, message interface{}) { diff --git a/internal/telemetry/export/ocagent/ocagent_test.go b/internal/telemetry/export/ocagent/ocagent_test.go index 24dc4375b1..97d2c2a01c 100644 --- a/internal/telemetry/export/ocagent/ocagent_test.go +++ b/internal/telemetry/export/ocagent/ocagent_test.go @@ -10,34 +10,92 @@ import ( "encoding/json" "errors" "testing" + "time" "golang.org/x/tools/internal/telemetry" "golang.org/x/tools/internal/telemetry/export/ocagent" "golang.org/x/tools/internal/telemetry/tag" ) -func TestConvert_annotation(t *testing.T) { +var ( + cfg = ocagent.Config{ + Host: "tester", + Process: 1, + Service: "ocagent-tests", + } + start time.Time + at time.Time + end time.Time +) + +func init() { + cfg.Start, _ = time.Parse(time.RFC3339Nano, "1970-01-01T00:00:00Z") +} + +const testNodeStr = `{ + "node":{ + "identifier":{ + "host_name":"tester", + "pid":1, + "start_timestamp":"1970-01-01T00:00:00Z" + }, + "library_info":{ + "language":4, + "exporter_version":"0.0.1", + "core_library_version":"x/tools" + }, + "service_info":{ + "name":"ocagent-tests" + } + },` + +func TestEvents(t *testing.T) { + start, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:30Z") + at, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:40Z") + end, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:50Z") + const prefix = testNodeStr + ` + "spans":[{ + "trace_id":"AAAAAAAAAAAAAAAAAAAAAA==", + "span_id":"AAAAAAAAAAA=", + "parent_span_id":"AAAAAAAAAAA=", + "name":{"value":"event span"}, + "start_time":"1970-01-01T00:00:30Z", + "end_time":"1970-01-01T00:00:50Z", + "time_events":{ + ` + const suffix = ` + }, + "same_process_as_parent_span":true + }] + }` tests := []struct { name string event func(ctx context.Context) telemetry.Event want string }{ { - name: "no tags", - event: func(ctx context.Context) telemetry.Event { return telemetry.Event{} }, - want: "null", + name: "no tags", + event: func(ctx context.Context) telemetry.Event { + return telemetry.Event{ + At: at, + } + }, + want: prefix + ` + "timeEvent":[{"time":"1970-01-01T00:00:40Z"}] + ` + suffix, }, { name: "description no error", event: func(ctx context.Context) telemetry.Event { return telemetry.Event{ + At: at, Message: "cache miss", Tags: telemetry.TagList{ tag.Of("db", "godb"), }, } }, - want: `{ + want: prefix + `"timeEvent":[{"time":"1970-01-01T00:00:40Z","annotation":{ "description": { "value": "cache miss" }, @@ -50,13 +108,14 @@ func TestConvert_annotation(t *testing.T) { } } } -}`, +}}]` + suffix, }, { name: "description and error", event: func(ctx context.Context) telemetry.Event { return telemetry.Event{ + At: at, Message: "cache miss", Error: errors.New("no network connectivity"), Tags: telemetry.TagList{ @@ -64,7 +123,7 @@ func TestConvert_annotation(t *testing.T) { }, } }, - want: `{ + want: prefix + `"timeEvent":[{"time":"1970-01-01T00:00:40Z","annotation":{ "description": { "value": "cache miss" }, @@ -82,19 +141,20 @@ func TestConvert_annotation(t *testing.T) { } } } -}`, + }}]` + suffix, }, { name: "no description, but error", event: func(ctx context.Context) telemetry.Event { return telemetry.Event{ + At: at, Error: errors.New("no network connectivity"), Tags: telemetry.TagList{ tag.Of("db", "godb"), }, } }, - want: `{ + want: prefix + `"timeEvent":[{"time":"1970-01-01T00:00:40Z","annotation":{ "description": { "value": "no network connectivity" }, @@ -107,12 +167,13 @@ func TestConvert_annotation(t *testing.T) { } } } -}`, + }}]` + suffix, }, { name: "enumerate all attribute types", event: func(ctx context.Context) telemetry.Event { return telemetry.Event{ + At: at, Message: "cache miss", Tags: telemetry.TagList{ tag.Of("db", "godb"), @@ -138,7 +199,7 @@ func TestConvert_annotation(t *testing.T) { }, } }, - want: `{ + want: prefix + `"timeEvent":[{"time":"1970-01-01T00:00:40Z","annotation":{ "description": { "value": "cache miss" }, @@ -194,13 +255,19 @@ func TestConvert_annotation(t *testing.T) { } } } -}`, +}}]` + suffix, }, } ctx := context.TODO() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := ocagent.EncodeAnnotation(tt.event(ctx)) + span := &telemetry.Span{ + Name: "event span", + Start: start, + Finish: end, + Events: []telemetry.Event{tt.event(ctx)}, + } + got, err := ocagent.EncodeSpan(cfg, span) if err != nil { t.Fatal(err) } @@ -221,6 +288,6 @@ func checkJSON(t *testing.T, got, want []byte) { t.Fatal(err) } if g.String() != w.String() { - t.Fatalf("Got:\n%s\nWant:\n%s", got, want) + t.Fatalf("Got:\n%s\nWant:\n%s", g, w) } }