mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-03-07 15:10:43 +02:00
api(trace): change trace id to byte array. (#226)
* api(trace): change trace id to byte array. * fix lint errors * add helper to create trace id from hex and improve stdout exporter. * remove comma. * fix lint * change TraceIDFromHex to be compliant with w3 trace-context * revert remove of hex16 regex because its used to parse SpanID * lint * fix typo
This commit is contained in:
parent
cf62d12648
commit
a6e139e1d4
api/core
experimental/bridge/opentracing
exporter/trace
internal/trace
propagation
binary_propagator.gobinary_propagator_test.gohttp_b3_propagator.gohttp_trace_context_propagator.gohttp_trace_context_propagator_benchmark_test.gohttp_trace_context_propagator_test.go
sdk/trace
@ -15,14 +15,13 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type TraceID struct {
|
||||
High uint64
|
||||
Low uint64
|
||||
}
|
||||
|
||||
const (
|
||||
traceFlagsBitMaskSampled = byte(0x01)
|
||||
traceFlagsBitMaskUnused = byte(0xFE)
|
||||
@ -33,23 +32,81 @@ const (
|
||||
TraceFlagsUnused = traceFlagsBitMaskUnused
|
||||
)
|
||||
|
||||
type TraceID [16]byte
|
||||
|
||||
var nilTraceID TraceID
|
||||
|
||||
func (t TraceID) isValid() bool {
|
||||
return !bytes.Equal(t[:], nilTraceID[:])
|
||||
}
|
||||
|
||||
// TraceIDFromHex returns a TraceID from a hex string if it is compliant
|
||||
// with the w3c trace-context specification.
|
||||
// See more at https://www.w3.org/TR/trace-context/#trace-id
|
||||
func TraceIDFromHex(h string) (TraceID, error) {
|
||||
t := TraceID{}
|
||||
if len(h) != 32 {
|
||||
return t, errors.New("hex encoded trace-id must have length equals to 32")
|
||||
}
|
||||
|
||||
for _, r := range h {
|
||||
switch {
|
||||
case 'a' <= r && r <= 'f':
|
||||
continue
|
||||
case '0' <= r && r <= '9':
|
||||
continue
|
||||
default:
|
||||
return t, errors.New("trace-id can only contain [0-9a-f] characters, all lowercase")
|
||||
}
|
||||
}
|
||||
|
||||
b, err := hex.DecodeString(h)
|
||||
if err != nil {
|
||||
return t, err
|
||||
}
|
||||
copy(t[:], b)
|
||||
|
||||
if !t.isValid() {
|
||||
return t, errors.New("trace-id can't be all zero")
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
type SpanContext struct {
|
||||
TraceID TraceID
|
||||
SpanID uint64
|
||||
TraceFlags byte
|
||||
}
|
||||
|
||||
var _ json.Marshaler = (*SpanContext)(nil)
|
||||
|
||||
// EmptySpanContext is meant for internal use to return invalid span context during error conditions.
|
||||
func EmptySpanContext() 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 {
|
||||
return sc.HasTraceID() && sc.HasSpanID()
|
||||
}
|
||||
|
||||
func (sc SpanContext) HasTraceID() bool {
|
||||
return sc.TraceID.High != 0 || sc.TraceID.Low != 0
|
||||
return sc.TraceID.isValid()
|
||||
}
|
||||
|
||||
func (sc SpanContext) HasSpanID() bool {
|
||||
@ -61,9 +118,7 @@ func (sc SpanContext) SpanIDString() string {
|
||||
}
|
||||
|
||||
func (sc SpanContext) TraceIDString() string {
|
||||
p1 := fmt.Sprintf("%.16x", sc.TraceID.High)
|
||||
p2 := fmt.Sprintf("%.16x", sc.TraceID.Low)
|
||||
return p1 + p2
|
||||
return hex.EncodeToString(sc.TraceID[:])
|
||||
}
|
||||
|
||||
func (sc SpanContext) IsSampled() bool {
|
||||
|
@ -29,22 +29,22 @@ func TestIsValid(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "SpanContext.IsValid() returns true if sc has both an Trace ID and Span ID",
|
||||
tid: core.TraceID{High: uint64(42)},
|
||||
tid: core.TraceID([16]byte{1}),
|
||||
sid: uint64(42),
|
||||
want: true,
|
||||
}, {
|
||||
name: "SpanContext.IsValid() returns false if sc has neither an Trace ID nor Span ID",
|
||||
tid: core.TraceID{High: uint64(0)},
|
||||
tid: core.TraceID([16]byte{}),
|
||||
sid: uint64(0),
|
||||
want: false,
|
||||
}, {
|
||||
name: "SpanContext.IsValid() returns false if sc has a Span ID but not a Trace ID",
|
||||
tid: core.TraceID{High: uint64(0)},
|
||||
tid: core.TraceID([16]byte{}),
|
||||
sid: uint64(42),
|
||||
want: false,
|
||||
}, {
|
||||
name: "SpanContext.IsValid() returns false if sc has a Trace ID but not a Span ID",
|
||||
tid: core.TraceID{High: uint64(42)},
|
||||
tid: core.TraceID([16]byte{1}),
|
||||
sid: uint64(0),
|
||||
want: false,
|
||||
},
|
||||
@ -62,6 +62,50 @@ func TestIsValid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidFromHex(t *testing.T) {
|
||||
for _, testcase := range []struct {
|
||||
name string
|
||||
hex string
|
||||
tid core.TraceID
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
name: "Valid TraceID",
|
||||
tid: core.TraceID([16]byte{128, 241, 152, 238, 86, 52, 59, 168, 100, 254, 139, 42, 87, 211, 239, 247}),
|
||||
hex: "80f198ee56343ba864fe8b2a57d3eff7",
|
||||
valid: true,
|
||||
}, {
|
||||
name: "Invalid TraceID with invalid length",
|
||||
hex: "80f198ee56343ba864fe8b2a57d3eff",
|
||||
valid: false,
|
||||
}, {
|
||||
name: "Invalid TraceID with invalid char",
|
||||
hex: "80f198ee56343ba864fe8b2a57d3efg7",
|
||||
valid: false,
|
||||
}, {
|
||||
name: "Invalid TraceID with uppercase",
|
||||
hex: "80f198ee56343ba864fe8b2a57d3efF7",
|
||||
valid: false,
|
||||
},
|
||||
} {
|
||||
t.Run(testcase.name, func(t *testing.T) {
|
||||
tid, err := core.TraceIDFromHex(testcase.hex)
|
||||
|
||||
if testcase.valid && err != nil {
|
||||
t.Errorf("Expected TraceID %s to be valid but end with error %s", testcase.hex, err.Error())
|
||||
}
|
||||
|
||||
if !testcase.valid && err == nil {
|
||||
t.Errorf("Expected TraceID %s to be invalid but end no error", testcase.hex)
|
||||
}
|
||||
|
||||
if tid != testcase.tid {
|
||||
t.Errorf("Want: %v, but have: %v", testcase.tid, tid)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasTraceID(t *testing.T) {
|
||||
for _, testcase := range []struct {
|
||||
name string
|
||||
@ -70,20 +114,12 @@ func TestHasTraceID(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "SpanContext.HasTraceID() returns true if both Low and High are nonzero",
|
||||
tid: core.TraceID{High: uint64(42), Low: uint64(42)},
|
||||
tid: core.TraceID([16]byte{1}),
|
||||
want: true,
|
||||
}, {
|
||||
name: "SpanContext.HasTraceID() returns false if neither Low nor High are nonzero",
|
||||
tid: core.TraceID{},
|
||||
want: false,
|
||||
}, {
|
||||
name: "SpanContext.HasTraceID() returns true if High != 0",
|
||||
tid: core.TraceID{High: uint64(42)},
|
||||
want: true,
|
||||
}, {
|
||||
name: "SpanContext.HasTraceID() returns true if Low != 0",
|
||||
tid: core.TraceID{Low: uint64(42)},
|
||||
want: true,
|
||||
},
|
||||
} {
|
||||
t.Run(testcase.name, func(t *testing.T) {
|
||||
@ -158,12 +194,9 @@ func TestTraceIDString(t *testing.T) {
|
||||
{
|
||||
name: "SpanContext.TraceIDString returns string representation of self.TraceID values > 0",
|
||||
sc: core.SpanContext{
|
||||
TraceID: core.TraceID{
|
||||
High: uint64(42),
|
||||
Low: uint64(42),
|
||||
},
|
||||
TraceID: core.TraceID([16]byte{255}),
|
||||
},
|
||||
want: `000000000000002a000000000000002a`,
|
||||
want: `ff000000000000000000000000000000`,
|
||||
}, {
|
||||
name: "SpanContext.TraceIDString returns string representation of self.TraceID values == 0",
|
||||
sc: core.SpanContext{TraceID: core.TraceID{}},
|
||||
@ -189,20 +222,14 @@ func TestSpanContextIsSampled(t *testing.T) {
|
||||
{
|
||||
name: "sampled",
|
||||
sc: core.SpanContext{
|
||||
TraceID: core.TraceID{
|
||||
High: uint64(42),
|
||||
Low: uint64(42),
|
||||
},
|
||||
TraceID: core.TraceID([16]byte{1}),
|
||||
TraceFlags: core.TraceFlagsSampled,
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "sampled plus unused",
|
||||
sc: core.SpanContext{
|
||||
TraceID: core.TraceID{
|
||||
High: uint64(42),
|
||||
Low: uint64(42),
|
||||
},
|
||||
TraceID: core.TraceID([16]byte{1}),
|
||||
TraceFlags: core.TraceFlagsSampled | core.TraceFlagsUnused,
|
||||
},
|
||||
want: true,
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
otelcore "go.opentelemetry.io/api/core"
|
||||
oteltrace "go.opentelemetry.io/api/trace"
|
||||
|
||||
migration "go.opentelemetry.io/experimental/bridge/opentracing/migration"
|
||||
"go.opentelemetry.io/experimental/bridge/opentracing/migration"
|
||||
)
|
||||
|
||||
type bridgeSpanContext struct {
|
||||
@ -512,7 +512,7 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
|
||||
if !ok {
|
||||
return ot.ErrInvalidCarrier
|
||||
}
|
||||
hhcarrier.Set(traceIDHeader, traceIDString(bridgeSC.otelSpanContext.TraceID))
|
||||
hhcarrier.Set(traceIDHeader, bridgeSC.otelSpanContext.TraceIDString())
|
||||
hhcarrier.Set(spanIDHeader, spanIDToString(bridgeSC.otelSpanContext.SpanID))
|
||||
hhcarrier.Set(traceFlagsHeader, traceFlagsToString(bridgeSC.otelSpanContext.TraceFlags))
|
||||
bridgeSC.ForeachBaggageItem(func(k, v string) bool {
|
||||
@ -523,12 +523,6 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
|
||||
return nil
|
||||
}
|
||||
|
||||
// mostly copied from core/span_context.go, but I prefer not to rely
|
||||
// on some impl details
|
||||
func traceIDString(traceID otelcore.TraceID) string {
|
||||
return fmt.Sprintf("%.16x%.16x", traceID.High, traceID.Low)
|
||||
}
|
||||
|
||||
func spanIDToString(spanID uint64) string {
|
||||
return fmt.Sprintf("%.16x", spanID)
|
||||
}
|
||||
@ -558,7 +552,7 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
||||
ck := http.CanonicalHeaderKey(k)
|
||||
switch ck {
|
||||
case traceIDHeader:
|
||||
traceID, err := traceIDFromString(v)
|
||||
traceID, err := otelcore.TraceIDFromHex(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -588,23 +582,6 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
||||
return bridgeSC, nil
|
||||
}
|
||||
|
||||
func traceIDFromString(s string) (otelcore.TraceID, error) {
|
||||
traceID := otelcore.TraceID{}
|
||||
if len(s) != 32 {
|
||||
return traceID, fmt.Errorf("invalid trace ID")
|
||||
}
|
||||
high, err := strconv.ParseUint(s[0:16], 16, 64)
|
||||
if err != nil {
|
||||
return traceID, err
|
||||
}
|
||||
low, err := strconv.ParseUint(s[16:32], 16, 64)
|
||||
if err != nil {
|
||||
return traceID, err
|
||||
}
|
||||
traceID.High, traceID.Low = high, low
|
||||
return traceID, nil
|
||||
}
|
||||
|
||||
func spanIDFromString(s string) (uint64, error) {
|
||||
if len(s) != 16 {
|
||||
return 0, fmt.Errorf("invalid span ID")
|
||||
|
@ -145,11 +145,7 @@ func (t *MockTracer) getTraceID(ctx context.Context, spanOpts *oteltrace.SpanOpt
|
||||
}
|
||||
return traceID
|
||||
}
|
||||
uints := t.getNRandUint64(2)
|
||||
return otelcore.TraceID{
|
||||
High: uints[0],
|
||||
Low: uints[1],
|
||||
}
|
||||
return t.getRandTraceID()
|
||||
}
|
||||
|
||||
func (t *MockTracer) getParentSpanID(ctx context.Context, spanOpts *oteltrace.SpanOptions) uint64 {
|
||||
@ -183,17 +179,19 @@ func (t *MockTracer) getSpanID() uint64 {
|
||||
}
|
||||
|
||||
func (t *MockTracer) getRandUint64() uint64 {
|
||||
return t.getNRandUint64(1)[0]
|
||||
}
|
||||
|
||||
func (t *MockTracer) getNRandUint64(n int) []uint64 {
|
||||
uints := make([]uint64, n)
|
||||
t.randLock.Lock()
|
||||
defer t.randLock.Unlock()
|
||||
for i := 0; i < n; i++ {
|
||||
uints[i] = t.rand.Uint64()
|
||||
}
|
||||
return uints
|
||||
return t.rand.Uint64()
|
||||
}
|
||||
|
||||
func (t *MockTracer) getRandTraceID() otelcore.TraceID {
|
||||
t.randLock.Lock()
|
||||
defer t.randLock.Unlock()
|
||||
|
||||
tid := otelcore.TraceID{}
|
||||
t.rand.Read(tid[:])
|
||||
|
||||
return tid
|
||||
}
|
||||
|
||||
func (t *MockTracer) DeferredContextSetupHook(ctx context.Context, span oteltrace.Span) context.Context {
|
||||
|
@ -504,10 +504,7 @@ func reverse(length int, swap func(i, j int)) {
|
||||
}
|
||||
|
||||
func simpleTraceID() otelcore.TraceID {
|
||||
return otelcore.TraceID{
|
||||
High: 1357,
|
||||
Low: 2468,
|
||||
}
|
||||
return [16]byte{123, 42}
|
||||
}
|
||||
|
||||
func simpleSpanIDs(count int) []uint64 {
|
||||
|
@ -16,6 +16,7 @@ package jaeger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
@ -196,8 +197,8 @@ func spanDataToThrift(data *export.SpanData) *gen.Span {
|
||||
var refs []*gen.SpanRef
|
||||
for _, link := range data.Links {
|
||||
refs = append(refs, &gen.SpanRef{
|
||||
TraceIdHigh: int64(link.TraceID.High),
|
||||
TraceIdLow: int64(link.TraceID.Low),
|
||||
TraceIdHigh: int64(binary.BigEndian.Uint64(link.TraceID[0:8])),
|
||||
TraceIdLow: int64(binary.BigEndian.Uint64(link.TraceID[8:16])),
|
||||
SpanId: int64(link.SpanID),
|
||||
// TODO(paivagustavo): properly set the reference type when specs are defined
|
||||
// see https://github.com/open-telemetry/opentelemetry-specification/issues/65
|
||||
@ -206,8 +207,8 @@ func spanDataToThrift(data *export.SpanData) *gen.Span {
|
||||
}
|
||||
|
||||
return &gen.Span{
|
||||
TraceIdHigh: int64(data.SpanContext.TraceID.High),
|
||||
TraceIdLow: int64(data.SpanContext.TraceID.Low),
|
||||
TraceIdHigh: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[0:8])),
|
||||
TraceIdLow: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[8:16])),
|
||||
SpanId: int64(data.SpanContext.SpanID),
|
||||
ParentSpanId: int64(data.ParentSpanID),
|
||||
OperationName: data.Name, // TODO: if span kind is added then add prefix "Sent"/"Recv"
|
||||
|
@ -15,6 +15,7 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
@ -35,10 +36,10 @@ import (
|
||||
|
||||
func Test_spanDataToThrift(t *testing.T) {
|
||||
now := time.Now()
|
||||
traceID := core.TraceID{High: 0x0102030405060708, Low: 0x090a0b0c0d0e0f10}
|
||||
traceID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
||||
spanID := uint64(0x0102030405060708)
|
||||
|
||||
linkTraceID := core.TraceID{High: 0x0102030405060709, Low: 0x090a0b0c0d0e0f11}
|
||||
linkTraceID, _ := core.TraceIDFromHex("0102030405060709090a0b0c0d0e0f11")
|
||||
linkSpanID := uint64(0x0102030405060709)
|
||||
|
||||
keyValue := "value"
|
||||
@ -99,8 +100,8 @@ func Test_spanDataToThrift(t *testing.T) {
|
||||
References: []*gen.SpanRef{
|
||||
{
|
||||
RefType: gen.SpanRefType_CHILD_OF,
|
||||
TraceIdLow: int64(linkTraceID.Low),
|
||||
TraceIdHigh: int64(linkTraceID.High),
|
||||
TraceIdHigh: int64(binary.BigEndian.Uint64(linkTraceID[0:8])),
|
||||
TraceIdLow: int64(binary.BigEndian.Uint64(linkTraceID[8:16])),
|
||||
SpanId: int64(linkSpanID),
|
||||
},
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ func TestExporter_ExportSpan(t *testing.T) {
|
||||
|
||||
// setup test span
|
||||
now := time.Now()
|
||||
traceID := core.TraceID{High: 0x0102030405060708, Low: 0x090a0b0c0d0e0f10}
|
||||
traceID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
|
||||
spanID := uint64(0x0102030405060708)
|
||||
keyValue := "value"
|
||||
doubleValue := float64(123.456)
|
||||
@ -70,8 +70,8 @@ func TestExporter_ExportSpan(t *testing.T) {
|
||||
|
||||
got := b.String()
|
||||
expectedOutput := `{"SpanContext":{` +
|
||||
`"TraceID":{"High":72623859790382856,"Low":651345242494996240},` +
|
||||
`"SpanID":72623859790382856,"TraceFlags":0},` +
|
||||
`"TraceID":"0102030405060708090a0b0c0d0e0f10",` +
|
||||
`"SpanID":"0102030405060708","TraceFlags":0},` +
|
||||
`"ParentSpanID":0,` +
|
||||
`"SpanKind":0,` +
|
||||
`"Name":"/foo",` +
|
||||
|
@ -16,7 +16,7 @@ package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"crypto/rand"
|
||||
"sync/atomic"
|
||||
|
||||
"go.opentelemetry.io/api/core"
|
||||
@ -69,12 +69,8 @@ func (mt *MockTracer) Start(ctx context.Context, name string, o ...apitrace.Span
|
||||
var span *MockSpan
|
||||
var sc core.SpanContext
|
||||
if !opts.Relation.SpanContext.IsValid() {
|
||||
sc = core.SpanContext{
|
||||
TraceID: core.TraceID{
|
||||
High: rand.Uint64(),
|
||||
Low: rand.Uint64(),
|
||||
},
|
||||
}
|
||||
sc = core.SpanContext{}
|
||||
_, _ = rand.Read(sc.TraceID[:])
|
||||
if mt.Sampled {
|
||||
sc.TraceFlags = core.TraceFlagsSampled
|
||||
}
|
||||
|
@ -38,8 +38,7 @@ func (bp binaryPropagator) ToBytes(sc core.SpanContext) []byte {
|
||||
return nil
|
||||
}
|
||||
var b [29]byte
|
||||
binary.BigEndian.PutUint64(b[2:10], sc.TraceID.High)
|
||||
binary.BigEndian.PutUint64(b[10:18], sc.TraceID.Low)
|
||||
copy(b[2:18], sc.TraceID[:])
|
||||
b[18] = 1
|
||||
binary.BigEndian.PutUint64(b[19:27], sc.SpanID)
|
||||
b[27] = 2
|
||||
@ -55,8 +54,7 @@ func (bp binaryPropagator) FromBytes(b []byte) (sc core.SpanContext) {
|
||||
}
|
||||
b = b[1:]
|
||||
if len(b) >= 17 && b[0] == 0 {
|
||||
sc.TraceID.High = binary.BigEndian.Uint64(b[1:9])
|
||||
sc.TraceID.Low = binary.BigEndian.Uint64(b[9:17])
|
||||
copy(sc.TraceID[:], b[1:17])
|
||||
b = b[17:]
|
||||
} else {
|
||||
return core.EmptySpanContext()
|
||||
|
@ -15,6 +15,7 @@
|
||||
package propagation_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@ -24,7 +25,10 @@ import (
|
||||
)
|
||||
|
||||
func TestExtractSpanContextFromBytes(t *testing.T) {
|
||||
traceID := core.TraceID{High: 0x4bf92f3577b34da6, Low: 0xa3ce929d0e0e4736}
|
||||
bTraceID, _ := hex.DecodeString("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||
traceID := core.TraceID{}
|
||||
copy(traceID[:], bTraceID)
|
||||
|
||||
spanID := uint64(0x00f067aa0ba902b7)
|
||||
propagator := propagation.BinaryPropagator()
|
||||
tests := []struct {
|
||||
@ -119,7 +123,10 @@ func TestExtractSpanContextFromBytes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConvertSpanContextToBytes(t *testing.T) {
|
||||
traceID := core.TraceID{High: 0x4bf92f3577b34da6, Low: 0xa3ce929d0e0e4736}
|
||||
bTraceID, _ := hex.DecodeString("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||
traceID := core.TraceID{}
|
||||
copy(traceID[:], bTraceID)
|
||||
|
||||
spanID := uint64(0x00f067aa0ba902b7)
|
||||
propagator := propagation.BinaryPropagator()
|
||||
tests := []struct {
|
||||
|
@ -57,7 +57,6 @@ type HTTPB3Propagator struct {
|
||||
|
||||
var _ apipropagation.TextFormatPropagator = HTTPB3Propagator{}
|
||||
|
||||
var hexStr32ByteRegex = regexp.MustCompile("^[a-f0-9]{32}$")
|
||||
var hexStr16ByteRegex = regexp.MustCompile("^[a-f0-9]{16}$")
|
||||
|
||||
func (b3 HTTPB3Propagator) Inject(ctx context.Context, supplier apipropagation.Supplier) {
|
||||
@ -66,10 +65,9 @@ func (b3 HTTPB3Propagator) Inject(ctx context.Context, supplier apipropagation.S
|
||||
if b3.SingleHeader {
|
||||
sampled := sc.TraceFlags & core.TraceFlagsSampled
|
||||
supplier.Set(B3SingleHeader,
|
||||
fmt.Sprintf("%.16x%.16x-%.16x-%.1d", sc.TraceID.High, sc.TraceID.Low, sc.SpanID, sampled))
|
||||
fmt.Sprintf("%s-%.16x-%.1d", sc.TraceIDString(), sc.SpanID, sampled))
|
||||
} else {
|
||||
supplier.Set(B3TraceIDHeader,
|
||||
fmt.Sprintf("%.16x%.16x", sc.TraceID.High, sc.TraceID.Low))
|
||||
supplier.Set(B3TraceIDHeader, sc.TraceIDString())
|
||||
supplier.Set(B3SpanIDHeader,
|
||||
fmt.Sprintf("%.16x", sc.SpanID))
|
||||
|
||||
@ -183,15 +181,8 @@ func (b3 HTTPB3Propagator) extractSingleHeader(supplier apipropagation.Supplier)
|
||||
|
||||
// extractTraceID parses the value of the X-B3-TraceId b3Header.
|
||||
func (b3 HTTPB3Propagator) extractTraceID(tid string) (traceID core.TraceID, ok bool) {
|
||||
if hexStr32ByteRegex.MatchString(tid) {
|
||||
traceID.High, _ = strconv.ParseUint(tid[0:(16)], 16, 64)
|
||||
traceID.Low, _ = strconv.ParseUint(tid[(16):32], 16, 64)
|
||||
ok = true
|
||||
} else if b3.SingleHeader && hexStr16ByteRegex.MatchString(tid) {
|
||||
traceID.Low, _ = strconv.ParseUint(tid[:16], 16, 64)
|
||||
ok = true
|
||||
}
|
||||
return traceID, ok
|
||||
traceID, err := core.TraceIDFromHex(tid)
|
||||
return traceID, err == nil
|
||||
}
|
||||
|
||||
// extractSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
|
||||
|
@ -46,10 +46,9 @@ var traceCtxRegExp = regexp.MustCompile("^[0-9a-f]{2}-[a-f0-9]{32}-[a-f0-9]{16}-
|
||||
func (hp HTTPTraceContextPropagator) Inject(ctx context.Context, supplier apipropagation.Supplier) {
|
||||
sc := trace.CurrentSpan(ctx).SpanContext()
|
||||
if sc.IsValid() {
|
||||
h := fmt.Sprintf("%.2x-%.16x%.16x-%.16x-%.2x",
|
||||
h := fmt.Sprintf("%.2x-%s-%.16x-%.2x",
|
||||
supportedVersion,
|
||||
sc.TraceID.High,
|
||||
sc.TraceID.Low,
|
||||
sc.TraceIDString(),
|
||||
sc.SpanID,
|
||||
sc.TraceFlags&core.TraceFlagsSampled)
|
||||
supplier.Set(TraceparentHeader, h)
|
||||
@ -118,24 +117,17 @@ func (hp HTTPTraceContextPropagator) extractSpanContext(
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
|
||||
result, err := strconv.ParseUint(sections[1][0:16], 16, 64)
|
||||
if err != nil {
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
var sc core.SpanContext
|
||||
|
||||
sc.TraceID.High = result
|
||||
|
||||
result, err = strconv.ParseUint(sections[1][16:32], 16, 64)
|
||||
_, err = hex.Decode(sc.TraceID[0:16], []byte(sections[1][0:32]))
|
||||
if err != nil {
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
sc.TraceID.Low = result
|
||||
|
||||
if len(sections[2]) != 16 {
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
result, err = strconv.ParseUint(sections[2][0:], 16, 64)
|
||||
result, err := strconv.ParseUint(sections[2][0:], 16, 64)
|
||||
if err != nil {
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package propagation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -27,8 +28,11 @@ func injectSubBenchmarks(b *testing.B, fn func(context.Context, *testing.B)) {
|
||||
var (
|
||||
id uint64
|
||||
spanID = uint64(0x00f067aa0ba902b7)
|
||||
traceID = core.TraceID{High: 0x4bf92f3577b34da6, Low: 0xa3ce929d0e0e4736}
|
||||
traceID = core.TraceID{}
|
||||
)
|
||||
bt, _ := hex.DecodeString("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||
copy(traceID[:], bt)
|
||||
|
||||
mockTracer := &mocktrace.MockTracer{
|
||||
Sampled: false,
|
||||
StartSpanID: &id,
|
||||
|
@ -31,10 +31,15 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
traceID = core.TraceID{High: 0x4bf92f3577b34da6, Low: 0xa3ce929d0e0e4736}
|
||||
traceID = mustTraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||
spanID = uint64(0x00f067aa0ba902b7)
|
||||
)
|
||||
|
||||
func mustTraceIDFromHex(s string) (t core.TraceID) {
|
||||
t, _ = core.TraceIDFromHex(s)
|
||||
return
|
||||
}
|
||||
|
||||
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||
var propagator propagation.HTTPTraceContextPropagator
|
||||
tests := []struct {
|
||||
|
@ -16,6 +16,7 @@ package trace_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@ -164,7 +165,7 @@ func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
|
||||
// Check first Span is reported. Most recent one is dropped.
|
||||
sc := getSpanContext()
|
||||
wantTraceID := sc.TraceID
|
||||
wantTraceID.High = 1
|
||||
binary.BigEndian.PutUint64(wantTraceID[0:8], uint64(1))
|
||||
gotTraceID := te.get(0).SpanContext.TraceID
|
||||
if wantTraceID != gotTraceID {
|
||||
t.Errorf("%s: first exported span: got %+v, want %+v\n", option.name, gotTraceID, wantTraceID)
|
||||
@ -185,14 +186,14 @@ func generateSpan(t *testing.T, tr apitrace.Tracer, option testOption) {
|
||||
sc := getSpanContext()
|
||||
|
||||
for i := 0; i < option.genNumSpans; i++ {
|
||||
sc.TraceID.High = uint64(i + 1)
|
||||
binary.BigEndian.PutUint64(sc.TraceID[0:8], uint64(i+1))
|
||||
_, span := tr.Start(context.Background(), option.name, apitrace.ChildOf(sc))
|
||||
span.End()
|
||||
}
|
||||
}
|
||||
|
||||
func getSpanContext() core.SpanContext {
|
||||
tid := core.TraceID{High: 0x0102030405060708, Low: 0x0102040810203040}
|
||||
tid, _ := core.TraceIDFromHex("01020304050607080102040810203040")
|
||||
sid := uint64(0x0102040810203040)
|
||||
return core.SpanContext{
|
||||
TraceID: tid,
|
||||
|
@ -147,7 +147,8 @@ func BenchmarkSpanWithAttributes_all_2x(b *testing.B) {
|
||||
|
||||
func BenchmarkTraceID_DotString(b *testing.B) {
|
||||
traceBenchmark(b, func(b *testing.B) {
|
||||
sc := core.SpanContext{TraceID: core.TraceID{High: 1, Low: 0x2a}}
|
||||
t, _ := core.TraceIDFromHex("0000000000000001000000000000002a")
|
||||
sc := core.SpanContext{TraceID: t}
|
||||
|
||||
want := "0000000000000001000000000000002a"
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -59,9 +59,7 @@ func (gen *defaultIDGenerator) NewTraceID() core.TraceID {
|
||||
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{
|
||||
High: gen.traceIDRand.Uint64() + gen.traceIDAdd[0],
|
||||
Low: gen.traceIDRand.Uint64() + gen.traceIDAdd[1],
|
||||
}
|
||||
tid := core.TraceID{}
|
||||
gen.traceIDRand.Read(tid[:])
|
||||
return tid
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"go.opentelemetry.io/api/core"
|
||||
)
|
||||
|
||||
@ -52,7 +54,7 @@ func ProbabilitySampler(fraction float64) Sampler {
|
||||
if p.ParentContext.IsSampled() {
|
||||
return SamplingDecision{Sample: true}
|
||||
}
|
||||
x := p.TraceID.High >> 1
|
||||
x := binary.BigEndian.Uint64(p.TraceID[0:8]) >> 1
|
||||
return SamplingDecision{Sample: x < traceIDUpperBound}
|
||||
})
|
||||
}
|
||||
|
@ -55,9 +55,10 @@ func TestSimpleSpanProcessorOnEnd(t *testing.T) {
|
||||
if ssp == nil {
|
||||
t.Errorf("Error creating new instance of SimpleSpanProcessor with nil Exporter\n")
|
||||
}
|
||||
|
||||
tp.RegisterSpanProcessor(ssp)
|
||||
tr := tp.GetTracer("SimpleSpanProcessor")
|
||||
tid := core.TraceID{High: 0x0102030405060708, Low: 0x0102040810203040}
|
||||
tid, _ := core.TraceIDFromHex("01020304050607080102040810203040")
|
||||
sid := uint64(0x0102040810203040)
|
||||
sc := core.SpanContext{
|
||||
TraceID: tid,
|
||||
|
@ -34,10 +34,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
tid = core.TraceID{High: 0x0102030405060708, Low: 0x0102040810203040}
|
||||
tid core.TraceID
|
||||
sid = uint64(0x0102040810203040)
|
||||
)
|
||||
|
||||
func init() {
|
||||
tid, _ = core.TraceIDFromHex("01020304050607080102040810203040")
|
||||
}
|
||||
|
||||
func TestTracerFollowsExpectedAPIBehaviour(t *testing.T) {
|
||||
tp, err := NewProvider(WithConfig(Config{DefaultSampler: ProbabilitySampler(0)}))
|
||||
if err != nil {
|
||||
@ -386,8 +390,8 @@ func TestAddLinks(t *testing.T) {
|
||||
k1v1 := key.New("key1").String("value1")
|
||||
k2v2 := key.New("key2").String("value2")
|
||||
|
||||
sc1 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x1}, SpanID: 0x3}
|
||||
sc2 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x2}, SpanID: 0x3}
|
||||
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
|
||||
link1 := apitrace.Link{SpanContext: sc1, Attributes: []core.KeyValue{k1v1}}
|
||||
link2 := apitrace.Link{SpanContext: sc2, Attributes: []core.KeyValue{k2v2}}
|
||||
@ -426,8 +430,8 @@ func TestLinks(t *testing.T) {
|
||||
k2v2 := key.New("key2").String("value2")
|
||||
k3v3 := key.New("key3").String("value3")
|
||||
|
||||
sc1 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x1}, SpanID: 0x3}
|
||||
sc2 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x2}, SpanID: 0x3}
|
||||
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
|
||||
span.Link(sc1, key.New("key1").String("value1"))
|
||||
span.Link(sc2,
|
||||
@ -460,12 +464,13 @@ func TestLinks(t *testing.T) {
|
||||
func TestLinksOverLimit(t *testing.T) {
|
||||
te := &testExporter{}
|
||||
cfg := Config{MaxLinksPerSpan: 2}
|
||||
tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te))
|
||||
|
||||
sc1 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
sc2 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
sc3 := core.SpanContext{TraceID: core.TraceID([16]byte{1, 1}), SpanID: 0x3}
|
||||
|
||||
tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te))
|
||||
span := startSpan(tp, "LinksOverLimit")
|
||||
sc1 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x1}, SpanID: 0x3}
|
||||
sc2 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x2}, SpanID: 0x3}
|
||||
sc3 := core.SpanContext{TraceID: core.TraceID{High: 0x1, Low: 0x3}, SpanID: 0x3}
|
||||
|
||||
k2v2 := key.New("key2").String("value2")
|
||||
k3v3 := key.New("key3").String("value3")
|
||||
@ -741,12 +746,14 @@ func TestExecutionTracerTaskEnd(t *testing.T) {
|
||||
s.executionTracerTaskEnd = executionTracerTaskEnd
|
||||
spans = append(spans, s) // never sample
|
||||
|
||||
tID, _ := core.TraceIDFromHex("0102030405060708090a0b0c0d0e0f")
|
||||
|
||||
_, apiSpan = tr.Start(
|
||||
context.Background(),
|
||||
"foo",
|
||||
apitrace.ChildOf(
|
||||
core.SpanContext{
|
||||
TraceID: core.TraceID{High: 0x0102030405060708, Low: 0x090a0b0c0d0e0f},
|
||||
TraceID: tID,
|
||||
SpanID: uint64(0x0001020304050607),
|
||||
TraceFlags: 0,
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user