You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-11-23 22:34:47 +02:00
api(trace): change SpanID to byte array (#241)
* api(trace): change SpanID to byte array * fix doc and create const errors
This commit is contained in:
committed by
rghetia
parent
d9c4aa5cee
commit
4e545e2ab8
@@ -18,8 +18,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -30,25 +28,89 @@ const (
|
|||||||
// for SpanContext TraceFlags field when a trace is sampled.
|
// for SpanContext TraceFlags field when a trace is sampled.
|
||||||
TraceFlagsSampled = traceFlagsBitMaskSampled
|
TraceFlagsSampled = traceFlagsBitMaskSampled
|
||||||
TraceFlagsUnused = traceFlagsBitMaskUnused
|
TraceFlagsUnused = traceFlagsBitMaskUnused
|
||||||
|
|
||||||
|
ErrInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase"
|
||||||
|
|
||||||
|
ErrInvalidTraceIDLength errorConst = "hex encoded trace-id must have length equals to 32"
|
||||||
|
ErrNilTraceID errorConst = "trace-id can't be all zero"
|
||||||
|
|
||||||
|
ErrInvalidSpanIDLength errorConst = "hex encoded span-id must have length equals to 16"
|
||||||
|
ErrNilSpanID errorConst = "span-id can't be all zero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type errorConst string
|
||||||
|
|
||||||
|
func (e errorConst) Error() string {
|
||||||
|
return string(e)
|
||||||
|
}
|
||||||
|
|
||||||
type TraceID [16]byte
|
type TraceID [16]byte
|
||||||
|
|
||||||
var nilTraceID TraceID
|
var nilTraceID TraceID
|
||||||
|
var _ json.Marshaler = nilTraceID
|
||||||
|
|
||||||
func (t TraceID) isValid() bool {
|
func (t TraceID) IsValid() bool {
|
||||||
return !bytes.Equal(t[:], nilTraceID[:])
|
return !bytes.Equal(t[:], nilTraceID[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements a custom marshal function to encode TraceID as a hex string
|
||||||
|
func (t TraceID) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(hex.EncodeToString(t[:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpanID [8]byte
|
||||||
|
|
||||||
|
var nilSpanID SpanID
|
||||||
|
var _ json.Marshaler = nilSpanID
|
||||||
|
|
||||||
|
func (s SpanID) IsValid() bool {
|
||||||
|
return !bytes.Equal(s[:], nilSpanID[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements a custom marshal function to encode SpanID as a hex string
|
||||||
|
func (s SpanID) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(hex.EncodeToString(s[:]))
|
||||||
|
}
|
||||||
|
|
||||||
// TraceIDFromHex returns a TraceID from a hex string if it is compliant
|
// TraceIDFromHex returns a TraceID from a hex string if it is compliant
|
||||||
// with the w3c trace-context specification.
|
// with the w3c trace-context specification.
|
||||||
// See more at https://www.w3.org/TR/trace-context/#trace-id
|
// See more at https://www.w3.org/TR/trace-context/#trace-id
|
||||||
func TraceIDFromHex(h string) (TraceID, error) {
|
func TraceIDFromHex(h string) (TraceID, error) {
|
||||||
t := TraceID{}
|
t := TraceID{}
|
||||||
if len(h) != 32 {
|
if len(h) != 32 {
|
||||||
return t, errors.New("hex encoded trace-id must have length equals to 32")
|
return t, ErrInvalidTraceIDLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := decodeHex(h, t[:]); err != nil {
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !t.IsValid() {
|
||||||
|
return t, ErrNilTraceID
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpanIDFromHex returns a SpanID from a hex string if it is compliant
|
||||||
|
// with the w3c trace-context specification.
|
||||||
|
// See more at https://www.w3.org/TR/trace-context/#parent-id
|
||||||
|
func SpanIDFromHex(h string) (SpanID, error) {
|
||||||
|
s := SpanID{}
|
||||||
|
if len(h) != 16 {
|
||||||
|
return s, ErrInvalidSpanIDLength
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := decodeHex(h, s[:]); err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.IsValid() {
|
||||||
|
return s, ErrNilSpanID
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeHex(h string, b []byte) error {
|
||||||
for _, r := range h {
|
for _, r := range h {
|
||||||
switch {
|
switch {
|
||||||
case 'a' <= r && r <= 'f':
|
case 'a' <= r && r <= 'f':
|
||||||
@@ -56,65 +118,45 @@ func TraceIDFromHex(h string) (TraceID, error) {
|
|||||||
case '0' <= r && r <= '9':
|
case '0' <= r && r <= '9':
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
return t, errors.New("trace-id can only contain [0-9a-f] characters, all lowercase")
|
return ErrInvalidHexID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := hex.DecodeString(h)
|
decoded, err := hex.DecodeString(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return t, err
|
return err
|
||||||
}
|
}
|
||||||
copy(t[:], b)
|
|
||||||
|
|
||||||
if !t.isValid() {
|
copy(b[:], decoded)
|
||||||
return t, errors.New("trace-id can't be all zero")
|
return nil
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SpanContext struct {
|
type SpanContext struct {
|
||||||
TraceID TraceID
|
TraceID TraceID
|
||||||
SpanID uint64
|
SpanID SpanID
|
||||||
TraceFlags byte
|
TraceFlags byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ json.Marshaler = (*SpanContext)(nil)
|
|
||||||
|
|
||||||
// EmptySpanContext is meant for internal use to return invalid span context during error conditions.
|
// EmptySpanContext is meant for internal use to return invalid span context during error conditions.
|
||||||
func EmptySpanContext() SpanContext {
|
func EmptySpanContext() SpanContext {
|
||||||
return SpanContext{}
|
return SpanContext{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements a custom marshal function to encode SpanContext
|
|
||||||
// in a human readable format with hex encoded TraceID and SpanID.
|
|
||||||
func (sc SpanContext) MarshalJSON() ([]byte, error) {
|
|
||||||
type JSONSpanContext struct {
|
|
||||||
TraceID string
|
|
||||||
SpanID string
|
|
||||||
TraceFlags byte
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(JSONSpanContext{
|
|
||||||
TraceID: sc.TraceIDString(),
|
|
||||||
SpanID: sc.SpanIDString(),
|
|
||||||
TraceFlags: sc.TraceFlags,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sc SpanContext) IsValid() bool {
|
func (sc SpanContext) IsValid() bool {
|
||||||
return sc.HasTraceID() && sc.HasSpanID()
|
return sc.HasTraceID() && sc.HasSpanID()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc SpanContext) HasTraceID() bool {
|
func (sc SpanContext) HasTraceID() bool {
|
||||||
return sc.TraceID.isValid()
|
return sc.TraceID.IsValid()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc SpanContext) HasSpanID() bool {
|
func (sc SpanContext) HasSpanID() bool {
|
||||||
return sc.SpanID != 0
|
return sc.SpanID.IsValid()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc SpanContext) SpanIDString() string {
|
func (sc SpanContext) SpanIDString() string {
|
||||||
return fmt.Sprintf("%.16x", sc.SpanID)
|
return hex.EncodeToString(sc.SpanID[:])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc SpanContext) TraceIDString() string {
|
func (sc SpanContext) TraceIDString() string {
|
||||||
|
|||||||
@@ -24,28 +24,28 @@ func TestIsValid(t *testing.T) {
|
|||||||
for _, testcase := range []struct {
|
for _, testcase := range []struct {
|
||||||
name string
|
name string
|
||||||
tid core.TraceID
|
tid core.TraceID
|
||||||
sid uint64
|
sid core.SpanID
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "SpanContext.IsValid() returns true if sc has both an Trace ID and Span ID",
|
name: "SpanContext.IsValid() returns true if sc has both an Trace ID and Span ID",
|
||||||
tid: core.TraceID([16]byte{1}),
|
tid: [16]byte{1},
|
||||||
sid: uint64(42),
|
sid: [8]byte{42},
|
||||||
want: true,
|
want: true,
|
||||||
}, {
|
}, {
|
||||||
name: "SpanContext.IsValid() returns false if sc has neither an Trace ID nor Span ID",
|
name: "SpanContext.IsValid() returns false if sc has neither an Trace ID nor Span ID",
|
||||||
tid: core.TraceID([16]byte{}),
|
tid: core.TraceID([16]byte{}),
|
||||||
sid: uint64(0),
|
sid: [8]byte{},
|
||||||
want: false,
|
want: false,
|
||||||
}, {
|
}, {
|
||||||
name: "SpanContext.IsValid() returns false if sc has a Span ID but not a Trace ID",
|
name: "SpanContext.IsValid() returns false if sc has a Span ID but not a Trace ID",
|
||||||
tid: core.TraceID([16]byte{}),
|
tid: core.TraceID([16]byte{}),
|
||||||
sid: uint64(42),
|
sid: [8]byte{42},
|
||||||
want: false,
|
want: false,
|
||||||
}, {
|
}, {
|
||||||
name: "SpanContext.IsValid() returns false if sc has a Trace ID but not a Span ID",
|
name: "SpanContext.IsValid() returns false if sc has a Trace ID but not a Span ID",
|
||||||
tid: core.TraceID([16]byte{1}),
|
tid: core.TraceID([16]byte{1}),
|
||||||
sid: uint64(0),
|
sid: [8]byte{},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
@@ -141,7 +141,7 @@ func TestHasSpanID(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "SpanContext.HasSpanID() returns true if self.SpanID != 0",
|
name: "SpanContext.HasSpanID() returns true if self.SpanID != 0",
|
||||||
sc: core.SpanContext{SpanID: uint64(42)},
|
sc: core.SpanContext{SpanID: [8]byte{42}},
|
||||||
want: true,
|
want: true,
|
||||||
}, {
|
}, {
|
||||||
name: "SpanContext.HasSpanID() returns false if self.SpanID == 0",
|
name: "SpanContext.HasSpanID() returns false if self.SpanID == 0",
|
||||||
@@ -167,8 +167,8 @@ func TestSpanIDString(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "SpanContext.SpanIDString returns string representation of self.TraceID values > 0",
|
name: "SpanContext.SpanIDString returns string representation of self.TraceID values > 0",
|
||||||
sc: core.SpanContext{SpanID: uint64(42)},
|
sc: core.SpanContext{SpanID: [8]byte{42}},
|
||||||
want: `000000000000002a`,
|
want: `2a00000000000000`,
|
||||||
}, {
|
}, {
|
||||||
name: "SpanContext.SpanIDString returns string representation of self.TraceID values == 0",
|
name: "SpanContext.SpanIDString returns string representation of self.TraceID values == 0",
|
||||||
sc: core.SpanContext{},
|
sc: core.SpanContext{},
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -512,7 +511,7 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
|
|||||||
return ot.ErrInvalidCarrier
|
return ot.ErrInvalidCarrier
|
||||||
}
|
}
|
||||||
hhcarrier.Set(traceIDHeader, bridgeSC.otelSpanContext.TraceIDString())
|
hhcarrier.Set(traceIDHeader, bridgeSC.otelSpanContext.TraceIDString())
|
||||||
hhcarrier.Set(spanIDHeader, spanIDToString(bridgeSC.otelSpanContext.SpanID))
|
hhcarrier.Set(spanIDHeader, bridgeSC.otelSpanContext.SpanIDString())
|
||||||
hhcarrier.Set(traceFlagsHeader, traceFlagsToString(bridgeSC.otelSpanContext.TraceFlags))
|
hhcarrier.Set(traceFlagsHeader, traceFlagsToString(bridgeSC.otelSpanContext.TraceFlags))
|
||||||
bridgeSC.ForeachBaggageItem(func(k, v string) bool {
|
bridgeSC.ForeachBaggageItem(func(k, v string) bool {
|
||||||
// we assume that keys are already canonicalized
|
// we assume that keys are already canonicalized
|
||||||
@@ -522,10 +521,6 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func spanIDToString(spanID uint64) string {
|
|
||||||
return fmt.Sprintf("%.16x", spanID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func traceFlagsToString(opts byte) string {
|
func traceFlagsToString(opts byte) string {
|
||||||
var parts []string
|
var parts []string
|
||||||
if opts&otelcore.TraceFlagsSampled == otelcore.TraceFlagsSampled {
|
if opts&otelcore.TraceFlagsSampled == otelcore.TraceFlagsSampled {
|
||||||
@@ -557,7 +552,7 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
|||||||
}
|
}
|
||||||
bridgeSC.otelSpanContext.TraceID = traceID
|
bridgeSC.otelSpanContext.TraceID = traceID
|
||||||
case spanIDHeader:
|
case spanIDHeader:
|
||||||
spanID, err := spanIDFromString(v)
|
spanID, err := otelcore.SpanIDFromHex(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -581,13 +576,6 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
|||||||
return bridgeSC, nil
|
return bridgeSC, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func spanIDFromString(s string) (uint64, error) {
|
|
||||||
if len(s) != 16 {
|
|
||||||
return 0, fmt.Errorf("invalid span ID")
|
|
||||||
}
|
|
||||||
return strconv.ParseUint(s, 16, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringToTraceFlags(s string) byte {
|
func stringToTraceFlags(s string) byte {
|
||||||
var opts byte
|
var opts byte
|
||||||
for _, part := range strings.Split(s, ",") {
|
for _, part := range strings.Split(s, ",") {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ type MockTracer struct {
|
|||||||
Resources oteldctx.Map
|
Resources oteldctx.Map
|
||||||
FinishedSpans []*MockSpan
|
FinishedSpans []*MockSpan
|
||||||
SpareTraceIDs []otelcore.TraceID
|
SpareTraceIDs []otelcore.TraceID
|
||||||
SpareSpanIDs []uint64
|
SpareSpanIDs []otelcore.SpanID
|
||||||
SpareContextKeyValues []MockContextKeyValue
|
SpareContextKeyValues []MockContextKeyValue
|
||||||
|
|
||||||
randLock sync.Mutex
|
randLock sync.Mutex
|
||||||
@@ -153,11 +153,11 @@ func (t *MockTracer) getTraceID(ctx context.Context, spanOpts *oteltrace.SpanOpt
|
|||||||
return t.getRandTraceID()
|
return t.getRandTraceID()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MockTracer) getParentSpanID(ctx context.Context, spanOpts *oteltrace.SpanOptions) uint64 {
|
func (t *MockTracer) getParentSpanID(ctx context.Context, spanOpts *oteltrace.SpanOptions) otelcore.SpanID {
|
||||||
if parent := t.getParentSpanContext(ctx, spanOpts); parent.IsValid() {
|
if parent := t.getParentSpanContext(ctx, spanOpts); parent.IsValid() {
|
||||||
return parent.SpanID
|
return parent.SpanID
|
||||||
}
|
}
|
||||||
return 0
|
return otelcore.SpanID{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MockTracer) getParentSpanContext(ctx context.Context, spanOpts *oteltrace.SpanOptions) otelcore.SpanContext {
|
func (t *MockTracer) getParentSpanContext(ctx context.Context, spanOpts *oteltrace.SpanOptions) otelcore.SpanContext {
|
||||||
@@ -171,7 +171,7 @@ func (t *MockTracer) getParentSpanContext(ctx context.Context, spanOpts *oteltra
|
|||||||
return otelcore.EmptySpanContext()
|
return otelcore.EmptySpanContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MockTracer) getSpanID() uint64 {
|
func (t *MockTracer) getSpanID() otelcore.SpanID {
|
||||||
if len(t.SpareSpanIDs) > 0 {
|
if len(t.SpareSpanIDs) > 0 {
|
||||||
spanID := t.SpareSpanIDs[0]
|
spanID := t.SpareSpanIDs[0]
|
||||||
t.SpareSpanIDs = t.SpareSpanIDs[1:]
|
t.SpareSpanIDs = t.SpareSpanIDs[1:]
|
||||||
@@ -180,13 +180,17 @@ func (t *MockTracer) getSpanID() uint64 {
|
|||||||
}
|
}
|
||||||
return spanID
|
return spanID
|
||||||
}
|
}
|
||||||
return t.getRandUint64()
|
return t.getRandSpanID()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MockTracer) getRandUint64() uint64 {
|
func (t *MockTracer) getRandSpanID() otelcore.SpanID {
|
||||||
t.randLock.Lock()
|
t.randLock.Lock()
|
||||||
defer t.randLock.Unlock()
|
defer t.randLock.Unlock()
|
||||||
return t.rand.Uint64()
|
|
||||||
|
sid := otelcore.SpanID{}
|
||||||
|
t.rand.Read(sid[:])
|
||||||
|
|
||||||
|
return sid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MockTracer) getRandTraceID() otelcore.TraceID {
|
func (t *MockTracer) getRandTraceID() otelcore.TraceID {
|
||||||
@@ -220,7 +224,7 @@ type MockSpan struct {
|
|||||||
Attributes oteldctx.Map
|
Attributes oteldctx.Map
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
EndTime time.Time
|
EndTime time.Time
|
||||||
ParentSpanID uint64
|
ParentSpanID otelcore.SpanID
|
||||||
Events []MockEvent
|
Events []MockEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func TestMixedAPIs(t *testing.T) {
|
|||||||
|
|
||||||
type simpleTest struct {
|
type simpleTest struct {
|
||||||
traceID otelcore.TraceID
|
traceID otelcore.TraceID
|
||||||
spanIDs []uint64
|
spanIDs []otelcore.SpanID
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSimpleTest() *simpleTest {
|
func newSimpleTest() *simpleTest {
|
||||||
@@ -166,10 +166,10 @@ func (st *simpleTest) noop(t *testing.T, ctx context.Context) {
|
|||||||
|
|
||||||
type currentActiveSpanTest struct {
|
type currentActiveSpanTest struct {
|
||||||
traceID otelcore.TraceID
|
traceID otelcore.TraceID
|
||||||
spanIDs []uint64
|
spanIDs []otelcore.SpanID
|
||||||
|
|
||||||
recordedCurrentOtelSpanIDs []uint64
|
recordedCurrentOtelSpanIDs []otelcore.SpanID
|
||||||
recordedActiveOTSpanIDs []uint64
|
recordedActiveOTSpanIDs []otelcore.SpanID
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCurrentActiveSpanTest() *currentActiveSpanTest {
|
func newCurrentActiveSpanTest() *currentActiveSpanTest {
|
||||||
@@ -220,7 +220,7 @@ func (cast *currentActiveSpanTest) recordSpans(t *testing.T, ctx context.Context
|
|||||||
spanID := oteltrace.CurrentSpan(ctx).SpanContext().SpanID
|
spanID := oteltrace.CurrentSpan(ctx).SpanContext().SpanID
|
||||||
cast.recordedCurrentOtelSpanIDs = append(cast.recordedCurrentOtelSpanIDs, spanID)
|
cast.recordedCurrentOtelSpanIDs = append(cast.recordedCurrentOtelSpanIDs, spanID)
|
||||||
|
|
||||||
spanID = 0
|
spanID = otelcore.SpanID{}
|
||||||
if bridgeSpan, ok := ot.SpanFromContext(ctx).(*bridgeSpan); ok {
|
if bridgeSpan, ok := ot.SpanFromContext(ctx).(*bridgeSpan); ok {
|
||||||
spanID = bridgeSpan.otelSpan.SpanContext().SpanID
|
spanID = bridgeSpan.otelSpan.SpanContext().SpanID
|
||||||
}
|
}
|
||||||
@@ -466,23 +466,23 @@ func (tm *tracerMessTest) recordTracers(t *testing.T, ctx context.Context) {
|
|||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTraceID otelcore.TraceID, expectedSpanIDs []uint64) {
|
func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTraceID otelcore.TraceID, expectedSpanIDs []otelcore.SpanID) {
|
||||||
expectedSpanCount := len(expectedSpanIDs)
|
expectedSpanCount := len(expectedSpanIDs)
|
||||||
|
|
||||||
// reverse spanIDs, since first span ID belongs to root, that
|
// reverse spanIDs, since first span ID belongs to root, that
|
||||||
// finishes last
|
// finishes last
|
||||||
spanIDs := make([]uint64, len(expectedSpanIDs))
|
spanIDs := make([]otelcore.SpanID, len(expectedSpanIDs))
|
||||||
copy(spanIDs, expectedSpanIDs)
|
copy(spanIDs, expectedSpanIDs)
|
||||||
reverse(len(spanIDs), func(i, j int) {
|
reverse(len(spanIDs), func(i, j int) {
|
||||||
spanIDs[i], spanIDs[j] = spanIDs[j], spanIDs[i]
|
spanIDs[i], spanIDs[j] = spanIDs[j], spanIDs[i]
|
||||||
})
|
})
|
||||||
// the last finished span has no parent
|
// the last finished span has no parent
|
||||||
parentSpanIDs := append(spanIDs[1:], 0)
|
parentSpanIDs := append(spanIDs[1:], otelcore.SpanID{})
|
||||||
|
|
||||||
sks := map[uint64]oteltrace.SpanKind{
|
sks := map[otelcore.SpanID]oteltrace.SpanKind{
|
||||||
3456: oteltrace.SpanKindProducer,
|
{125}: oteltrace.SpanKindProducer,
|
||||||
2345: oteltrace.SpanKindInternal,
|
{124}: oteltrace.SpanKindInternal,
|
||||||
1234: oteltrace.SpanKindClient,
|
{123}: oteltrace.SpanKindClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tracer.FinishedSpans) != expectedSpanCount {
|
if len(tracer.FinishedSpans) != expectedSpanCount {
|
||||||
@@ -517,23 +517,16 @@ func simpleTraceID() otelcore.TraceID {
|
|||||||
return [16]byte{123, 42}
|
return [16]byte{123, 42}
|
||||||
}
|
}
|
||||||
|
|
||||||
func simpleSpanIDs(count int) []uint64 {
|
func simpleSpanIDs(count int) []otelcore.SpanID {
|
||||||
base := []uint64{
|
base := []otelcore.SpanID{
|
||||||
1234,
|
{123},
|
||||||
2345,
|
{124},
|
||||||
3456,
|
{125},
|
||||||
4567,
|
{126},
|
||||||
5678,
|
{127},
|
||||||
6789,
|
{128},
|
||||||
}
|
}
|
||||||
if count <= len(base) {
|
return base[:count]
|
||||||
return base[:count]
|
|
||||||
}
|
|
||||||
count -= len(base)
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
base = append(base, base[i]*10)
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(a, b int) int {
|
func min(a, b int) int {
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ func spanDataToThrift(data *export.SpanData) *gen.Span {
|
|||||||
refs = append(refs, &gen.SpanRef{
|
refs = append(refs, &gen.SpanRef{
|
||||||
TraceIdHigh: int64(binary.BigEndian.Uint64(link.TraceID[0:8])),
|
TraceIdHigh: int64(binary.BigEndian.Uint64(link.TraceID[0:8])),
|
||||||
TraceIdLow: int64(binary.BigEndian.Uint64(link.TraceID[8:16])),
|
TraceIdLow: int64(binary.BigEndian.Uint64(link.TraceID[8:16])),
|
||||||
SpanId: int64(link.SpanID),
|
SpanId: int64(binary.BigEndian.Uint64(link.SpanID[:])),
|
||||||
// TODO(paivagustavo): properly set the reference type when specs are defined
|
// TODO(paivagustavo): properly set the reference type when specs are defined
|
||||||
// see https://github.com/open-telemetry/opentelemetry-specification/issues/65
|
// see https://github.com/open-telemetry/opentelemetry-specification/issues/65
|
||||||
RefType: gen.SpanRefType_CHILD_OF,
|
RefType: gen.SpanRefType_CHILD_OF,
|
||||||
@@ -209,8 +209,8 @@ func spanDataToThrift(data *export.SpanData) *gen.Span {
|
|||||||
return &gen.Span{
|
return &gen.Span{
|
||||||
TraceIdHigh: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[0:8])),
|
TraceIdHigh: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[0:8])),
|
||||||
TraceIdLow: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[8:16])),
|
TraceIdLow: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[8:16])),
|
||||||
SpanId: int64(data.SpanContext.SpanID),
|
SpanId: int64(binary.BigEndian.Uint64(data.SpanContext.SpanID[:])),
|
||||||
ParentSpanId: int64(data.ParentSpanID),
|
ParentSpanId: int64(binary.BigEndian.Uint64(data.ParentSpanID[:])),
|
||||||
OperationName: data.Name, // TODO: if span kind is added then add prefix "Sent"/"Recv"
|
OperationName: data.Name, // TODO: if span kind is added then add prefix "Sent"/"Recv"
|
||||||
Flags: int32(data.SpanContext.TraceFlags),
|
Flags: int32(data.SpanContext.TraceFlags),
|
||||||
StartTime: data.StartTime.UnixNano() / 1000,
|
StartTime: data.StartTime.UnixNano() / 1000,
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ import (
|
|||||||
func Test_spanDataToThrift(t *testing.T) {
|
func Test_spanDataToThrift(t *testing.T) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
traceID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
traceID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
||||||
spanID := uint64(0x0102030405060708)
|
spanID, _ := core.SpanIDFromHex("0102030405060708")
|
||||||
|
|
||||||
linkTraceID, _ := core.TraceIDFromHex("0102030405060709090a0b0c0d0e0f11")
|
linkTraceID, _ := core.TraceIDFromHex("0102030405060709090a0b0c0d0e0f11")
|
||||||
linkSpanID := uint64(0x0102030405060709)
|
linkSpanID, _ := core.SpanIDFromHex("0102030405060709")
|
||||||
|
|
||||||
keyValue := "value"
|
keyValue := "value"
|
||||||
statusCodeValue := int64(2)
|
statusCodeValue := int64(2)
|
||||||
@@ -102,7 +102,7 @@ func Test_spanDataToThrift(t *testing.T) {
|
|||||||
RefType: gen.SpanRefType_CHILD_OF,
|
RefType: gen.SpanRefType_CHILD_OF,
|
||||||
TraceIdHigh: int64(binary.BigEndian.Uint64(linkTraceID[0:8])),
|
TraceIdHigh: int64(binary.BigEndian.Uint64(linkTraceID[0:8])),
|
||||||
TraceIdLow: int64(binary.BigEndian.Uint64(linkTraceID[8:16])),
|
TraceIdLow: int64(binary.BigEndian.Uint64(linkTraceID[8:16])),
|
||||||
SpanId: int64(linkSpanID),
|
SpanId: int64(binary.BigEndian.Uint64(linkSpanID[:])),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// TODO [rghetia]: check Logs when event is added.
|
// TODO [rghetia]: check Logs when event is added.
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func protoFromSpanData(s *export.SpanData, projectID string) *tracepb.Span {
|
|||||||
EndTime: timestampProto(s.EndTime),
|
EndTime: timestampProto(s.EndTime),
|
||||||
SameProcessAsParentSpan: &wrapperspb.BoolValue{Value: !s.HasRemoteParent},
|
SameProcessAsParentSpan: &wrapperspb.BoolValue{Value: !s.HasRemoteParent},
|
||||||
}
|
}
|
||||||
if s.ParentSpanID != s.SpanContext.SpanID && s.ParentSpanID != 0 {
|
if s.ParentSpanID != s.SpanContext.SpanID && s.ParentSpanID.IsValid() {
|
||||||
sp.ParentSpanId = fmt.Sprintf("%.16x", s.ParentSpanID)
|
sp.ParentSpanId = fmt.Sprintf("%.16x", s.ParentSpanID)
|
||||||
}
|
}
|
||||||
if s.Status != codes.OK {
|
if s.Status != codes.OK {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func TestExporter_ExportSpan(t *testing.T) {
|
|||||||
// setup test span
|
// setup test span
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
traceID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
traceID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
||||||
spanID := uint64(0x0102030405060708)
|
spanID, _ := core.SpanIDFromHex("0102030405060708")
|
||||||
keyValue := "value"
|
keyValue := "value"
|
||||||
doubleValue := float64(123.456)
|
doubleValue := float64(123.456)
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ func TestExporter_ExportSpan(t *testing.T) {
|
|||||||
expectedOutput := `{"SpanContext":{` +
|
expectedOutput := `{"SpanContext":{` +
|
||||||
`"TraceID":"0102030405060708090a0b0c0d0e0f10",` +
|
`"TraceID":"0102030405060708090a0b0c0d0e0f10",` +
|
||||||
`"SpanID":"0102030405060708","TraceFlags":0},` +
|
`"SpanID":"0102030405060708","TraceFlags":0},` +
|
||||||
`"ParentSpanID":0,` +
|
`"ParentSpanID":"0000000000000000",` +
|
||||||
`"SpanKind":"internal",` +
|
`"SpanKind":"internal",` +
|
||||||
`"Name":"/foo",` +
|
`"Name":"/foo",` +
|
||||||
`"StartTime":` + string(expectedSerializedNow) + "," +
|
`"StartTime":` + string(expectedSerializedNow) + "," +
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package trace
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
@@ -77,7 +78,8 @@ func (mt *MockTracer) Start(ctx context.Context, name string, o ...apitrace.Span
|
|||||||
} else {
|
} else {
|
||||||
sc = opts.Relation.SpanContext
|
sc = opts.Relation.SpanContext
|
||||||
}
|
}
|
||||||
sc.SpanID = atomic.AddUint64(mt.StartSpanID, 1)
|
|
||||||
|
binary.BigEndian.PutUint64(sc.SpanID[:], atomic.AddUint64(mt.StartSpanID, 1))
|
||||||
span = &MockSpan{
|
span = &MockSpan{
|
||||||
sc: sc,
|
sc: sc,
|
||||||
tracer: mt,
|
tracer: mt,
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
package propagation
|
package propagation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
apipropagation "go.opentelemetry.io/api/propagation"
|
apipropagation "go.opentelemetry.io/api/propagation"
|
||||||
)
|
)
|
||||||
@@ -40,7 +38,7 @@ func (bp binaryPropagator) ToBytes(sc core.SpanContext) []byte {
|
|||||||
var b [29]byte
|
var b [29]byte
|
||||||
copy(b[2:18], sc.TraceID[:])
|
copy(b[2:18], sc.TraceID[:])
|
||||||
b[18] = 1
|
b[18] = 1
|
||||||
binary.BigEndian.PutUint64(b[19:27], sc.SpanID)
|
copy(b[19:27], sc.SpanID[:])
|
||||||
b[27] = 2
|
b[27] = 2
|
||||||
b[28] = sc.TraceFlags
|
b[28] = sc.TraceFlags
|
||||||
return b[:]
|
return b[:]
|
||||||
@@ -60,7 +58,7 @@ func (bp binaryPropagator) FromBytes(b []byte) (sc core.SpanContext) {
|
|||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
if len(b) >= 9 && b[0] == 1 {
|
if len(b) >= 9 && b[0] == 1 {
|
||||||
sc.SpanID = binary.BigEndian.Uint64(b[1:9])
|
copy(sc.SpanID[:], b[1:9])
|
||||||
b = b[9:]
|
b = b[9:]
|
||||||
}
|
}
|
||||||
if len(b) >= 2 && b[0] == 2 {
|
if len(b) >= 2 && b[0] == 2 {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
package propagation_test
|
package propagation_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
@@ -25,11 +24,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestExtractSpanContextFromBytes(t *testing.T) {
|
func TestExtractSpanContextFromBytes(t *testing.T) {
|
||||||
bTraceID, _ := hex.DecodeString("4bf92f3577b34da6a3ce929d0e0e4736")
|
traceID, _ := core.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||||
traceID := core.TraceID{}
|
spanID, _ := core.SpanIDFromHex("00f067aa0ba902b7")
|
||||||
copy(traceID[:], bTraceID)
|
|
||||||
|
|
||||||
spanID := uint64(0x00f067aa0ba902b7)
|
|
||||||
propagator := propagation.BinaryPropagator()
|
propagator := propagation.BinaryPropagator()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -123,11 +120,9 @@ func TestExtractSpanContextFromBytes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestConvertSpanContextToBytes(t *testing.T) {
|
func TestConvertSpanContextToBytes(t *testing.T) {
|
||||||
bTraceID, _ := hex.DecodeString("4bf92f3577b34da6a3ce929d0e0e4736")
|
traceID, _ := core.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||||
traceID := core.TraceID{}
|
spanID, _ := core.SpanIDFromHex("00f067aa0ba902b7")
|
||||||
copy(traceID[:], bTraceID)
|
|
||||||
|
|
||||||
spanID := uint64(0x00f067aa0ba902b7)
|
|
||||||
propagator := propagation.BinaryPropagator()
|
propagator := propagation.BinaryPropagator()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ package propagation
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.opentelemetry.io/api/trace"
|
"go.opentelemetry.io/api/trace"
|
||||||
@@ -57,8 +55,6 @@ type HTTPB3Propagator struct {
|
|||||||
|
|
||||||
var _ apipropagation.TextFormatPropagator = HTTPB3Propagator{}
|
var _ apipropagation.TextFormatPropagator = HTTPB3Propagator{}
|
||||||
|
|
||||||
var hexStr16ByteRegex = regexp.MustCompile("^[a-f0-9]{16}$")
|
|
||||||
|
|
||||||
func (b3 HTTPB3Propagator) Inject(ctx context.Context, supplier apipropagation.Supplier) {
|
func (b3 HTTPB3Propagator) Inject(ctx context.Context, supplier apipropagation.Supplier) {
|
||||||
sc := trace.CurrentSpan(ctx).SpanContext()
|
sc := trace.CurrentSpan(ctx).SpanContext()
|
||||||
if sc.IsValid() {
|
if sc.IsValid() {
|
||||||
@@ -98,12 +94,12 @@ func (b3 HTTPB3Propagator) GetAllKeys() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b3 HTTPB3Propagator) extract(supplier apipropagation.Supplier) core.SpanContext {
|
func (b3 HTTPB3Propagator) extract(supplier apipropagation.Supplier) core.SpanContext {
|
||||||
tid, ok := b3.extractTraceID(supplier.Get(B3TraceIDHeader))
|
tid, err := core.TraceIDFromHex(supplier.Get(B3TraceIDHeader))
|
||||||
if !ok {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
sid, ok := b3.extractSpanID(supplier.Get(B3SpanIDHeader))
|
sid, err := core.SpanIDFromHex(supplier.Get(B3SpanIDHeader))
|
||||||
if !ok {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
sampled, ok := b3.extractSampledState(supplier.Get(B3SampledHeader))
|
sampled, ok := b3.extractSampledState(supplier.Get(B3SampledHeader))
|
||||||
@@ -148,26 +144,27 @@ func (b3 HTTPB3Propagator) extractSingleHeader(supplier apipropagation.Supplier)
|
|||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
var ok bool
|
var err error
|
||||||
sc.TraceID, ok = b3.extractTraceID(parts[0])
|
sc.TraceID, err = core.TraceIDFromHex(parts[0])
|
||||||
if !ok {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.SpanID, ok = b3.extractSpanID(parts[1])
|
sc.SpanID, err = core.SpanIDFromHex(parts[1])
|
||||||
if !ok {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
if l > 2 {
|
if l > 2 {
|
||||||
|
var ok bool
|
||||||
sc.TraceFlags, ok = b3.extractSampledState(parts[2])
|
sc.TraceFlags, ok = b3.extractSampledState(parts[2])
|
||||||
if !ok {
|
if !ok {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if l == 4 {
|
if l == 4 {
|
||||||
_, ok = b3.extractSpanID(parts[3])
|
_, err = core.SpanIDFromHex(parts[3])
|
||||||
if !ok {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,21 +176,6 @@ func (b3 HTTPB3Propagator) extractSingleHeader(supplier apipropagation.Supplier)
|
|||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractTraceID parses the value of the X-B3-TraceId b3Header.
|
|
||||||
func (b3 HTTPB3Propagator) extractTraceID(tid string) (traceID core.TraceID, ok bool) {
|
|
||||||
traceID, err := core.TraceIDFromHex(tid)
|
|
||||||
return traceID, err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
|
|
||||||
func (b3 HTTPB3Propagator) extractSpanID(sid string) (spanID uint64, ok bool) {
|
|
||||||
if hexStr16ByteRegex.MatchString(sid) {
|
|
||||||
spanID, _ = strconv.ParseUint(sid, 16, 64)
|
|
||||||
ok = true
|
|
||||||
}
|
|
||||||
return spanID, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractSampledState parses the value of the X-B3-Sampled b3Header.
|
// extractSampledState parses the value of the X-B3-Sampled b3Header.
|
||||||
func (b3 HTTPB3Propagator) extractSampledState(sampled string) (flag byte, ok bool) {
|
func (b3 HTTPB3Propagator) extractSampledState(sampled string) (flag byte, ok bool) {
|
||||||
switch sampled {
|
switch sampled {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
@@ -119,7 +118,7 @@ func (hp HTTPTraceContextPropagator) extractSpanContext(
|
|||||||
|
|
||||||
var sc core.SpanContext
|
var sc core.SpanContext
|
||||||
|
|
||||||
_, err = hex.Decode(sc.TraceID[0:16], []byte(sections[1][0:32]))
|
sc.TraceID, err = core.TraceIDFromHex(sections[1][:32])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
@@ -127,11 +126,10 @@ func (hp HTTPTraceContextPropagator) extractSpanContext(
|
|||||||
if len(sections[2]) != 16 {
|
if len(sections[2]) != 16 {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
result, err := strconv.ParseUint(sections[2][0:], 16, 64)
|
sc.SpanID, err = core.SpanIDFromHex(sections[2][:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
}
|
}
|
||||||
sc.SpanID = result
|
|
||||||
|
|
||||||
if len(sections[3]) != 2 {
|
if len(sections[3]) != 2 {
|
||||||
return core.EmptySpanContext()
|
return core.EmptySpanContext()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package propagation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -25,13 +24,9 @@ func BenchmarkInject(b *testing.B) {
|
|||||||
|
|
||||||
func injectSubBenchmarks(b *testing.B, fn func(context.Context, *testing.B)) {
|
func injectSubBenchmarks(b *testing.B, fn func(context.Context, *testing.B)) {
|
||||||
b.Run("SampledSpanContext", func(b *testing.B) {
|
b.Run("SampledSpanContext", func(b *testing.B) {
|
||||||
var (
|
var id uint64
|
||||||
id uint64
|
spanID, _ := core.SpanIDFromHex("00f067aa0ba902b7")
|
||||||
spanID = uint64(0x00f067aa0ba902b7)
|
traceID, _ := core.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||||
traceID = core.TraceID{}
|
|
||||||
)
|
|
||||||
bt, _ := hex.DecodeString("4bf92f3577b34da6a3ce929d0e0e4736")
|
|
||||||
copy(traceID[:], bt)
|
|
||||||
|
|
||||||
mockTracer := &mocktrace.MockTracer{
|
mockTracer := &mocktrace.MockTracer{
|
||||||
Sampled: false,
|
Sampled: false,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
traceID = mustTraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
traceID = mustTraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||||
spanID = uint64(0x00f067aa0ba902b7)
|
spanID = mustSpanIDFromHex("00f067aa0ba902b7")
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustTraceIDFromHex(s string) (t core.TraceID) {
|
func mustTraceIDFromHex(s string) (t core.TraceID) {
|
||||||
@@ -40,6 +40,11 @@ func mustTraceIDFromHex(s string) (t core.TraceID) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustSpanIDFromHex(s string) (t core.SpanID) {
|
||||||
|
t, _ = core.SpanIDFromHex(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||||
var propagator propagation.HTTPTraceContextPropagator
|
var propagator propagation.HTTPTraceContextPropagator
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import (
|
|||||||
// SpanData contains all the information collected by a span.
|
// SpanData contains all the information collected by a span.
|
||||||
type SpanData struct {
|
type SpanData struct {
|
||||||
SpanContext core.SpanContext
|
SpanContext core.SpanContext
|
||||||
ParentSpanID uint64
|
ParentSpanID core.SpanID
|
||||||
SpanKind apitrace.SpanKind
|
SpanKind apitrace.SpanKind
|
||||||
Name string
|
Name string
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ func generateSpan(t *testing.T, tr apitrace.Tracer, option testOption) {
|
|||||||
|
|
||||||
func getSpanContext() core.SpanContext {
|
func getSpanContext() core.SpanContext {
|
||||||
tid, _ := core.TraceIDFromHex("01020304050607080102040810203040")
|
tid, _ := core.TraceIDFromHex("01020304050607080102040810203040")
|
||||||
sid := uint64(0x0102040810203040)
|
sid, _ := core.SpanIDFromHex("0102040810203040")
|
||||||
return core.SpanContext{
|
return core.SpanContext{
|
||||||
TraceID: tid,
|
TraceID: tid,
|
||||||
SpanID: sid,
|
SpanID: sid,
|
||||||
|
|||||||
@@ -161,8 +161,8 @@ func BenchmarkTraceID_DotString(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkSpanID_DotString(b *testing.B) {
|
func BenchmarkSpanID_DotString(b *testing.B) {
|
||||||
traceBenchmark(b, func(b *testing.B) {
|
traceBenchmark(b, func(b *testing.B) {
|
||||||
sc := core.SpanContext{SpanID: 1}
|
sc := core.SpanContext{SpanID: core.SpanID{1}}
|
||||||
want := "0000000000000001"
|
want := "1000000000000000"
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
if got := sc.SpanIDString(); got != want {
|
if got := sc.SpanIDString(); got != want {
|
||||||
b.Fatalf("got = %q want = %q", got, want)
|
b.Fatalf("got = %q want = %q", got, want)
|
||||||
@@ -188,4 +188,4 @@ func getTracer(b *testing.B, name string) apitrace.Tracer {
|
|||||||
b.Fatalf("Failed to create trace provider for test %s\n", name)
|
b.Fatalf("Failed to create trace provider for test %s\n", name)
|
||||||
}
|
}
|
||||||
return tp.GetTracer(name)
|
return tp.GetTracer(name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package trace
|
|||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
"go.opentelemetry.io/sdk/trace/internal"
|
"go.opentelemetry.io/sdk/trace/internal"
|
||||||
@@ -25,31 +24,18 @@ import (
|
|||||||
|
|
||||||
type defaultIDGenerator struct {
|
type defaultIDGenerator struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
randSource *rand.Rand
|
||||||
// Please keep these as the first fields
|
|
||||||
// so that these 8 byte fields will be aligned on addresses
|
|
||||||
// divisible by 8, on both 32-bit and 64-bit machines when
|
|
||||||
// performing atomic increments and accesses.
|
|
||||||
// See:
|
|
||||||
// * https://github.com/census-instrumentation/opencensus-go/issues/587
|
|
||||||
// * https://github.com/census-instrumentation/opencensus-go/issues/865
|
|
||||||
// * https://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
|
||||||
nextSpanID uint64
|
|
||||||
spanIDInc uint64
|
|
||||||
|
|
||||||
traceIDAdd [2]uint64
|
|
||||||
traceIDRand *rand.Rand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ internal.IDGenerator = &defaultIDGenerator{}
|
var _ internal.IDGenerator = &defaultIDGenerator{}
|
||||||
|
|
||||||
// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
|
// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
|
||||||
func (gen *defaultIDGenerator) NewSpanID() uint64 {
|
func (gen *defaultIDGenerator) NewSpanID() core.SpanID {
|
||||||
var id uint64
|
gen.Lock()
|
||||||
for id == 0 {
|
defer gen.Unlock()
|
||||||
id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc)
|
sid := core.SpanID{}
|
||||||
}
|
gen.randSource.Read(sid[:])
|
||||||
return id
|
return sid
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence.
|
// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence.
|
||||||
@@ -57,9 +43,7 @@ func (gen *defaultIDGenerator) NewSpanID() uint64 {
|
|||||||
func (gen *defaultIDGenerator) NewTraceID() core.TraceID {
|
func (gen *defaultIDGenerator) NewTraceID() core.TraceID {
|
||||||
gen.Lock()
|
gen.Lock()
|
||||||
defer gen.Unlock()
|
defer gen.Unlock()
|
||||||
// Construct the trace ID from two outputs of traceIDRand, with a constant
|
|
||||||
// added to each half for additional entropy.
|
|
||||||
tid := core.TraceID{}
|
tid := core.TraceID{}
|
||||||
gen.traceIDRand.Read(tid[:])
|
gen.randSource.Read(tid[:])
|
||||||
return tid
|
return tid
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ import "go.opentelemetry.io/api/core"
|
|||||||
// IDGenerator allows custom generators for TraceId and SpanId.
|
// IDGenerator allows custom generators for TraceId and SpanId.
|
||||||
type IDGenerator interface {
|
type IDGenerator interface {
|
||||||
NewTraceID() core.TraceID
|
NewTraceID() core.TraceID
|
||||||
NewSpanID() uint64
|
NewSpanID() core.SpanID
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ type Sampler func(SamplingParameters) SamplingDecision
|
|||||||
type SamplingParameters struct {
|
type SamplingParameters struct {
|
||||||
ParentContext core.SpanContext
|
ParentContext core.SpanContext
|
||||||
TraceID core.TraceID
|
TraceID core.TraceID
|
||||||
SpanID uint64
|
SpanID core.SpanID
|
||||||
Name string
|
Name string
|
||||||
HasRemoteParent bool
|
HasRemoteParent bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func TestSimpleSpanProcessorOnEnd(t *testing.T) {
|
|||||||
tp.RegisterSpanProcessor(ssp)
|
tp.RegisterSpanProcessor(ssp)
|
||||||
tr := tp.GetTracer("SimpleSpanProcessor")
|
tr := tp.GetTracer("SimpleSpanProcessor")
|
||||||
tid, _ := core.TraceIDFromHex("01020304050607080102040810203040")
|
tid, _ := core.TraceIDFromHex("01020304050607080102040810203040")
|
||||||
sid := uint64(0x0102040810203040)
|
sid, _ := core.SpanIDFromHex("0102040810203040")
|
||||||
sc := core.SpanContext{
|
sc := core.SpanContext{
|
||||||
TraceID: tid,
|
TraceID: tid,
|
||||||
SpanID: sid,
|
SpanID: sid,
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ func (s *span) SetName(name string) {
|
|||||||
spanName := s.tracer.spanNameWithPrefix(name)
|
spanName := s.tracer.spanNameWithPrefix(name)
|
||||||
s.data.Name = spanName
|
s.data.Name = spanName
|
||||||
// SAMPLING
|
// SAMPLING
|
||||||
noParent := s.data.ParentSpanID == 0
|
noParent := !s.data.ParentSpanID.IsValid()
|
||||||
var ctx core.SpanContext
|
var ctx core.SpanContext
|
||||||
if noParent {
|
if noParent {
|
||||||
ctx = core.EmptySpanContext()
|
ctx = core.EmptySpanContext()
|
||||||
|
|||||||
@@ -24,14 +24,8 @@ import (
|
|||||||
|
|
||||||
func defIDGenerator() internal.IDGenerator {
|
func defIDGenerator() internal.IDGenerator {
|
||||||
gen := &defaultIDGenerator{}
|
gen := &defaultIDGenerator{}
|
||||||
// initialize traceID and spanID generators.
|
|
||||||
var rngSeed int64
|
var rngSeed int64
|
||||||
for _, p := range []interface{}{
|
_ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed)
|
||||||
&rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc,
|
gen.randSource = rand.New(rand.NewSource(rngSeed))
|
||||||
} {
|
|
||||||
_ = binary.Read(crand.Reader, binary.LittleEndian, p)
|
|
||||||
}
|
|
||||||
gen.traceIDRand = rand.New(rand.NewSource(rngSeed))
|
|
||||||
gen.spanIDInc |= 1
|
|
||||||
return gen
|
return gen
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,11 +35,12 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
tid core.TraceID
|
tid core.TraceID
|
||||||
sid = uint64(0x0102040810203040)
|
sid core.SpanID
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
tid, _ = core.TraceIDFromHex("01020304050607080102040810203040")
|
tid, _ = core.TraceIDFromHex("01020304050607080102040810203040")
|
||||||
|
sid, _ = core.SpanIDFromHex("0102040810203040")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTracerFollowsExpectedAPIBehaviour(t *testing.T) {
|
func TestTracerFollowsExpectedAPIBehaviour(t *testing.T) {
|
||||||
@@ -394,8 +395,8 @@ func TestAddLinks(t *testing.T) {
|
|||||||
k1v1 := key.New("key1").String("value1")
|
k1v1 := key.New("key1").String("value1")
|
||||||
k2v2 := key.New("key2").String("value2")
|
k2v2 := key.New("key2").String("value2")
|
||||||
|
|
||||||
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
|
|
||||||
link1 := apitrace.Link{SpanContext: sc1, Attributes: []core.KeyValue{k1v1}}
|
link1 := apitrace.Link{SpanContext: sc1, Attributes: []core.KeyValue{k1v1}}
|
||||||
link2 := apitrace.Link{SpanContext: sc2, Attributes: []core.KeyValue{k2v2}}
|
link2 := apitrace.Link{SpanContext: sc2, Attributes: []core.KeyValue{k2v2}}
|
||||||
@@ -435,8 +436,8 @@ func TestLinks(t *testing.T) {
|
|||||||
k2v2 := key.New("key2").String("value2")
|
k2v2 := key.New("key2").String("value2")
|
||||||
k3v3 := key.New("key3").String("value3")
|
k3v3 := key.New("key3").String("value3")
|
||||||
|
|
||||||
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
|
|
||||||
span.Link(sc1, key.New("key1").String("value1"))
|
span.Link(sc1, key.New("key1").String("value1"))
|
||||||
span.Link(sc2,
|
span.Link(sc2,
|
||||||
@@ -471,9 +472,9 @@ func TestLinksOverLimit(t *testing.T) {
|
|||||||
te := &testExporter{}
|
te := &testExporter{}
|
||||||
cfg := Config{MaxLinksPerSpan: 2}
|
cfg := Config{MaxLinksPerSpan: 2}
|
||||||
|
|
||||||
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
sc3 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
sc3 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: core.SpanID{3}}
|
||||||
|
|
||||||
tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te))
|
tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te))
|
||||||
span := startSpan(tp, "LinksOverLimit")
|
span := startSpan(tp, "LinksOverLimit")
|
||||||
@@ -632,10 +633,10 @@ func endSpan(te *testExporter, span apitrace.Span) (*export.SpanData, error) {
|
|||||||
return nil, fmt.Errorf("got exported spans %#v, want one span", te.spans)
|
return nil, fmt.Errorf("got exported spans %#v, want one span", te.spans)
|
||||||
}
|
}
|
||||||
got := te.spans[0]
|
got := te.spans[0]
|
||||||
if got.SpanContext.SpanID == 0 {
|
if !got.SpanContext.SpanID.IsValid() {
|
||||||
return nil, fmt.Errorf("exporting span: expected nonzero SpanID")
|
return nil, fmt.Errorf("exporting span: expected nonzero SpanID")
|
||||||
}
|
}
|
||||||
got.SpanContext.SpanID = 0
|
got.SpanContext.SpanID = core.SpanID{}
|
||||||
if !checkTime(&got.StartTime) {
|
if !checkTime(&got.StartTime) {
|
||||||
return nil, fmt.Errorf("exporting span: expected nonzero StartTime")
|
return nil, fmt.Errorf("exporting span: expected nonzero StartTime")
|
||||||
}
|
}
|
||||||
@@ -755,6 +756,7 @@ func TestExecutionTracerTaskEnd(t *testing.T) {
|
|||||||
spans = append(spans, s) // never sample
|
spans = append(spans, s) // never sample
|
||||||
|
|
||||||
tID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f")
|
tID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f")
|
||||||
|
sID, _ := core.SpanIDFromHex("0001020304050607")
|
||||||
|
|
||||||
_, apiSpan = tr.Start(
|
_, apiSpan = tr.Start(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
@@ -762,7 +764,7 @@ func TestExecutionTracerTaskEnd(t *testing.T) {
|
|||||||
apitrace.ChildOf(
|
apitrace.ChildOf(
|
||||||
core.SpanContext{
|
core.SpanContext{
|
||||||
TraceID: tID,
|
TraceID: tID,
|
||||||
SpanID: uint64(0x0001020304050607),
|
SpanID: sID,
|
||||||
TraceFlags: 0,
|
TraceFlags: 0,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user