mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-01-30 04:40:41 +02:00
Populate Jaeger's Span.Process from Resource (#1673)
* Jaeger exporter now populate Jaeger's Span Process from Resource * Remove jaeger.WithProcess * Fix tests * Change the type of default service name into string * Add tests * Update CHANGELOG * Use the API from `Set` to fetch service name in exporter * Fix nits * Add more test cases for jaegerBatchList function * precommit Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
This commit is contained in:
parent
28eaaa9a91
commit
62cbf0f240
@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- Added `Marshaler` config option to `otlphttp` to enable otlp over json or protobufs. (#1586)
|
||||
- A `ForceFlush` method to the `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` to flush all registered `SpanProcessor`s. (#1608)
|
||||
- Added `WithDefaultSampler` and `WithSpanLimits` to tracer provider. (#1633)
|
||||
- Jaeger exporter falls back to `resource.Default`'s `service.name` if the exported Span does not have one. (#1673)
|
||||
|
||||
### Changed
|
||||
|
||||
@ -25,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- `trace.SpanContext` is now immutable and has no exported fields. (#1573)
|
||||
- `trace.NewSpanContext()` can be used in conjunction with the `trace.SpanContextConfig` struct to initialize a new `SpanContext` where all values are known.
|
||||
- Renamed the `LabelSet` method of `"go.opentelemetry.io/otel/sdk/resource".Resource` to `Set`. (#1692)
|
||||
- Jaeger exporter populates Jaeger's Span Process from Resource. (#1673)
|
||||
|
||||
### Removed
|
||||
|
||||
@ -33,6 +35,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
These are now returned as a SpanProcessor interface from their respective constructors. (#1638)
|
||||
- Removed setting status to `Error` while recording an error as a span event in `RecordError`. (#1663)
|
||||
- Removed `WithConfig` from tracer provider to avoid overriding configuration. (#1633)
|
||||
- Removed `jaeger.WithProcess`. (#1673)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -8,7 +8,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
|
@ -21,6 +21,8 @@ import (
|
||||
"log"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/semconv"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/trace/jaeger"
|
||||
@ -32,14 +34,14 @@ func initTracer() func() {
|
||||
// Create and install Jaeger export pipeline.
|
||||
flush, err := jaeger.InstallNewPipeline(
|
||||
jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"),
|
||||
jaeger.WithProcess(jaeger.Process{
|
||||
ServiceName: "trace-demo",
|
||||
Tags: []attribute.KeyValue{
|
||||
jaeger.WithSDK(&sdktrace.Config{
|
||||
DefaultSampler: sdktrace.AlwaysSample(),
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("trace-demo"),
|
||||
attribute.String("exporter", "jaeger"),
|
||||
attribute.Float64("float", 312.23),
|
||||
},
|
||||
),
|
||||
}),
|
||||
jaeger.WithSDK(&sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -63,6 +65,7 @@ func main() {
|
||||
func bar(ctx context.Context) {
|
||||
tr := otel.Tracer("component-bar")
|
||||
_, span := tr.Start(ctx, "bar")
|
||||
span.SetAttributes(attribute.Key("testset").String("value"))
|
||||
defer span.End()
|
||||
|
||||
// Do bar...
|
||||
|
@ -234,8 +234,8 @@ func TestNewRawExporterWithEnv(t *testing.T) {
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, exp.o.Disabled)
|
||||
assert.EqualValues(t, serviceName, exp.process.ServiceName)
|
||||
assert.Len(t, exp.process.Tags, 1)
|
||||
assert.EqualValues(t, serviceName, exp.o.Process.ServiceName)
|
||||
assert.Len(t, exp.o.Process.Tags, 1)
|
||||
|
||||
require.IsType(t, &collectorUploader{}, exp.uploader)
|
||||
uploader := exp.uploader.(*collectorUploader)
|
||||
@ -276,8 +276,8 @@ func TestNewRawExporterWithEnvImplicitly(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
// NewRawExporter will ignore Disabled env
|
||||
assert.Equal(t, true, exp.o.Disabled)
|
||||
assert.EqualValues(t, serviceName, exp.process.ServiceName)
|
||||
assert.Len(t, exp.process.Tags, 1)
|
||||
assert.EqualValues(t, serviceName, exp.o.Process.ServiceName)
|
||||
assert.Len(t, exp.o.Process.Tags, 1)
|
||||
|
||||
require.IsType(t, &collectorUploader{}, exp.uploader)
|
||||
uploader := exp.uploader.(*collectorUploader)
|
||||
|
@ -28,13 +28,13 @@ import (
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger"
|
||||
export "go.opentelemetry.io/otel/sdk/export/trace"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
"go.opentelemetry.io/otel/semconv"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultServiceName = "OpenTelemetry"
|
||||
|
||||
keyInstrumentationLibraryName = "otel.library.name"
|
||||
keyInstrumentationLibraryVersion = "otel.library.version"
|
||||
)
|
||||
@ -57,13 +57,6 @@ type options struct {
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
// WithProcess sets the process with the information about the exporting process.
|
||||
func WithProcess(process Process) Option {
|
||||
return func(o *options) {
|
||||
o.Process = process
|
||||
}
|
||||
}
|
||||
|
||||
// WithBufferMaxCount defines the total number of traces that can be buffered in memory
|
||||
func WithBufferMaxCount(bufferMaxCount int) Option {
|
||||
return func(o *options) {
|
||||
@ -109,27 +102,24 @@ func NewRawExporter(endpointOption EndpointOption, opts ...Option) (*Exporter, e
|
||||
opt(&o)
|
||||
}
|
||||
|
||||
service := o.Process.ServiceName
|
||||
if service == "" {
|
||||
service = defaultServiceName
|
||||
}
|
||||
tags := make([]*gen.Tag, 0, len(o.Process.Tags))
|
||||
for _, tag := range o.Process.Tags {
|
||||
t := keyValueToTag(tag)
|
||||
if t != nil {
|
||||
tags = append(tags, t)
|
||||
// Fetch default service.name from default resource for backup
|
||||
var defaultServiceName string
|
||||
defaultResource := resource.Default()
|
||||
if value, exists := defaultResource.Set().Value(semconv.ServiceNameKey); exists {
|
||||
defaultServiceName = value.AsString()
|
||||
}
|
||||
if defaultServiceName == "" {
|
||||
return nil, fmt.Errorf("failed to get service name from default resource")
|
||||
}
|
||||
|
||||
e := &Exporter{
|
||||
uploader: uploader,
|
||||
process: &gen.Process{
|
||||
ServiceName: service,
|
||||
Tags: tags,
|
||||
},
|
||||
o: o,
|
||||
defaultServiceName: defaultServiceName,
|
||||
resourceFromProcess: processToResource(o.Process),
|
||||
}
|
||||
bundler := bundler.NewBundler((*gen.Span)(nil), func(bundle interface{}) {
|
||||
if err := e.upload(bundle.([]*gen.Span)); err != nil {
|
||||
bundler := bundler.NewBundler((*export.SpanSnapshot)(nil), func(bundle interface{}) {
|
||||
if err := e.upload(bundle.([]*export.SpanSnapshot)); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
})
|
||||
@ -205,13 +195,15 @@ type Process struct {
|
||||
// Exporter is an implementation of an OTel SpanSyncer that uploads spans to
|
||||
// Jaeger.
|
||||
type Exporter struct {
|
||||
process *gen.Process
|
||||
bundler *bundler.Bundler
|
||||
uploader batchUploader
|
||||
o options
|
||||
|
||||
stoppedMu sync.RWMutex
|
||||
stopped bool
|
||||
|
||||
defaultServiceName string
|
||||
resourceFromProcess *resource.Resource
|
||||
}
|
||||
|
||||
var _ export.SpanExporter = (*Exporter)(nil)
|
||||
@ -227,7 +219,7 @@ func (e *Exporter) ExportSpans(ctx context.Context, ss []*export.SpanSnapshot) e
|
||||
|
||||
for _, span := range ss {
|
||||
// TODO(jbd): Handle oversized bundlers.
|
||||
err := e.bundler.Add(spanSnapshotToThrift(span), 1)
|
||||
err := e.bundler.Add(span, 1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to bundle %q: %w", span.Name, err)
|
||||
}
|
||||
@ -275,17 +267,6 @@ func spanSnapshotToThrift(ss *export.SpanSnapshot) *gen.Span {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (jmacd): OTel has a broad "last value wins"
|
||||
// semantic. Should resources be appended before span
|
||||
// attributes, above, to allow span attributes to
|
||||
// overwrite resource attributes?
|
||||
if ss.Resource != nil {
|
||||
for iter := ss.Resource.Iter(); iter.Next(); {
|
||||
if tag := keyValueToTag(iter.Attribute()); tag != nil {
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
if il := ss.InstrumentationLibrary; il.Name != "" {
|
||||
tags = append(tags, getStringTag(keyInstrumentationLibraryName, il.Name))
|
||||
if il.Version != "" {
|
||||
@ -429,11 +410,94 @@ func (e *Exporter) Flush() {
|
||||
flush(e)
|
||||
}
|
||||
|
||||
func (e *Exporter) upload(spans []*gen.Span) error {
|
||||
batch := &gen.Batch{
|
||||
Spans: spans,
|
||||
Process: e.process,
|
||||
func (e *Exporter) upload(spans []*export.SpanSnapshot) error {
|
||||
batchList := jaegerBatchList(spans, e.defaultServiceName, e.resourceFromProcess)
|
||||
for _, batch := range batchList {
|
||||
err := e.uploader.upload(batch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return e.uploader.upload(batch)
|
||||
return nil
|
||||
}
|
||||
|
||||
// jaegerBatchList transforms a slice of SpanSnapshot into a slice of jaeger
|
||||
// Batch.
|
||||
func jaegerBatchList(ssl []*export.SpanSnapshot, defaultServiceName string, resourceFromProcess *resource.Resource) []*gen.Batch {
|
||||
if len(ssl) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
batchDict := make(map[attribute.Distinct]*gen.Batch)
|
||||
|
||||
for _, ss := range ssl {
|
||||
if ss == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
newResource := ss.Resource
|
||||
if resourceFromProcess != nil {
|
||||
// The value from process will overwrite the value from span's resources
|
||||
newResource = resource.Merge(ss.Resource, resourceFromProcess)
|
||||
}
|
||||
resourceKey := newResource.Equivalent()
|
||||
batch, bOK := batchDict[resourceKey]
|
||||
if !bOK {
|
||||
batch = &gen.Batch{
|
||||
Process: process(newResource, defaultServiceName),
|
||||
Spans: []*gen.Span{},
|
||||
}
|
||||
}
|
||||
batch.Spans = append(batch.Spans, spanSnapshotToThrift(ss))
|
||||
batchDict[resourceKey] = batch
|
||||
}
|
||||
|
||||
// Transform the categorized map into a slice
|
||||
batchList := make([]*gen.Batch, 0, len(batchDict))
|
||||
for _, batch := range batchDict {
|
||||
batchList = append(batchList, batch)
|
||||
}
|
||||
return batchList
|
||||
}
|
||||
|
||||
// process transforms an OTel Resource into a jaeger Process.
|
||||
func process(res *resource.Resource, defaultServiceName string) *gen.Process {
|
||||
var process gen.Process
|
||||
|
||||
var serviceName attribute.KeyValue
|
||||
if res != nil {
|
||||
for iter := res.Iter(); iter.Next(); {
|
||||
if iter.Attribute().Key == semconv.ServiceNameKey {
|
||||
serviceName = iter.Attribute()
|
||||
// Don't convert service.name into tag.
|
||||
continue
|
||||
}
|
||||
if tag := keyValueToTag(iter.Attribute()); tag != nil {
|
||||
process.Tags = append(process.Tags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no service.name is contained in a Span's Resource,
|
||||
// that field MUST be populated from the default Resource.
|
||||
if serviceName.Value.AsString() == "" {
|
||||
serviceName = semconv.ServiceVersionKey.String(defaultServiceName)
|
||||
}
|
||||
process.ServiceName = serviceName.Value.AsString()
|
||||
|
||||
return &process
|
||||
}
|
||||
|
||||
func processToResource(process Process) *resource.Resource {
|
||||
var attrs []attribute.KeyValue
|
||||
if process.ServiceName != "" {
|
||||
attrs = append(attrs, semconv.ServiceNameKey.String(process.ServiceName))
|
||||
}
|
||||
attrs = append(attrs, process.Tags...)
|
||||
|
||||
if len(attrs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return resource.NewWithAttributes(attrs...)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -36,6 +37,7 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
"go.opentelemetry.io/otel/semconv"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
@ -185,32 +187,14 @@ func TestNewRawExporter(t *testing.T) {
|
||||
{
|
||||
name: "default exporter",
|
||||
endpoint: WithCollectorEndpoint(collectorEndpoint),
|
||||
expectedServiceName: defaultServiceName,
|
||||
expectedServiceName: "unknown_service",
|
||||
expectedBufferMaxCount: bundler.DefaultBufferedByteLimit,
|
||||
expectedBatchMaxCount: bundler.DefaultBundleCountThreshold,
|
||||
},
|
||||
{
|
||||
name: "default exporter with agent endpoint",
|
||||
endpoint: WithAgentEndpoint(agentEndpoint),
|
||||
expectedServiceName: defaultServiceName,
|
||||
expectedBufferMaxCount: bundler.DefaultBufferedByteLimit,
|
||||
expectedBatchMaxCount: bundler.DefaultBundleCountThreshold,
|
||||
},
|
||||
{
|
||||
name: "with process",
|
||||
endpoint: WithCollectorEndpoint(collectorEndpoint),
|
||||
options: []Option{
|
||||
WithProcess(
|
||||
Process{
|
||||
ServiceName: "jaeger-test",
|
||||
Tags: []attribute.KeyValue{
|
||||
attribute.String("key", "val"),
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
expectedServiceName: "jaeger-test",
|
||||
expectedTagsLen: 1,
|
||||
expectedServiceName: "unknown_service",
|
||||
expectedBufferMaxCount: bundler.DefaultBufferedByteLimit,
|
||||
expectedBatchMaxCount: bundler.DefaultBundleCountThreshold,
|
||||
},
|
||||
@ -218,15 +202,10 @@ func TestNewRawExporter(t *testing.T) {
|
||||
name: "with buffer and batch max count",
|
||||
endpoint: WithCollectorEndpoint(collectorEndpoint),
|
||||
options: []Option{
|
||||
WithProcess(
|
||||
Process{
|
||||
ServiceName: "jaeger-test",
|
||||
},
|
||||
),
|
||||
WithBufferMaxCount(99),
|
||||
WithBatchMaxCount(99),
|
||||
},
|
||||
expectedServiceName: "jaeger-test",
|
||||
expectedServiceName: "unknown_service",
|
||||
expectedBufferMaxCount: 99,
|
||||
expectedBatchMaxCount: 99,
|
||||
},
|
||||
@ -240,10 +219,10 @@ func TestNewRawExporter(t *testing.T) {
|
||||
)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedServiceName, exp.process.ServiceName)
|
||||
assert.Len(t, exp.process.Tags, tc.expectedTagsLen)
|
||||
assert.Equal(t, tc.expectedBufferMaxCount, exp.bundler.BufferedByteLimit)
|
||||
assert.Equal(t, tc.expectedBatchMaxCount, exp.bundler.BundleCountThreshold)
|
||||
assert.NotEmpty(t, exp.defaultServiceName)
|
||||
assert.True(t, strings.HasPrefix(exp.defaultServiceName, tc.expectedServiceName))
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -327,11 +306,11 @@ func TestExporter_ExportSpan(t *testing.T) {
|
||||
// Create Jaeger Exporter
|
||||
exp, err := NewRawExporter(
|
||||
withTestCollectorEndpoint(),
|
||||
WithProcess(Process{
|
||||
ServiceName: serviceName,
|
||||
Tags: []attribute.KeyValue{
|
||||
WithSDK(&sdktrace.Config{
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String(serviceName),
|
||||
attribute.String(tagKey, tagVal),
|
||||
},
|
||||
),
|
||||
}),
|
||||
)
|
||||
|
||||
@ -409,7 +388,6 @@ func Test_spanSnapshotToThrift(t *testing.T) {
|
||||
StatusCode: codes.Error,
|
||||
StatusMessage: statusMessage,
|
||||
SpanKind: trace.SpanKindClient,
|
||||
Resource: resource.NewWithAttributes(attribute.String("rk1", rv1), attribute.Int64("rk2", rv2)),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: instrLibName,
|
||||
Version: instrLibVersion,
|
||||
@ -432,8 +410,6 @@ func Test_spanSnapshotToThrift(t *testing.T) {
|
||||
{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},
|
||||
{Key: "rk1", VType: gen.TagType_STRING, VStr: &rv1},
|
||||
{Key: "rk2", VType: gen.TagType_LONG, VLong: &rv2},
|
||||
},
|
||||
References: []*gen.SpanRef{
|
||||
{
|
||||
@ -516,6 +492,44 @@ func Test_spanSnapshotToThrift(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resources do not affect the tags",
|
||||
data: &export.SpanSnapshot{
|
||||
ParentSpanID: parentSpanID,
|
||||
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
}),
|
||||
Name: "/foo",
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
Resource: resource.NewWithAttributes(
|
||||
attribute.String("rk1", rv1),
|
||||
attribute.Int64("rk2", rv2),
|
||||
semconv.ServiceNameKey.String("service name"),
|
||||
),
|
||||
StatusCode: codes.Unset,
|
||||
StatusMessage: statusMessage,
|
||||
SpanKind: trace.SpanKindInternal,
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: instrLibName,
|
||||
Version: instrLibVersion,
|
||||
},
|
||||
},
|
||||
want: &gen.Span{
|
||||
TraceIdLow: 651345242494996240,
|
||||
TraceIdHigh: 72623859790382856,
|
||||
SpanId: 72623859790382856,
|
||||
ParentSpanId: 578437695752307201,
|
||||
OperationName: "/foo",
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
Duration: 0,
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "otel.library.name", VType: gen.TagType_STRING, VStr: &instrLibName},
|
||||
{Key: "otel.library.version", VType: gen.TagType_STRING, VStr: &instrLibVersion},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@ -579,3 +593,296 @@ func TestErrorOnExportShutdownExporter(t *testing.T) {
|
||||
assert.NoError(t, e.Shutdown(context.Background()))
|
||||
assert.NoError(t, e.ExportSpans(context.Background(), nil))
|
||||
}
|
||||
|
||||
func TestJaegerBatchList(t *testing.T) {
|
||||
newString := func(value string) *string {
|
||||
return &value
|
||||
}
|
||||
spanKind := "unspecified"
|
||||
now := time.Now()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
spanSnapshotList []*export.SpanSnapshot
|
||||
defaultServiceName string
|
||||
resourceFromProcess *resource.Resource
|
||||
expectedBatchList []*gen.Batch
|
||||
}{
|
||||
{
|
||||
name: "no span shots",
|
||||
spanSnapshotList: nil,
|
||||
expectedBatchList: nil,
|
||||
},
|
||||
{
|
||||
name: "span's snapshot contains nil span",
|
||||
spanSnapshotList: []*export.SpanSnapshot{
|
||||
{
|
||||
Name: "s1",
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("name"),
|
||||
attribute.Key("r1").String("v1"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
expectedBatchList: []*gen.Batch{
|
||||
{
|
||||
Process: &gen.Process{
|
||||
ServiceName: "name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: newString("v1")},
|
||||
},
|
||||
},
|
||||
Spans: []*gen.Span{
|
||||
{
|
||||
OperationName: "s1",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "merge spans that have the same resources",
|
||||
spanSnapshotList: []*export.SpanSnapshot{
|
||||
{
|
||||
Name: "s1",
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("name"),
|
||||
attribute.Key("r1").String("v1"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
{
|
||||
Name: "s2",
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("name"),
|
||||
attribute.Key("r1").String("v1"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
{
|
||||
Name: "s3",
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("name"),
|
||||
attribute.Key("r2").String("v2"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
},
|
||||
expectedBatchList: []*gen.Batch{
|
||||
{
|
||||
Process: &gen.Process{
|
||||
ServiceName: "name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: newString("v1")},
|
||||
},
|
||||
},
|
||||
Spans: []*gen.Span{
|
||||
{
|
||||
OperationName: "s1",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
{
|
||||
OperationName: "s2",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Process: &gen.Process{
|
||||
ServiceName: "name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r2", VType: gen.TagType_STRING, VStr: newString("v2")},
|
||||
},
|
||||
},
|
||||
Spans: []*gen.Span{
|
||||
{
|
||||
OperationName: "s3",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "merge resources that come from process",
|
||||
spanSnapshotList: []*export.SpanSnapshot{
|
||||
{
|
||||
Name: "s1",
|
||||
Resource: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("name"),
|
||||
attribute.Key("r1").String("v1"),
|
||||
attribute.Key("r2").String("v2"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
},
|
||||
resourceFromProcess: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("new-name"),
|
||||
attribute.Key("r1").String("v2"),
|
||||
),
|
||||
expectedBatchList: []*gen.Batch{
|
||||
{
|
||||
Process: &gen.Process{
|
||||
ServiceName: "new-name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: newString("v2")},
|
||||
{Key: "r2", VType: gen.TagType_STRING, VStr: newString("v2")},
|
||||
},
|
||||
},
|
||||
Spans: []*gen.Span{
|
||||
{
|
||||
OperationName: "s1",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "span's snapshot contains no service name but resourceFromProcess does",
|
||||
spanSnapshotList: []*export.SpanSnapshot{
|
||||
{
|
||||
Name: "s1",
|
||||
Resource: resource.NewWithAttributes(
|
||||
attribute.Key("r1").String("v1"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
resourceFromProcess: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("new-name"),
|
||||
),
|
||||
expectedBatchList: []*gen.Batch{
|
||||
{
|
||||
Process: &gen.Process{
|
||||
ServiceName: "new-name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: newString("v1")},
|
||||
},
|
||||
},
|
||||
Spans: []*gen.Span{
|
||||
{
|
||||
OperationName: "s1",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no service name in spans and resourceFromProcess",
|
||||
spanSnapshotList: []*export.SpanSnapshot{
|
||||
{
|
||||
Name: "s1",
|
||||
Resource: resource.NewWithAttributes(
|
||||
attribute.Key("r1").String("v1"),
|
||||
),
|
||||
StartTime: now,
|
||||
EndTime: now,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
defaultServiceName: "default service name",
|
||||
expectedBatchList: []*gen.Batch{
|
||||
{
|
||||
Process: &gen.Process{
|
||||
ServiceName: "default service name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: newString("v1")},
|
||||
},
|
||||
},
|
||||
Spans: []*gen.Span{
|
||||
{
|
||||
OperationName: "s1",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "span.kind", VType: gen.TagType_STRING, VStr: &spanKind},
|
||||
},
|
||||
StartTime: now.UnixNano() / 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
batchList := jaegerBatchList(tc.spanSnapshotList, tc.defaultServiceName, tc.resourceFromProcess)
|
||||
|
||||
assert.ElementsMatch(t, tc.expectedBatchList, batchList)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcess(t *testing.T) {
|
||||
v1 := "v1"
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
res *resource.Resource
|
||||
defaultServiceName string
|
||||
expectedProcess *gen.Process
|
||||
}{
|
||||
{
|
||||
name: "resources contain service name",
|
||||
res: resource.NewWithAttributes(
|
||||
semconv.ServiceNameKey.String("service name"),
|
||||
attribute.Key("r1").String("v1"),
|
||||
),
|
||||
defaultServiceName: "default service name",
|
||||
expectedProcess: &gen.Process{
|
||||
ServiceName: "service name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: &v1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resources don't have service name",
|
||||
res: resource.NewWithAttributes(attribute.Key("r1").String("v1")),
|
||||
defaultServiceName: "default service name",
|
||||
expectedProcess: &gen.Process{
|
||||
ServiceName: "default service name",
|
||||
Tags: []*gen.Tag{
|
||||
{Key: "r1", VType: gen.TagType_STRING, VStr: &v1},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
pro := process(tc.res, tc.defaultServiceName)
|
||||
|
||||
assert.Equal(t, tc.expectedProcess, pro)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user