2020-03-24 07:41:10 +02:00
|
|
|
// Copyright The OpenTelemetry Authors
|
2019-09-28 20:27:02 +02:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2020-07-22 21:34:44 +02:00
|
|
|
package stdout_test
|
2019-09-28 20:27:02 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-10-08 20:56:58 +02:00
|
|
|
"context"
|
2019-09-28 20:27:02 +02:00
|
|
|
"encoding/json"
|
2020-09-09 19:19:03 +02:00
|
|
|
"errors"
|
2019-09-28 20:27:02 +02:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-10-09 04:58:56 +02:00
|
|
|
"go.opentelemetry.io/otel"
|
2020-10-05 20:36:03 +02:00
|
|
|
"go.opentelemetry.io/otel/codes"
|
2020-07-22 21:34:44 +02:00
|
|
|
"go.opentelemetry.io/otel/exporters/stdout"
|
2020-08-18 05:25:03 +02:00
|
|
|
"go.opentelemetry.io/otel/label"
|
2019-11-05 23:08:55 +02:00
|
|
|
export "go.opentelemetry.io/otel/sdk/export/trace"
|
2020-03-17 01:48:35 +02:00
|
|
|
"go.opentelemetry.io/otel/sdk/resource"
|
2019-09-28 20:27:02 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestExporter_ExportSpan(t *testing.T) {
|
2020-01-02 18:40:37 +02:00
|
|
|
// write to buffer for testing
|
|
|
|
var b bytes.Buffer
|
2020-07-22 21:34:44 +02:00
|
|
|
ex, err := stdout.NewExporter(stdout.WithWriter(&b))
|
2019-09-28 20:27:02 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Error constructing stdout exporter %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup test span
|
|
|
|
now := time.Now()
|
2020-10-09 04:58:56 +02:00
|
|
|
traceID, _ := otel.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
|
|
|
spanID, _ := otel.SpanIDFromHex("0102030405060708")
|
2019-09-28 20:27:02 +02:00
|
|
|
keyValue := "value"
|
2019-12-09 23:03:11 +02:00
|
|
|
doubleValue := 123.456
|
2020-10-31 20:16:55 +02:00
|
|
|
resource := resource.NewWithAttributes(label.String("rk1", "rv11"))
|
2019-09-28 20:27:02 +02:00
|
|
|
|
2019-10-08 20:56:58 +02:00
|
|
|
testSpan := &export.SpanData{
|
2020-10-09 04:58:56 +02:00
|
|
|
SpanContext: otel.SpanContext{
|
2019-09-28 20:27:02 +02:00
|
|
|
TraceID: traceID,
|
|
|
|
SpanID: spanID,
|
|
|
|
},
|
|
|
|
Name: "/foo",
|
|
|
|
StartTime: now,
|
|
|
|
EndTime: now,
|
2020-08-18 05:25:03 +02:00
|
|
|
Attributes: []label.KeyValue{
|
|
|
|
label.String("key", keyValue),
|
|
|
|
label.Float64("double", doubleValue),
|
2019-09-28 20:27:02 +02:00
|
|
|
},
|
2019-11-04 21:46:34 +02:00
|
|
|
MessageEvents: []export.Event{
|
2020-08-18 05:25:03 +02:00
|
|
|
{Name: "foo", Attributes: []label.KeyValue{label.String("key", keyValue)}, Time: now},
|
|
|
|
{Name: "bar", Attributes: []label.KeyValue{label.Float64("double", doubleValue)}, Time: now},
|
2019-11-04 21:46:34 +02:00
|
|
|
},
|
2020-10-09 04:58:56 +02:00
|
|
|
SpanKind: otel.SpanKindInternal,
|
2020-10-05 20:36:03 +02:00
|
|
|
StatusCode: codes.Error,
|
2020-03-07 20:38:59 +02:00
|
|
|
StatusMessage: "interesting",
|
2020-03-17 01:48:35 +02:00
|
|
|
Resource: resource,
|
2019-09-28 20:27:02 +02:00
|
|
|
}
|
2020-09-09 19:19:03 +02:00
|
|
|
if err := ex.ExportSpans(context.Background(), []*export.SpanData{testSpan}); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2019-09-28 20:27:02 +02:00
|
|
|
|
|
|
|
expectedSerializedNow, _ := json.Marshal(now)
|
|
|
|
|
|
|
|
got := b.String()
|
2020-07-22 21:34:44 +02:00
|
|
|
expectedOutput := `[{"SpanContext":{` +
|
2019-10-23 08:01:33 +02:00
|
|
|
`"TraceID":"0102030405060708090a0b0c0d0e0f10",` +
|
|
|
|
`"SpanID":"0102030405060708","TraceFlags":0},` +
|
2019-10-28 19:05:06 +02:00
|
|
|
`"ParentSpanID":"0000000000000000",` +
|
2019-11-05 02:05:43 +02:00
|
|
|
`"SpanKind":1,` +
|
2019-09-28 20:27:02 +02:00
|
|
|
`"Name":"/foo",` +
|
|
|
|
`"StartTime":` + string(expectedSerializedNow) + "," +
|
|
|
|
`"EndTime":` + string(expectedSerializedNow) + "," +
|
|
|
|
`"Attributes":[` +
|
|
|
|
`{` +
|
2019-10-17 07:49:58 +02:00
|
|
|
`"Key":"key",` +
|
2019-10-31 00:01:19 +02:00
|
|
|
`"Value":{"Type":"STRING","Value":"value"}` +
|
2019-09-28 20:27:02 +02:00
|
|
|
`},` +
|
|
|
|
`{` +
|
2019-10-17 07:49:58 +02:00
|
|
|
`"Key":"double",` +
|
2019-10-31 00:01:19 +02:00
|
|
|
`"Value":{"Type":"FLOAT64","Value":123.456}` +
|
2020-04-22 23:32:58 +02:00
|
|
|
`}],` +
|
2019-11-04 21:46:34 +02:00
|
|
|
`"MessageEvents":[` +
|
|
|
|
`{` +
|
2019-12-18 20:13:05 +02:00
|
|
|
`"Name":"foo",` +
|
2019-11-04 21:46:34 +02:00
|
|
|
`"Attributes":[` +
|
|
|
|
`{` +
|
|
|
|
`"Key":"key",` +
|
|
|
|
`"Value":{"Type":"STRING","Value":"value"}` +
|
|
|
|
`}` +
|
|
|
|
`],` +
|
|
|
|
`"Time":` + string(expectedSerializedNow) +
|
|
|
|
`},` +
|
|
|
|
`{` +
|
2019-12-18 20:13:05 +02:00
|
|
|
`"Name":"bar",` +
|
2019-11-04 21:46:34 +02:00
|
|
|
`"Attributes":[` +
|
|
|
|
`{` +
|
|
|
|
`"Key":"double",` +
|
|
|
|
`"Value":{"Type":"FLOAT64","Value":123.456}` +
|
|
|
|
`}` +
|
|
|
|
`],` +
|
|
|
|
`"Time":` + string(expectedSerializedNow) +
|
|
|
|
`}` +
|
|
|
|
`],` +
|
2019-09-28 20:27:02 +02:00
|
|
|
`"Links":null,` +
|
2020-10-05 20:36:03 +02:00
|
|
|
`"StatusCode":"Error",` +
|
2020-03-07 20:38:59 +02:00
|
|
|
`"StatusMessage":"interesting",` +
|
2019-09-28 20:27:02 +02:00
|
|
|
`"HasRemoteParent":false,` +
|
|
|
|
`"DroppedAttributeCount":0,` +
|
|
|
|
`"DroppedMessageEventCount":0,` +
|
|
|
|
`"DroppedLinkCount":0,` +
|
2020-03-13 22:07:36 +02:00
|
|
|
`"ChildSpanCount":0,` +
|
2020-04-22 23:32:58 +02:00
|
|
|
`"Resource":[` +
|
|
|
|
`{` +
|
|
|
|
`"Key":"rk1",` +
|
|
|
|
`"Value":{"Type":"STRING","Value":"rv11"}` +
|
2020-06-10 07:15:53 +02:00
|
|
|
`}],` +
|
|
|
|
`"InstrumentationLibrary":{` +
|
|
|
|
`"Name":"",` +
|
|
|
|
`"Version":""` +
|
2020-07-22 21:34:44 +02:00
|
|
|
`}}]` + "\n"
|
2019-09-28 20:27:02 +02:00
|
|
|
|
|
|
|
if got != expectedOutput {
|
|
|
|
t.Errorf("Want: %v but got: %v", expectedOutput, got)
|
|
|
|
}
|
|
|
|
}
|
2020-09-09 19:19:03 +02:00
|
|
|
|
|
|
|
func TestExporterShutdownHonorsTimeout(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
e, err := stdout.NewExporter()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create exporter: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
innerCtx, innerCancel := context.WithTimeout(ctx, time.Nanosecond)
|
|
|
|
defer innerCancel()
|
|
|
|
<-innerCtx.Done()
|
|
|
|
if err := e.Shutdown(innerCtx); err == nil {
|
|
|
|
t.Error("expected context DeadlineExceeded error, got nil")
|
|
|
|
} else if !errors.Is(err, context.DeadlineExceeded) {
|
|
|
|
t.Errorf("expected context DeadlineExceeded error, got %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExporterShutdownHonorsCancel(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
e, err := stdout.NewExporter()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create exporter: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
innerCtx, innerCancel := context.WithCancel(ctx)
|
|
|
|
innerCancel()
|
|
|
|
if err := e.Shutdown(innerCtx); err == nil {
|
|
|
|
t.Error("expected context canceled error, got nil")
|
|
|
|
} else if !errors.Is(err, context.Canceled) {
|
|
|
|
t.Errorf("expected context canceled error, got %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExporterShutdownNoError(t *testing.T) {
|
|
|
|
e, err := stdout.NewExporter()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to create exporter: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := e.Shutdown(context.Background()); err != nil {
|
|
|
|
t.Errorf("shutdown errored: expected nil, got %v", err)
|
|
|
|
}
|
|
|
|
}
|