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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- `OTEL_EXPORTER_OTLP_CERTIFICATE`
- `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE`
- `OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE`
- `trace.TraceFlags` is now a defined type over `byte` and `WithSampled(bool) TraceFlags` and `IsSampled() bool` methods have been added to it. (#1770)

### Fixed

Expand Down Expand Up @@ -65,6 +66,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
If needed, that Span's `SpanContext.IsRemote()` can then be used to determine if it is remote or not. (#1731)
- The `HasRemoteParent` field of the `"go.opentelemetry.io/otel/sdk/trace".SamplingParameters` is removed.
This field is redundant to the information returned from the `Remote` method of the `SpanContext` held in the `ParentContext` field. (#1749)
- The `trace.FlagsDebug` and `trace.FlagsDeferred` constants have been removed and will be localized to the B3 propagator. (#1770)

## [0.19.0] - 2021-03-18

Expand Down
8 changes: 1 addition & 7 deletions bridge/opencensus/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,15 @@
package utils // import "go.opentelemetry.io/otel/bridge/opencensus/utils"

import (
"fmt"

octrace "go.opencensus.io/trace"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
)

// OTelSpanContextToOC converts from an OpenTelemetry SpanContext to an
// OpenCensus SpanContext, and handles any incompatibilities with the global
// error handler.
func OTelSpanContextToOC(sc trace.SpanContext) octrace.SpanContext {
if sc.IsDebug() || sc.IsDeferred() {
otel.Handle(fmt.Errorf("ignoring OpenTelemetry Debug or Deferred trace flags for span %q because they are not supported by OpenCensus", sc.SpanID()))
}
var to octrace.TraceOptions
if sc.IsSampled() {
// OpenCensus doesn't expose functions to directly set sampled
Expand All @@ -45,7 +39,7 @@ func OTelSpanContextToOC(sc trace.SpanContext) octrace.SpanContext {
// OCSpanContextToOTel converts from an OpenCensus SpanContext to an
// OpenTelemetry SpanContext.
func OCSpanContextToOTel(sc octrace.SpanContext) trace.SpanContext {
var traceFlags byte
var traceFlags trace.TraceFlags
if sc.IsSampled() {
traceFlags = trace.FlagsSampled
}
Expand Down
13 changes: 0 additions & 13 deletions bridge/opencensus/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,6 @@ func TestOTelSpanContextToOC(t *testing.T) {
TraceOptions: octrace.TraceOptions(0),
},
},
{
description: "debug flag",
input: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{1}),
SpanID: trace.SpanID([8]byte{2}),
TraceFlags: trace.FlagsDebug,
}),
expected: octrace.SpanContext{
TraceID: octrace.TraceID([16]byte{1}),
SpanID: octrace.SpanID([8]byte{2}),
TraceOptions: octrace.TraceOptions(0),
},
},
} {
t.Run(tc.description, func(t *testing.T) {
output := OTelSpanContextToOC(tc.input)
Expand Down
10 changes: 5 additions & 5 deletions exporters/otlp/otlp_span_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestExportSpans(t *testing.T) {
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}),
SpanID: trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
TraceFlags: byte(1),
TraceFlags: trace.FlagsSampled,
}),
SpanKind: trace.SpanKindServer,
Name: "parent process",
Expand All @@ -80,7 +80,7 @@ func TestExportSpans(t *testing.T) {
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}),
SpanID: trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
TraceFlags: byte(1),
TraceFlags: trace.FlagsSampled,
}),
SpanKind: trace.SpanKindServer,
Name: "secondary parent process",
Expand All @@ -102,12 +102,12 @@ func TestExportSpans(t *testing.T) {
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}),
SpanID: trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 2}),
TraceFlags: byte(1),
TraceFlags: trace.FlagsSampled,
}),
Parent: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}),
SpanID: trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
TraceFlags: byte(1),
TraceFlags: trace.FlagsSampled,
}),
SpanKind: trace.SpanKindInternal,
Name: "internal process",
Expand All @@ -129,7 +129,7 @@ func TestExportSpans(t *testing.T) {
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}),
SpanID: trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1}),
TraceFlags: byte(1),
TraceFlags: trace.FlagsSampled,
}),
SpanKind: trace.SpanKindServer,
Name: "parent process",
Expand Down
4 changes: 2 additions & 2 deletions exporters/stdout/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestExporter_ExportSpan(t *testing.T) {
got := b.String()
expectedOutput := `[{"SpanContext":{` +
`"TraceID":"0102030405060708090a0b0c0d0e0f10",` +
`"SpanID":"0102030405060708","TraceFlags":0,` +
`"SpanID":"0102030405060708","TraceFlags":"00",` +
`"TraceState":[` +
`{` +
`"Key":"key",` +
Expand All @@ -87,7 +87,7 @@ func TestExporter_ExportSpan(t *testing.T) {
`"Parent":{` +
`"TraceID":"00000000000000000000000000000000",` +
`"SpanID":"0000000000000000",` +
`"TraceFlags":0,` +
`"TraceFlags":"00",` +
`"TraceState":null,` +
`"Remote":false` +
`},` +
Expand Down
9 changes: 6 additions & 3 deletions propagation/trace_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,14 @@ func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {

carrier.Set(tracestateHeader, sc.TraceState().String())

h := fmt.Sprintf("%.2x-%s-%s-%.2x",
// Clear all flags other than the trace-context supported sampling bit.
flags := sc.TraceFlags() & trace.FlagsSampled

h := fmt.Sprintf("%.2x-%s-%s-%s",
supportedVersion,
sc.TraceID(),
sc.SpanID(),
sc.TraceFlags()&trace.FlagsSampled)
flags)
carrier.Set(traceparentHeader, h)
}

Expand Down Expand Up @@ -134,7 +137,7 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
return trace.SpanContext{}
}
// Clear all flags other than the trace-context supported sampling bit.
scc.TraceFlags = opts[0] & trace.FlagsSampled
scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled

scc.TraceState = parseTraceState(carrier.Get(tracestateHeader))
scc.Remote = true
Expand Down
2 changes: 1 addition & 1 deletion sdk/trace/simple_span_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
ssp.exporterMu.RLock()
defer ssp.exporterMu.RUnlock()

if ssp.exporter != nil && s.SpanContext().IsSampled() {
if ssp.exporter != nil && s.SpanContext().TraceFlags().IsSampled() {
ss := s.Snapshot()
if err := ssp.exporter.ExportSpans(context.Background(), []*export.SpanSnapshot{ss}); err != nil {
otel.Handle(err)
Expand Down
64 changes: 38 additions & 26 deletions trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,7 @@ import (
const (
// FlagsSampled is a bitmask with the sampled bit set. A SpanContext
// with the sampling bit set means the span is sampled.
FlagsSampled = byte(0x01)
// FlagsDeferred is a bitmask with the deferred bit set. A SpanContext
// with the deferred bit set means the sampling decision has been
// defered to the receiver.
FlagsDeferred = byte(0x02)
// FlagsDebug is a bitmask with the debug bit set.
FlagsDebug = byte(0x04)
FlagsSampled = TraceFlags(0x01)

errInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase"

Expand Down Expand Up @@ -319,12 +313,40 @@ func isTraceStateKeyValueValid(kv attribute.KeyValue) bool {
valueFormatRegExp.MatchString(kv.Value.Emit())
}

// TraceFlags contains flags that can be set on a SpanContext
type TraceFlags byte //nolint:golint

// IsSampled returns if the sampling bit is set in the TraceFlags.
func (tf TraceFlags) IsSampled() bool {
return tf&FlagsSampled == FlagsSampled
}

// WithSampled sets the sampling bit in a new copy of the TraceFlags.
func (tf TraceFlags) WithSampled(sampled bool) TraceFlags {
if sampled {
return tf | FlagsSampled
}

return tf &^ FlagsSampled
}

// MarshalJSON implements a custom marshal function to encode TraceFlags
// as a hex string.
func (tf TraceFlags) MarshalJSON() ([]byte, error) {
return json.Marshal(tf.String())
}

// String returns the hex string representation form of TraceFlags
func (tf TraceFlags) String() string {
return hex.EncodeToString([]byte{byte(tf)}[:])
}

// SpanContextConfig contains mutable fields usable for constructing
// an immutable SpanContext.
type SpanContextConfig struct {
TraceID TraceID
SpanID SpanID
TraceFlags byte
TraceFlags TraceFlags
TraceState TraceState
Remote bool
}
Expand All @@ -345,7 +367,7 @@ func NewSpanContext(config SpanContextConfig) SpanContext {
type SpanContext struct {
traceID TraceID
spanID SpanID
traceFlags byte
traceFlags TraceFlags
traceState TraceState
remote bool
}
Expand Down Expand Up @@ -415,12 +437,17 @@ func (sc SpanContext) WithSpanID(spanID SpanID) SpanContext {
}

// TraceFlags returns the flags from the SpanContext.
func (sc SpanContext) TraceFlags() byte {
func (sc SpanContext) TraceFlags() TraceFlags {
return sc.traceFlags
}

// IsSampled returns if the sampling bit is set in the SpanContext's TraceFlags.
func (sc SpanContext) IsSampled() bool {
return sc.traceFlags.IsSampled()
}

// WithTraceFlags returns a new SpanContext with the TraceFlags replaced.
func (sc SpanContext) WithTraceFlags(flags byte) SpanContext {
func (sc SpanContext) WithTraceFlags(flags TraceFlags) SpanContext {
return SpanContext{
traceID: sc.traceID,
spanID: sc.spanID,
Expand All @@ -430,21 +457,6 @@ func (sc SpanContext) WithTraceFlags(flags byte) SpanContext {
}
}

// IsDeferred returns if the deferred bit is set in the trace flags.
func (sc SpanContext) IsDeferred() bool {
return sc.traceFlags&FlagsDeferred == FlagsDeferred
}

// IsDebug returns if the debug bit is set in the trace flags.
func (sc SpanContext) IsDebug() bool {
return sc.traceFlags&FlagsDebug == FlagsDebug
}

// IsSampled returns if the sampling bit is set in the trace flags.
func (sc SpanContext) IsSampled() bool {
return sc.traceFlags&FlagsSampled == FlagsSampled
}
Comment thread
Aneurysm9 marked this conversation as resolved.

// TraceState returns the TraceState from the SpanContext.
func (sc SpanContext) TraceState() TraceState {
return sc.traceState
Expand Down
62 changes: 46 additions & 16 deletions trace/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,41 +164,71 @@ func TestHasSpanID(t *testing.T) {
}
}

func TestSpanContextIsSampled(t *testing.T) {
func TestTraceFlagsIsSampled(t *testing.T) {
for _, testcase := range []struct {
name string
sc SpanContext
tf TraceFlags
want bool
}{
{
name: "sampled",
sc: SpanContext{
traceID: TraceID([16]byte{1}),
traceFlags: FlagsSampled,
},
tf: FlagsSampled,
want: true,
}, {
name: "unused bits are ignored, still not sampled",
sc: SpanContext{
traceID: TraceID([16]byte{1}),
traceFlags: ^FlagsSampled,
},
tf: ^FlagsSampled,
want: false,
}, {
name: "unused bits are ignored, still sampled",
sc: SpanContext{
traceID: TraceID([16]byte{1}),
traceFlags: FlagsSampled | ^FlagsSampled,
},
tf: FlagsSampled | ^FlagsSampled,
want: true,
}, {
name: "not sampled/default",
sc: SpanContext{traceID: TraceID{}},
want: false,
},
} {
t.Run(testcase.name, func(t *testing.T) {
have := testcase.sc.IsSampled()
have := testcase.tf.IsSampled()
if have != testcase.want {
t.Errorf("Want: %v, but have: %v", testcase.want, have)
}
})
}
}

func TestTraceFlagsWithSampled(t *testing.T) {
for _, testcase := range []struct {
name string
start TraceFlags
sample bool
want TraceFlags
}{
{
name: "sampled unchanged",
start: FlagsSampled,
want: FlagsSampled,
sample: true,
}, {
name: "become sampled",
want: FlagsSampled,
sample: true,
}, {
name: "unused bits are ignored, still not sampled",
start: ^FlagsSampled,
want: ^FlagsSampled,
sample: false,
}, {
name: "unused bits are ignored, becomes sampled",
start: ^FlagsSampled,
want: FlagsSampled | ^FlagsSampled,
sample: true,
}, {
name: "not sampled/default",
sample: false,
},
} {
t.Run(testcase.name, func(t *testing.T) {
have := testcase.start.WithSampled(testcase.sample)
if have != testcase.want {
t.Errorf("Want: %v, but have: %v", testcase.want, have)
}
Expand Down