+++ /dev/null
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package export
-
-import (
- "context"
- "fmt"
- "sync"
-
- "golang.org/x/tools/internal/event"
- "golang.org/x/tools/internal/event/core"
- "golang.org/x/tools/internal/event/keys"
- "golang.org/x/tools/internal/event/label"
-)
-
-type SpanContext struct {
- TraceID TraceID
- SpanID SpanID
-}
-
-type Span struct {
- Name string
- ID SpanContext
- ParentID SpanID
- mu sync.Mutex
- start core.Event
- finish core.Event
- events []core.Event
-}
-
-type contextKeyType int
-
-const (
- spanContextKey = contextKeyType(iota)
- labelContextKey
-)
-
-func GetSpan(ctx context.Context) *Span {
- v := ctx.Value(spanContextKey)
- if v == nil {
- return nil
- }
- return v.(*Span)
-}
-
-// Spans creates an exporter that maintains hierarchical span structure in the
-// context.
-// It creates new spans on start events, adds events to the current span on
-// log or label, and closes the span on end events.
-// The span structure can then be used by other exporters.
-func Spans(output event.Exporter) event.Exporter {
- return func(ctx context.Context, ev core.Event, lm label.Map) context.Context {
- switch {
- case event.IsLog(ev), event.IsLabel(ev):
- if span := GetSpan(ctx); span != nil {
- span.mu.Lock()
- span.events = append(span.events, ev)
- span.mu.Unlock()
- }
- case event.IsStart(ev):
- span := &Span{
- Name: keys.Start.Get(lm),
- start: ev,
- }
- if parent := GetSpan(ctx); parent != nil {
- span.ID.TraceID = parent.ID.TraceID
- span.ParentID = parent.ID.SpanID
- } else {
- span.ID.TraceID = newTraceID()
- }
- span.ID.SpanID = newSpanID()
- ctx = context.WithValue(ctx, spanContextKey, span)
- case event.IsEnd(ev):
- if span := GetSpan(ctx); span != nil {
- span.mu.Lock()
- span.finish = ev
- span.mu.Unlock()
- }
- case event.IsDetach(ev):
- ctx = context.WithValue(ctx, spanContextKey, nil)
- }
- return output(ctx, ev, lm)
- }
-}
-
-func (s *SpanContext) Format(f fmt.State, r rune) {
- fmt.Fprintf(f, "%v:%v", s.TraceID, s.SpanID)
-}
-
-func (s *Span) Start() core.Event {
- // start never changes after construction, so we dont need to hold the mutex
- return s.start
-}
-
-func (s *Span) Finish() core.Event {
- s.mu.Lock()
- defer s.mu.Unlock()
- return s.finish
-}
-
-func (s *Span) Events() []core.Event {
- s.mu.Lock()
- defer s.mu.Unlock()
- return s.events
-}
-
-func (s *Span) Format(f fmt.State, r rune) {
- s.mu.Lock()
- defer s.mu.Unlock()
- fmt.Fprintf(f, "%v %v", s.Name, s.ID)
- if s.ParentID.IsValid() {
- fmt.Fprintf(f, "[%v]", s.ParentID)
- }
- fmt.Fprintf(f, " %v->%v", s.start, s.finish)
-}