Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add InstrumentationLibrary info to Zipkin/Jaeger exporters #1119

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -12,13 +12,15 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- In the `go.opentelemetry.io/otel/api/trace` package a new `TracerConfigure` function was added to configure a new `TracerConfig`.
This addition was made to conform with our project option conventions. (#1109)
- Instrumentation library information was added to the Zipkin exporter. (#1119)

### Changed

- Add reconnecting udp connection type to Jaeger exporter.
This change adds a new optional implementation of the udp conn interface used to detect changes to an agent's host dns record.
It then adopts the new destination address to ensure the exporter doesn't get stuck. This change was ported from jaegertracing/jaeger-client-go#520. (#1063)
- The `go.opentelemetry.io/otel/api/trace` `TracerOption` was changed to an interface to conform to project option conventions. (#1109)
- Rename Jaeger tags used for instrumentation library information to reflect changes in OpenTelemetry specification. (#1119)

## [0.11.0] - 2020-08-24

Expand Down
12 changes: 8 additions & 4 deletions exporters/trace/jaeger/jaeger.go
Expand Up @@ -29,7 +29,12 @@ import (
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

const defaultServiceName = "OpenTelemetry"
const (
defaultServiceName = "OpenTelemetry"

keyInstrumentationLibraryName = "otel.instrumentation_library.name"
keyInstrumentationLibraryVersion = "otel.instrumentation_library.version"
)

type Option func(*options)

Expand Down Expand Up @@ -228,11 +233,10 @@ func spanDataToThrift(data *export.SpanData) *gen.Span {
}
}
}

if il := data.InstrumentationLibrary; il.Name != "" {
tags = append(tags, getStringTag("instrumentation.name", il.Name))
tags = append(tags, getStringTag(keyInstrumentationLibraryName, il.Name))
if il.Version != "" {
tags = append(tags, getStringTag("instrumentation.version", il.Version))
tags = append(tags, getStringTag(keyInstrumentationLibraryVersion, il.Version))
}
}

Expand Down
4 changes: 2 additions & 2 deletions exporters/trace/jaeger/jaeger_test.go
Expand Up @@ -430,8 +430,8 @@ func Test_spanDataToThrift(t *testing.T) {
{Key: "key", VType: gen.TagType_STRING, VStr: &keyValue},
{Key: "uint", VType: gen.TagType_LONG, VLong: &uintValue},
{Key: "error", VType: gen.TagType_BOOL, VBool: &boolTrue},
{Key: "instrumentation.name", VType: gen.TagType_STRING, VStr: &instrLibName},
{Key: "instrumentation.version", VType: gen.TagType_STRING, VStr: &instrLibVersion},
{Key: "otel.instrumentation_library.name", VType: gen.TagType_STRING, VStr: &instrLibName},
{Key: "otel.instrumentation_library.version", VType: gen.TagType_STRING, VStr: &instrLibVersion},
{Key: "status.code", VType: gen.TagType_LONG, VLong: &statusCodeValue},
{Key: "status.message", VType: gen.TagType_STRING, VStr: &statusMessage},
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
Expand Down
1 change: 1 addition & 0 deletions exporters/trace/zipkin/go.mod
Expand Up @@ -8,6 +8,7 @@ replace (
)

require (
github.com/google/go-cmp v0.5.2
github.com/openzipkin/zipkin-go v0.2.3
github.com/stretchr/testify v1.6.1
go.opentelemetry.io/otel v0.11.0
Expand Down
23 changes: 21 additions & 2 deletions exporters/trace/zipkin/model.go
Expand Up @@ -26,6 +26,11 @@ import (
export "go.opentelemetry.io/otel/sdk/export/trace"
)

const (
keyInstrumentationLibraryName = "otel.instrumentation_library.name"
keyInstrumentationLibraryVersion = "otel.instrumentation_library.version"
)

func toZipkinSpanModels(batch []*export.SpanData, serviceName string) []zkmodel.SpanModel {
models := make([]zkmodel.SpanModel, 0, len(batch))
for _, data := range batch {
Expand Down Expand Up @@ -132,9 +137,16 @@ func attributesToJSONMapString(attributes []label.KeyValue) string {
return (string)(jsonBytes)
}

// extraZipkinTags are those that may be added to every outgoing span
var extraZipkinTags = []string{
"ot.status_code",
"ot.status_description",
keyInstrumentationLibraryName,
keyInstrumentationLibraryVersion,
}

func toZipkinTags(data *export.SpanData) map[string]string {
// +2 for status code and for status message
m := make(map[string]string, len(data.Attributes)+2)
m := make(map[string]string, len(data.Attributes)+len(extraZipkinTags))
for _, kv := range data.Attributes {
m[(string)(kv.Key)] = kv.Value.Emit()
}
Expand All @@ -143,5 +155,12 @@ func toZipkinTags(data *export.SpanData) map[string]string {
}
m["ot.status_code"] = data.StatusCode.String()
m["ot.status_description"] = data.StatusMessage

if il := data.InstrumentationLibrary; il.Name != "" {
m[keyInstrumentationLibraryName] = il.Name
if il.Version != "" {
m[keyInstrumentationLibraryVersion] = il.Version
}
}
return m
}
124 changes: 124 additions & 0 deletions exporters/trace/zipkin/model_test.go
Expand Up @@ -15,16 +15,20 @@
package zipkin

import (
"fmt"
"strconv"
"testing"
"time"

"github.com/google/go-cmp/cmp"
zkmodel "github.com/openzipkin/zipkin-go/model"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"

"go.opentelemetry.io/otel/api/trace"
"go.opentelemetry.io/otel/label"
export "go.opentelemetry.io/otel/sdk/export/trace"
"go.opentelemetry.io/otel/sdk/instrumentation"
)

func TestModelConversion(t *testing.T) {
Expand Down Expand Up @@ -656,3 +660,123 @@ func zkmodelIDPtr(n uint64) *zkmodel.ID {
id := zkmodel.ID(n)
return &id
}

func Test_toZipkinTags(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 *export.SpanData
want map[string]string
}{
{
name: "attributes",
data: &export.SpanData{
Attributes: []label.KeyValue{
label.String("key", keyValue),
label.Float64("double", doubleValue),
label.Uint64("uint", uint64(uintValue)),
label.Bool("ok", true),
},
},
want: map[string]string{
"double": fmt.Sprint(doubleValue),
"key": keyValue,
"ok": "true",
"uint": strconv.FormatInt(uintValue, 10),
"ot.status_code": codes.OK.String(),
"ot.status_description": "",
},
},
{
name: "no attributes",
data: &export.SpanData{},
want: map[string]string{
"ot.status_code": codes.OK.String(),
"ot.status_description": "",
},
},
{
name: "omit-noerror",
data: &export.SpanData{
Attributes: []label.KeyValue{
label.Bool("error", false),
},
},
want: map[string]string{
"ot.status_code": codes.OK.String(),
"ot.status_description": "",
},
},
{
name: "statusCode",
data: &export.SpanData{
Attributes: []label.KeyValue{
label.String("key", keyValue),
label.Bool("error", true),
},
StatusCode: codes.Unknown,
StatusMessage: statusMessage,
},
want: map[string]string{
"error": "true",
"key": keyValue,
"ot.status_code": codes.Unknown.String(),
"ot.status_description": statusMessage,
},
},
{
name: "instrLib-empty",
data: &export.SpanData{
InstrumentationLibrary: instrumentation.Library{},
},
want: map[string]string{
"ot.status_code": codes.OK.String(),
"ot.status_description": "",
},
},
{
name: "instrLib-noversion",
data: &export.SpanData{
Attributes: []label.KeyValue{},
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
},
},
want: map[string]string{
"otel.instrumentation_library.name": instrLibName,
"ot.status_code": codes.OK.String(),
"ot.status_description": "",
},
},
{
name: "instrLib-with-version",
data: &export.SpanData{
Attributes: []label.KeyValue{},
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
Version: instrLibVersion,
},
},
want: map[string]string{
"otel.instrumentation_library.name": instrLibName,
"otel.instrumentation_library.version": instrLibVersion,
"ot.status_code": codes.OK.String(),
"ot.status_description": "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := toZipkinTags(tt.data)
if diff := cmp.Diff(got, tt.want); diff != "" {
t.Errorf("Diff%v", diff)
}
})
}
}