summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Ashpole <dashpole@google.com>2020-10-22 14:54:54 -0700
committerGitHub <noreply@github.com>2020-10-23 08:54:54 +1100
commitfc3822be251c0e5c0d1b92bd51fabe401fe3c0bf (patch)
treec435e951d1d8c17f47f29c84e827d097d156df4f
parent3fb168f674736c026e623310bfccb0691e6dec8a (diff)
downloadopencensus-go-fc3822be251c0e5c0d1b92bd51fabe401fe3c0bf.tar.gz
Allow replacing trace SDK (#1234)
-rw-r--r--go.sum2
-rw-r--r--plugin/ochttp/client.go4
-rw-r--r--plugin/ochttp/server.go2
-rw-r--r--plugin/ochttp/server_test.go2
-rw-r--r--plugin/ochttp/span_annotating_client_trace.go6
-rw-r--r--plugin/ochttp/trace.go4
-rw-r--r--plugin/ochttp/trace_test.go2
-rw-r--r--trace/basetypes.go10
-rw-r--r--trace/examples_test.go2
-rw-r--r--trace/spanstore.go14
-rw-r--r--trace/trace.go86
-rw-r--r--trace/trace_api.go138
-rw-r--r--trace/trace_test.go53
13 files changed, 245 insertions, 80 deletions
diff --git a/go.sum b/go.sum
index 01c0297..4294159 100644
--- a/go.sum
+++ b/go.sum
@@ -48,6 +48,8 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/plugin/ochttp/client.go b/plugin/ochttp/client.go
index da815b2..791de85 100644
--- a/plugin/ochttp/client.go
+++ b/plugin/ochttp/client.go
@@ -56,10 +56,10 @@ type Transport struct {
// name equals the URL Path.
FormatSpanName func(*http.Request) string
- // NewClientTrace may be set to a function allowing the current *trace.Span
+ // NewClientTrace may be set to a function allowing the current trace.Span
// to be annotated with HTTP request event information emitted by the
// httptrace package.
- NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
+ NewClientTrace func(*http.Request, trace.Span) *httptrace.ClientTrace
// TODO: Implement tag propagation for HTTP.
}
diff --git a/plugin/ochttp/server.go b/plugin/ochttp/server.go
index c7ea642..69b357c 100644
--- a/plugin/ochttp/server.go
+++ b/plugin/ochttp/server.go
@@ -109,7 +109,7 @@ func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Requ
startOpts = h.GetStartOptions(r)
}
- var span *trace.Span
+ var span trace.Span
sc, ok := h.extractSpanContext(r)
if ok && !h.IsPublicEndpoint {
ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
diff --git a/plugin/ochttp/server_test.go b/plugin/ochttp/server_test.go
index 6e4ed5f..69c6a70 100644
--- a/plugin/ochttp/server_test.go
+++ b/plugin/ochttp/server_test.go
@@ -584,7 +584,7 @@ func TestIgnoreHealthEndpoints(t *testing.T) {
ts := httptest.NewServer(&Handler{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
span := trace.FromContext(r.Context())
- if span != nil {
+ if span.IsRecordingEvents() {
spans++
}
fmt.Fprint(w, "ok")
diff --git a/plugin/ochttp/span_annotating_client_trace.go b/plugin/ochttp/span_annotating_client_trace.go
index 05c6c56..be29c64 100644
--- a/plugin/ochttp/span_annotating_client_trace.go
+++ b/plugin/ochttp/span_annotating_client_trace.go
@@ -24,7 +24,7 @@ import (
)
type spanAnnotator struct {
- sp *trace.Span
+ sp trace.Span
}
// TODO: Remove NewSpanAnnotator at the next release.
@@ -32,13 +32,13 @@ type spanAnnotator struct {
// NewSpanAnnotator returns a httptrace.ClientTrace which annotates
// all emitted httptrace events on the provided Span.
// Deprecated: Use NewSpanAnnotatingClientTrace instead
-func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace {
+func NewSpanAnnotator(r *http.Request, s trace.Span) *httptrace.ClientTrace {
return NewSpanAnnotatingClientTrace(r, s)
}
// NewSpanAnnotatingClientTrace returns a httptrace.ClientTrace which annotates
// all emitted httptrace events on the provided Span.
-func NewSpanAnnotatingClientTrace(_ *http.Request, s *trace.Span) *httptrace.ClientTrace {
+func NewSpanAnnotatingClientTrace(_ *http.Request, s trace.Span) *httptrace.ClientTrace {
sa := spanAnnotator{sp: s}
return &httptrace.ClientTrace{
diff --git a/plugin/ochttp/trace.go b/plugin/ochttp/trace.go
index ed3a5db..43f9799 100644
--- a/plugin/ochttp/trace.go
+++ b/plugin/ochttp/trace.go
@@ -44,7 +44,7 @@ type traceTransport struct {
startOptions trace.StartOptions
format propagation.HTTPFormat
formatSpanName func(*http.Request) string
- newClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
+ newClientTrace func(*http.Request, trace.Span) *httptrace.ClientTrace
}
// TODO(jbd): Add message events for request and response size.
@@ -104,7 +104,7 @@ func (t *traceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
// the body of the original response.
type bodyTracker struct {
rc io.ReadCloser
- span *trace.Span
+ span trace.Span
}
var _ io.ReadCloser = (*bodyTracker)(nil)
diff --git a/plugin/ochttp/trace_test.go b/plugin/ochttp/trace_test.go
index 615c271..afb93e6 100644
--- a/plugin/ochttp/trace_test.go
+++ b/plugin/ochttp/trace_test.go
@@ -106,7 +106,7 @@ func TestTransport_RoundTrip(t *testing.T) {
_, parent := trace.StartSpan(context.Background(), "parent")
tests := []struct {
name string
- parent *trace.Span
+ parent trace.Span
}{
{
name: "no parent",
diff --git a/trace/basetypes.go b/trace/basetypes.go
index 0c54492..c8e26ed 100644
--- a/trace/basetypes.go
+++ b/trace/basetypes.go
@@ -49,6 +49,16 @@ type Attribute struct {
value interface{}
}
+// Key returns the attribute's key
+func (a *Attribute) Key() string {
+ return a.key
+}
+
+// Value returns the attribute's value
+func (a *Attribute) Value() interface{} {
+ return a.value
+}
+
// BoolAttribute returns a bool-valued attribute.
func BoolAttribute(key string, value bool) Attribute {
return Attribute{key: key, value: value}
diff --git a/trace/examples_test.go b/trace/examples_test.go
index 286990c..6981ebf 100644
--- a/trace/examples_test.go
+++ b/trace/examples_test.go
@@ -21,7 +21,7 @@ import (
"go.opencensus.io/trace"
)
-// This example shows how to use StartSpan and (*Span).End to capture
+// This example shows how to use StartSpan and (Span).End to capture
// a function execution in a Span. It assumes that the function
// has a context.Context argument.
func ExampleStartSpan() {
diff --git a/trace/spanstore.go b/trace/spanstore.go
index c442d99..b61c1b7 100644
--- a/trace/spanstore.go
+++ b/trace/spanstore.go
@@ -48,8 +48,10 @@ func (i internalOnly) ReportActiveSpans(name string) []*SpanData {
var out []*SpanData
s.mu.Lock()
defer s.mu.Unlock()
- for span := range s.active {
- out = append(out, span.makeSpanData())
+ for activeSpan := range s.active {
+ if s, ok := activeSpan.(*span); ok {
+ out = append(out, s.makeSpanData())
+ }
}
return out
}
@@ -185,7 +187,7 @@ func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency t
// bucketed by latency.
type spanStore struct {
mu sync.Mutex // protects everything below.
- active map[*Span]struct{}
+ active map[Span]struct{}
errors map[int32]*bucket
latency []bucket
maxSpansPerErrorBucket int
@@ -194,7 +196,7 @@ type spanStore struct {
// newSpanStore creates a span store.
func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore {
s := &spanStore{
- active: make(map[*Span]struct{}),
+ active: make(map[Span]struct{}),
latency: make([]bucket, len(defaultLatencies)+1),
maxSpansPerErrorBucket: errorBucketSize,
}
@@ -271,7 +273,7 @@ func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) {
}
// add adds a span to the active bucket of the spanStore.
-func (s *spanStore) add(span *Span) {
+func (s *spanStore) add(span Span) {
s.mu.Lock()
s.active[span] = struct{}{}
s.mu.Unlock()
@@ -279,7 +281,7 @@ func (s *spanStore) add(span *Span) {
// finished removes a span from the active set, and adds a corresponding
// SpanData to a latency or error bucket.
-func (s *spanStore) finished(span *Span, sd *SpanData) {
+func (s *spanStore) finished(span Span, sd *SpanData) {
latency := sd.EndTime.Sub(sd.StartTime)
if latency < 0 {
latency = 0
diff --git a/trace/trace.go b/trace/trace.go
index daf8955..556ddc4 100644
--- a/trace/trace.go
+++ b/trace/trace.go
@@ -28,12 +28,18 @@ import (
"go.opencensus.io/trace/tracestate"
)
+type tracer struct{}
+
+var _ Span = &span{}
+
+var _ Tracer = &tracer{}
+
// Span represents a span of a trace. It has an associated SpanContext, and
// stores data accumulated while the span is active.
//
// Ideally users should interact with Spans by calling the functions in this
// package that take a Context parameter.
-type Span struct {
+type span struct {
// data contains information recorded about the span.
//
// It will be non-nil if we are exporting the span or recording events for it.
@@ -66,7 +72,7 @@ type Span struct {
// IsRecordingEvents returns true if events are being recorded for this span.
// Use this check to avoid computing expensive annotations when they will never
// be used.
-func (s *Span) IsRecordingEvents() bool {
+func (s *span) IsRecordingEvents() bool {
if s == nil {
return false
}
@@ -108,14 +114,16 @@ type SpanContext struct {
type contextKey struct{}
-// FromContext returns the Span stored in a context, or nil if there isn't one.
-func FromContext(ctx context.Context) *Span {
- s, _ := ctx.Value(contextKey{}).(*Span)
+// FromContext returns the *span stored in a context, or a Span that is not
+// recording events if there isn't one.
+func (t *tracer) FromContext(ctx context.Context) Span {
+ s, _ := ctx.Value(contextKey{}).(*span)
return s
}
-// NewContext returns a new context with the given Span attached.
-func NewContext(parent context.Context, s *Span) context.Context {
+// NewContext returns a new context with the given Span attached. This tracer
+// accepts only the *span implementation of Span.
+func (t *tracer) NewContext(parent context.Context, s Span) context.Context {
return context.WithValue(parent, contextKey{}, s)
}
@@ -166,12 +174,14 @@ func WithSampler(sampler Sampler) StartOption {
//
// Returned context contains the newly created span. You can use it to
// propagate the returned span in process.
-func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) {
+func (t *tracer) StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, Span) {
var opts StartOptions
var parent SpanContext
- if p := FromContext(ctx); p != nil {
- p.addChild()
- parent = p.spanContext
+ if p := t.FromContext(ctx); p != nil {
+ if internalParent, ok := p.(*span); ok {
+ internalParent.addChild()
+ }
+ parent = p.SpanContext()
}
for _, op := range o {
op(&opts)
@@ -180,7 +190,7 @@ func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Cont
ctx, end := startExecutionTracerTask(ctx, name)
span.executionTracerTaskEnd = end
- return NewContext(ctx, span), span
+ return t.NewContext(ctx, span), span
}
// StartSpanWithRemoteParent starts a new child span of the span from the given parent.
@@ -190,7 +200,7 @@ func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Cont
//
// Returned context contains the newly created span. You can use it to
// propagate the returned span in process.
-func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) {
+func (t *tracer) StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, Span) {
var opts StartOptions
for _, op := range o {
op(&opts)
@@ -198,11 +208,11 @@ func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanCont
span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts)
ctx, end := startExecutionTracerTask(ctx, name)
span.executionTracerTaskEnd = end
- return NewContext(ctx, span), span
+ return t.NewContext(ctx, span), span
}
-func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span {
- span := &Span{}
+func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *span {
+ span := &span{}
span.spanContext = parent
cfg := config.Load().(*Config)
@@ -266,7 +276,7 @@ func startSpanInternal(name string, hasParent bool, parent SpanContext, remotePa
}
// End ends the span.
-func (s *Span) End() {
+func (s *span) End() {
if s == nil {
return
}
@@ -296,9 +306,10 @@ func (s *Span) End() {
// makeSpanData produces a SpanData representing the current state of the Span.
// It requires that s.data is non-nil.
-func (s *Span) makeSpanData() *SpanData {
+func (s *span) makeSpanData() *SpanData {
var sd SpanData
s.mu.Lock()
+ defer s.mu.Unlock()
sd = *s.data
if s.lruAttributes.len() > 0 {
sd.Attributes = s.lruAttributesToAttributeMap()
@@ -316,12 +327,11 @@ func (s *Span) makeSpanData() *SpanData {
sd.Links = s.interfaceArrayToLinksArray()
sd.DroppedLinkCount = s.links.droppedCount
}
- s.mu.Unlock()
return &sd
}
// SpanContext returns the SpanContext of the span.
-func (s *Span) SpanContext() SpanContext {
+func (s *span) SpanContext() SpanContext {
if s == nil {
return SpanContext{}
}
@@ -329,7 +339,7 @@ func (s *Span) SpanContext() SpanContext {
}
// SetName sets the name of the span, if it is recording events.
-func (s *Span) SetName(name string) {
+func (s *span) SetName(name string) {
if !s.IsRecordingEvents() {
return
}
@@ -339,7 +349,7 @@ func (s *Span) SetName(name string) {
}
// SetStatus sets the status of the span, if it is recording events.
-func (s *Span) SetStatus(status Status) {
+func (s *span) SetStatus(status Status) {
if !s.IsRecordingEvents() {
return
}
@@ -348,7 +358,7 @@ func (s *Span) SetStatus(status Status) {
s.mu.Unlock()
}
-func (s *Span) interfaceArrayToLinksArray() []Link {
+func (s *span) interfaceArrayToLinksArray() []Link {
linksArr := make([]Link, 0, len(s.links.queue))
for _, value := range s.links.queue {
linksArr = append(linksArr, value.(Link))
@@ -356,7 +366,7 @@ func (s *Span) interfaceArrayToLinksArray() []Link {
return linksArr
}
-func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent {
+func (s *span) interfaceArrayToMessageEventArray() []MessageEvent {
messageEventArr := make([]MessageEvent, 0, len(s.messageEvents.queue))
for _, value := range s.messageEvents.queue {
messageEventArr = append(messageEventArr, value.(MessageEvent))
@@ -364,7 +374,7 @@ func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent {
return messageEventArr
}
-func (s *Span) interfaceArrayToAnnotationArray() []Annotation {
+func (s *span) interfaceArrayToAnnotationArray() []Annotation {
annotationArr := make([]Annotation, 0, len(s.annotations.queue))
for _, value := range s.annotations.queue {
annotationArr = append(annotationArr, value.(Annotation))
@@ -372,7 +382,7 @@ func (s *Span) interfaceArrayToAnnotationArray() []Annotation {
return annotationArr
}
-func (s *Span) lruAttributesToAttributeMap() map[string]interface{} {
+func (s *span) lruAttributesToAttributeMap() map[string]interface{} {
attributes := make(map[string]interface{}, s.lruAttributes.len())
for _, key := range s.lruAttributes.keys() {
value, ok := s.lruAttributes.get(key)
@@ -384,13 +394,13 @@ func (s *Span) lruAttributesToAttributeMap() map[string]interface{} {
return attributes
}
-func (s *Span) copyToCappedAttributes(attributes []Attribute) {
+func (s *span) copyToCappedAttributes(attributes []Attribute) {
for _, a := range attributes {
s.lruAttributes.add(a.key, a.value)
}
}
-func (s *Span) addChild() {
+func (s *span) addChild() {
if !s.IsRecordingEvents() {
return
}
@@ -402,7 +412,7 @@ func (s *Span) addChild() {
// AddAttributes sets attributes in the span.
//
// Existing attributes whose keys appear in the attributes parameter are overwritten.
-func (s *Span) AddAttributes(attributes ...Attribute) {
+func (s *span) AddAttributes(attributes ...Attribute) {
if !s.IsRecordingEvents() {
return
}
@@ -418,7 +428,7 @@ func copyAttributes(m map[string]interface{}, attributes []Attribute) {
}
}
-func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) {
+func (s *span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) {
now := time.Now()
msg := fmt.Sprintf(format, a...)
var m map[string]interface{}
@@ -435,7 +445,7 @@ func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...in
s.mu.Unlock()
}
-func (s *Span) printStringInternal(attributes []Attribute, str string) {
+func (s *span) printStringInternal(attributes []Attribute, str string) {
now := time.Now()
var a map[string]interface{}
s.mu.Lock()
@@ -453,7 +463,7 @@ func (s *Span) printStringInternal(attributes []Attribute, str string) {
// Annotate adds an annotation with attributes.
// Attributes can be nil.
-func (s *Span) Annotate(attributes []Attribute, str string) {
+func (s *span) Annotate(attributes []Attribute, str string) {
if !s.IsRecordingEvents() {
return
}
@@ -461,7 +471,7 @@ func (s *Span) Annotate(attributes []Attribute, str string) {
}
// Annotatef adds an annotation with attributes.
-func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) {
+func (s *span) Annotatef(attributes []Attribute, format string, a ...interface{}) {
if !s.IsRecordingEvents() {
return
}
@@ -474,7 +484,7 @@ func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}
// unique in this span and the same between the send event and the receive
// event (this allows to identify a message between the sender and receiver).
// For example, this could be a sequence id.
-func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+func (s *span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
if !s.IsRecordingEvents() {
return
}
@@ -496,7 +506,7 @@ func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedBy
// unique in this span and the same between the send event and the receive
// event (this allows to identify a message between the sender and receiver).
// For example, this could be a sequence id.
-func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+func (s *span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
if !s.IsRecordingEvents() {
return
}
@@ -513,7 +523,7 @@ func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compresse
}
// AddLink adds a link to the span.
-func (s *Span) AddLink(l Link) {
+func (s *span) AddLink(l Link) {
if !s.IsRecordingEvents() {
return
}
@@ -522,8 +532,8 @@ func (s *Span) AddLink(l Link) {
s.mu.Unlock()
}
-func (s *Span) String() string {
- if s == nil {
+func (s *span) String() string {
+ if !s.IsRecordingEvents() {
return "<nil>"
}
if s.data == nil {
diff --git a/trace/trace_api.go b/trace/trace_api.go
new file mode 100644
index 0000000..0665780
--- /dev/null
+++ b/trace/trace_api.go
@@ -0,0 +1,138 @@
+// Copyright 2020, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "context"
+)
+
+// DefaultTracer is the tracer used when package-level exported functions are used.
+var DefaultTracer Tracer = &tracer{}
+
+// Tracer can start spans and access context functions.
+type Tracer interface {
+
+ // StartSpan starts a new child span of the current span in the context. If
+ // there is no span in the context, creates a new trace and span.
+ //
+ // Returned context contains the newly created span. You can use it to
+ // propagate the returned span in process.
+ StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, Span)
+
+ // StartSpanWithRemoteParent starts a new child span of the span from the given parent.
+ //
+ // If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
+ // preferred for cases where the parent is propagated via an incoming request.
+ //
+ // Returned context contains the newly created span. You can use it to
+ // propagate the returned span in process.
+ StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, Span)
+
+ // FromContext returns the Span stored in a context, or nil if there isn't one.
+ FromContext(ctx context.Context) Span
+
+ // NewContext returns a new context with the given Span attached.
+ NewContext(parent context.Context, s Span) context.Context
+}
+
+// StartSpan starts a new child span of the current span in the context. If
+// there is no span in the context, creates a new trace and span.
+//
+// Returned context contains the newly created span. You can use it to
+// propagate the returned span in process.
+func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, Span) {
+ return DefaultTracer.StartSpan(ctx, name, o...)
+}
+
+// StartSpanWithRemoteParent starts a new child span of the span from the given parent.
+//
+// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
+// preferred for cases where the parent is propagated via an incoming request.
+//
+// Returned context contains the newly created span. You can use it to
+// propagate the returned span in process.
+func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, Span) {
+ return DefaultTracer.StartSpanWithRemoteParent(ctx, name, parent, o...)
+}
+
+// FromContext returns the Span stored in a context, or a Span that is not
+// recording events if there isn't one.
+func FromContext(ctx context.Context) Span {
+ return DefaultTracer.FromContext(ctx)
+}
+
+// NewContext returns a new context with the given Span attached.
+func NewContext(parent context.Context, s Span) context.Context {
+ return DefaultTracer.NewContext(parent, s)
+}
+
+// Span represents a span of a trace. It has an associated SpanContext, and
+// stores data accumulated while the span is active.
+//
+// Ideally users should interact with Spans by calling the functions in this
+// package that take a Context parameter.
+type Span interface {
+
+ // IsRecordingEvents returns true if events are being recorded for this span.
+ // Use this check to avoid computing expensive annotations when they will never
+ // be used.
+ IsRecordingEvents() bool
+
+ // End ends the span.
+ End()
+
+ // SpanContext returns the SpanContext of the span.
+ SpanContext() SpanContext
+
+ // SetName sets the name of the span, if it is recording events.
+ SetName(name string)
+
+ // SetStatus sets the status of the span, if it is recording events.
+ SetStatus(status Status)
+
+ // AddAttributes sets attributes in the span.
+ //
+ // Existing attributes whose keys appear in the attributes parameter are overwritten.
+ AddAttributes(attributes ...Attribute)
+
+ // Annotate adds an annotation with attributes.
+ // Attributes can be nil.
+ Annotate(attributes []Attribute, str string)
+
+ // Annotatef adds an annotation with attributes.
+ Annotatef(attributes []Attribute, format string, a ...interface{})
+
+ // AddMessageSendEvent adds a message send event to the span.
+ //
+ // messageID is an identifier for the message, which is recommended to be
+ // unique in this span and the same between the send event and the receive
+ // event (this allows to identify a message between the sender and receiver).
+ // For example, this could be a sequence id.
+ AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64)
+
+ // AddMessageReceiveEvent adds a message receive event to the span.
+ //
+ // messageID is an identifier for the message, which is recommended to be
+ // unique in this span and the same between the send event and the receive
+ // event (this allows to identify a message between the sender and receiver).
+ // For example, this could be a sequence id.
+ AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64)
+
+ // AddLink adds a link to the span.
+ AddLink(l Link)
+
+ // String prints a string representation of a span.
+ String() string
+}
diff --git a/trace/trace_test.go b/trace/trace_test.go
index c215136..77b3763 100644
--- a/trace/trace_test.go
+++ b/trace/trace_test.go
@@ -46,7 +46,7 @@ func TestStrings(t *testing.T) {
}
func TestFromContext(t *testing.T) {
- want := &Span{}
+ want := &span{}
ctx := NewContext(context.Background(), want)
got := FromContext(ctx)
if got != want {
@@ -61,20 +61,20 @@ func (f foo) String() string {
}
// checkChild tests that c has fields set appropriately, given that it is a child span of p.
-func checkChild(p SpanContext, c *Span) error {
+func checkChild(p SpanContext, c Span) error {
if c == nil {
return fmt.Errorf("got nil child span, want non-nil")
}
- if got, want := c.spanContext.TraceID, p.TraceID; got != want {
+ if got, want := c.SpanContext().TraceID, p.TraceID; got != want {
return fmt.Errorf("got child trace ID %s, want %s", got, want)
}
- if childID, parentID := c.spanContext.SpanID, p.SpanID; childID == parentID {
+ if childID, parentID := c.SpanContext().SpanID, p.SpanID; childID == parentID {
return fmt.Errorf("got child span ID %s, parent span ID %s; want unequal IDs", childID, parentID)
}
- if got, want := c.spanContext.TraceOptions, p.TraceOptions; got != want {
+ if got, want := c.SpanContext().TraceOptions, p.TraceOptions; got != want {
return fmt.Errorf("got child trace options %d, want %d", got, want)
}
- if got, want := c.spanContext.Tracestate, p.Tracestate; got != want {
+ if got, want := c.SpanContext().Tracestate, p.Tracestate; got != want {
return fmt.Errorf("got child tracestate %v, want %v", got, want)
}
return nil
@@ -82,7 +82,7 @@ func checkChild(p SpanContext, c *Span) error {
func TestStartSpan(t *testing.T) {
ctx, _ := StartSpan(context.Background(), "StartSpan")
- if FromContext(ctx).data != nil {
+ if FromContext(ctx).(*span).data != nil {
t.Error("StartSpan: new span is recording events")
}
}
@@ -231,7 +231,7 @@ func TestStartSpanWithRemoteParent(t *testing.T) {
}
// startSpan returns a context with a new Span that is recording events and will be exported.
-func startSpan(o StartOptions) *Span {
+func startSpan(o StartOptions) Span {
_, span := StartSpanWithRemoteParent(context.Background(), "span0",
SpanContext{
TraceID: tid,
@@ -255,7 +255,7 @@ func (t *testExporter) ExportSpan(s *SpanData) {
// endSpan ends the Span in the context and returns the exported SpanData.
//
// It also does some tests on the Span, and tests and clears some fields in the SpanData.
-func endSpan(span *Span) (*SpanData, error) {
+func endSpan(span Span) (*SpanData, error) {
if !span.IsRecordingEvents() {
return nil, fmt.Errorf("IsRecordingEvents: got false, want true")
@@ -579,10 +579,10 @@ func TestSetSpanName(t *testing.T) {
func TestSetSpanNameUnsampledSpan(t *testing.T) {
var nilSpanData *SpanData
- span := startSpan(StartOptions{Sampler: NeverSample()})
- span.SetName("NoopName")
+ sp := startSpan(StartOptions{Sampler: NeverSample()})
+ sp.SetName("NoopName")
- if want, got := nilSpanData, span.data; want != got {
+ if want, got := nilSpanData, sp.(*span).data; want != got {
t.Errorf("span.data=%+v; want %+v", got, want)
}
}
@@ -861,7 +861,7 @@ func TestChildSpanCount(t *testing.T) {
}
func TestNilSpanEnd(t *testing.T) {
- var span *Span
+ var span *span
span.End()
}
@@ -871,25 +871,28 @@ func TestExecutionTracerTaskEnd(t *testing.T) {
atomic.AddUint64(&n, 1)
}
- var spans []*Span
- _, span := StartSpan(context.Background(), "foo", WithSampler(NeverSample()))
- span.executionTracerTaskEnd = executionTracerTaskEnd
- spans = append(spans, span) // never sample
+ var spans []Span
+ _, s := StartSpan(context.Background(), "foo", WithSampler(NeverSample()))
+ sp := s.(*span)
+ sp.executionTracerTaskEnd = executionTracerTaskEnd
+ spans = append(spans, sp) // never sample
- _, span = StartSpanWithRemoteParent(context.Background(), "foo", SpanContext{
+ _, s = StartSpanWithRemoteParent(context.Background(), "foo", SpanContext{
TraceID: TraceID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
SpanID: SpanID{0, 1, 2, 3, 4, 5, 6, 7},
TraceOptions: 0,
})
- span.executionTracerTaskEnd = executionTracerTaskEnd
- spans = append(spans, span) // parent not sampled
+ sp = s.(*span)
+ sp.executionTracerTaskEnd = executionTracerTaskEnd
+ spans = append(spans, sp) // parent not sampled
- _, span = StartSpan(context.Background(), "foo", WithSampler(AlwaysSample()))
- span.executionTracerTaskEnd = executionTracerTaskEnd
- spans = append(spans, span) // always sample
+ _, s = StartSpan(context.Background(), "foo", WithSampler(AlwaysSample()))
+ sp = s.(*span)
+ sp.executionTracerTaskEnd = executionTracerTaskEnd
+ spans = append(spans, sp) // always sample
- for _, span := range spans {
- span.End()
+ for _, sp := range spans {
+ sp.End()
}
if got, want := n, uint64(len(spans)); got != want {
t.Fatalf("Execution tracer task ended for %v spans; want %v", got, want)