1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-12-12 10:04:29 +02:00
opentelemetry-go/exporters/zipkin/model_test.go
ReStartercc 3dd4e816a6
fix wrong representation of status value in zipkin exporter (#3340)
* export status codes to upper case in zipkin exporter

* add test cases for status UNSET and ERROR

* Update exporters/zipkin/model.go

correct the usage of case-sensitive terms

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>

* change unit test cases to test exact behavior

* move this PR to unrelease section in the CHANGELOG.md

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2022-10-27 21:22:18 -07:00

1219 lines
35 KiB
Go

// Copyright The OpenTelemetry Authors
//
// 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.
package zipkin
import (
"fmt"
"net"
"strconv"
"testing"
"time"
"github.com/google/go-cmp/cmp"
zkmodel "github.com/openzipkin/zipkin-go/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
"go.opentelemetry.io/otel/trace"
)
func TestModelConversion(t *testing.T) {
res := resource.NewSchemaless(
semconv.ServiceNameKey.String("model-test"),
semconv.ServiceVersionKey.String("0.1.0"),
attribute.Int64("resource-attr1", 42),
attribute.IntSlice("resource-attr2", []int{0, 1, 2}),
)
inputBatch := tracetest.SpanStubs{
// typical span data with UNSET status
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindServer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
attribute.IntSlice("attr3", []int{0, 1, 2}),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Unset,
Description: "",
},
Resource: res,
},
// typical span data with OK status
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindServer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
attribute.IntSlice("attr3", []int{0, 1, 2}),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Ok,
Description: "",
},
Resource: res,
},
// typical span data with ERROR status
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindServer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
attribute.IntSlice("attr3", []int{0, 1, 2}),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data with no parent (same as typical, but has
// invalid parent)
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
SpanKind: trace.SpanKindServer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data of unspecified kind
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindUnspecified,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data of internal kind
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindInternal,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data of client kind
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindClient,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
attribute.String("peer.hostname", "test-peer-hostname"),
attribute.String("net.peer.ip", "1.2.3.4"),
attribute.Int64("net.peer.port", 9876),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data of producer kind
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindProducer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data of consumer kind
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindConsumer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data with no events
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindServer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"),
},
Events: nil,
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: res,
},
// span data with an "error" attribute set to "false"
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
}),
SpanKind: trace.SpanKindServer,
Name: "foo",
StartTime: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: []attribute.KeyValue{
attribute.String("error", "false"),
},
Events: []tracesdk.Event{
{
Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Name: "ev1",
Attributes: []attribute.KeyValue{
attribute.Int64("eventattr1", 123),
},
},
{
Time: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Name: "ev2",
Attributes: nil,
},
},
Resource: res,
},
}.Snapshots()
expectedOutputBatch := []zkmodel.SpanModel{
// model for typical span data with UNSET status
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "SERVER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"attr3": "[0,1,2]",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for typical span data with OK status
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "SERVER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"attr3": "[0,1,2]",
"otel.status_code": "OK",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for typical span data with ERROR status
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "SERVER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"attr3": "[0,1,2]",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data with no parent
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: nil,
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "SERVER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data of unspecified kind
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data of internal kind
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data of client kind
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "CLIENT",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: &zkmodel.Endpoint{
IPv4: net.ParseIP("1.2.3.4"),
Port: 9876,
},
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"net.peer.ip": "1.2.3.4",
"net.peer.port": "9876",
"peer.hostname": "test-peer-hostname",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data of producer kind
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "PRODUCER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data of consumer kind
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "CONSUMER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data with no events
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "SERVER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: nil,
Tags: map[string]string{
"attr1": "42",
"attr2": "bar",
"otel.status_code": "ERROR",
"error": "404, file not found",
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
},
},
// model for span data with an "error" attribute set to "false"
{
SpanContext: zkmodel.SpanContext{
TraceID: zkmodel.TraceID{
High: 0x001020304050607,
Low: 0x8090a0b0c0d0e0f,
},
ID: zkmodel.ID(0xfffefdfcfbfaf9f8),
ParentID: zkmodelIDPtr(0x3f3e3d3c3b3a3938),
Debug: false,
Sampled: nil,
Err: nil,
},
Name: "foo",
Kind: "SERVER",
Timestamp: time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
Duration: time.Minute,
Shared: false,
LocalEndpoint: &zkmodel.Endpoint{
ServiceName: "model-test",
},
RemoteEndpoint: nil,
Annotations: []zkmodel.Annotation{
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
Value: `ev1: {"eventattr1":123}`,
},
{
Timestamp: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Value: "ev2",
},
},
Tags: map[string]string{
"service.name": "model-test",
"service.version": "0.1.0",
"resource-attr1": "42",
"resource-attr2": "[0,1,2]",
}, // only resource tags should be included
},
}
gottenOutputBatch := SpanModels(inputBatch)
require.Equal(t, expectedOutputBatch, gottenOutputBatch)
}
func zkmodelIDPtr(n uint64) *zkmodel.ID {
id := zkmodel.ID(n)
return &id
}
func TestTagsTransformation(t *testing.T) {
keyValue := "value"
doubleValue := 123.456
uintValue := int64(123)
statusMessage := "this is a problem"
instrLibName := "instrumentation-library"
instrLibVersion := "semver:1.0.0"
tests := []struct {
name string
data tracetest.SpanStub
want map[string]string
}{
{
name: "attributes",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{
attribute.String("key", keyValue),
attribute.Float64("double", doubleValue),
attribute.Int64("uint", uintValue),
attribute.Bool("ok", true),
},
},
want: map[string]string{
"double": fmt.Sprint(doubleValue),
"key": keyValue,
"ok": "true",
"uint": strconv.FormatInt(uintValue, 10),
},
},
{
name: "no attributes",
data: tracetest.SpanStub{},
want: nil,
},
{
name: "omit-noerror",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{
attribute.Bool("error", false),
},
},
want: nil,
},
{
name: "statusCode UNSET",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{
attribute.String("key", keyValue),
},
Status: tracesdk.Status{
Code: codes.Unset,
Description: "",
},
},
want: map[string]string{
"key": keyValue,
},
},
{
name: "statusCode OK",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{
attribute.String("key", keyValue),
attribute.Bool("ok", true),
},
Status: tracesdk.Status{
Code: codes.Ok,
Description: "",
},
},
want: map[string]string{
"key": keyValue,
"ok": "true",
"otel.status_code": "OK",
},
},
{
name: "statusCode ERROR",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{
attribute.String("key", keyValue),
attribute.Bool("error", true),
},
Status: tracesdk.Status{
Code: codes.Error,
Description: statusMessage,
},
},
want: map[string]string{
"error": statusMessage,
"key": keyValue,
"otel.status_code": "ERROR",
},
},
{
name: "instrLib-empty",
data: tracetest.SpanStub{
InstrumentationLibrary: instrumentation.Library{},
},
want: nil,
},
{
name: "instrLib-noversion",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{},
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
},
},
want: map[string]string{
"otel.library.name": instrLibName,
},
},
{
name: "instrLib-with-version",
data: tracetest.SpanStub{
Attributes: []attribute.KeyValue{},
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
Version: instrLibVersion,
},
},
want: map[string]string{
"otel.library.name": instrLibName,
"otel.library.version": instrLibVersion,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := toZipkinTags(tt.data.Snapshot())
if diff := cmp.Diff(got, tt.want); diff != "" {
t.Errorf("Diff%v", diff)
}
})
}
}
func TestRemoteEndpointTransformation(t *testing.T) {
tests := []struct {
name string
data tracetest.SpanStub
want *zkmodel.Endpoint
}{
{
name: "nil-not-applicable",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindClient,
Attributes: []attribute.KeyValue{},
},
want: nil,
},
{
name: "nil-not-found",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindConsumer,
Attributes: []attribute.KeyValue{
attribute.String("attr", "test"),
},
},
want: nil,
},
{
name: "peer-service-rank",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
semconv.PeerServiceKey.String("peer-service-test"),
semconv.NetPeerNameKey.String("peer-name-test"),
semconv.HTTPHostKey.String("http-host-test"),
},
},
want: &zkmodel.Endpoint{
ServiceName: "peer-service-test",
},
},
{
name: "http-host-rank",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
semconv.HTTPHostKey.String("http-host-test"),
semconv.DBNameKey.String("db-name-test"),
},
},
want: &zkmodel.Endpoint{
ServiceName: "http-host-test",
},
},
{
name: "db-name-rank",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
attribute.String("foo", "bar"),
semconv.DBNameKey.String("db-name-test"),
},
},
want: &zkmodel.Endpoint{
ServiceName: "db-name-test",
},
},
{
name: "peer-hostname-rank",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
keyPeerHostname.String("peer-hostname-test"),
keyPeerAddress.String("peer-address-test"),
semconv.HTTPHostKey.String("http-host-test"),
semconv.DBNameKey.String("http-host-test"),
},
},
want: &zkmodel.Endpoint{
ServiceName: "peer-hostname-test",
},
},
{
name: "peer-address-rank",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
keyPeerAddress.String("peer-address-test"),
semconv.HTTPHostKey.String("http-host-test"),
semconv.DBNameKey.String("http-host-test"),
},
},
want: &zkmodel.Endpoint{
ServiceName: "peer-address-test",
},
},
{
name: "net-peer-invalid-ip",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
semconv.NetPeerIPKey.String("INVALID"),
},
},
want: nil,
},
{
name: "net-peer-ipv6-no-port",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
semconv.NetPeerIPKey.String("0:0:1:5ee:bad:c0de:0:0"),
},
},
want: &zkmodel.Endpoint{
IPv6: net.ParseIP("0:0:1:5ee:bad:c0de:0:0"),
},
},
{
name: "net-peer-ipv4-port",
data: tracetest.SpanStub{
SpanKind: trace.SpanKindProducer,
Attributes: []attribute.KeyValue{
semconv.NetPeerIPKey.String("1.2.3.4"),
semconv.NetPeerPortKey.Int(9876),
},
},
want: &zkmodel.Endpoint{
IPv4: net.ParseIP("1.2.3.4"),
Port: 9876,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := toZipkinRemoteEndpoint(tt.data.Snapshot())
if diff := cmp.Diff(got, tt.want); diff != "" {
t.Errorf("Diff%v", diff)
}
})
}
}
func TestServiceName(t *testing.T) {
attrs := []attribute.KeyValue{}
assert.Equal(t, defaultServiceName, getServiceName(attrs))
attrs = append(attrs, attribute.String("test_key", "test_value"))
assert.Equal(t, defaultServiceName, getServiceName(attrs))
attrs = append(attrs, semconv.ServiceNameKey.String("my_service"))
assert.Equal(t, "my_service", getServiceName(attrs))
}