2020-03-01 16:35:55 -07:00
|
|
|
// 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"
|
2020-03-27 16:59:18 -06:00
|
|
|
"sync"
|
2020-03-01 16:35:55 -07:00
|
|
|
|
2020-04-17 07:32:56 -06:00
|
|
|
"golang.org/x/tools/internal/event"
|
|
|
|
"golang.org/x/tools/internal/event/core"
|
2020-04-20 19:50:02 -06:00
|
|
|
"golang.org/x/tools/internal/event/keys"
|
2020-04-20 13:44:34 -06:00
|
|
|
"golang.org/x/tools/internal/event/label"
|
2020-03-01 16:35:55 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type SpanContext struct {
|
|
|
|
TraceID TraceID
|
|
|
|
SpanID SpanID
|
|
|
|
}
|
|
|
|
|
|
|
|
type Span struct {
|
|
|
|
Name string
|
|
|
|
ID SpanContext
|
|
|
|
ParentID SpanID
|
2020-03-27 16:59:18 -06:00
|
|
|
mu sync.Mutex
|
2020-04-17 07:32:56 -06:00
|
|
|
start core.Event
|
|
|
|
finish core.Event
|
|
|
|
events []core.Event
|
2020-03-01 16:35:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type contextKeyType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
spanContextKey = contextKeyType(iota)
|
2020-03-20 06:29:48 -06:00
|
|
|
labelContextKey
|
2020-03-01 16:35:55 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func GetSpan(ctx context.Context) *Span {
|
|
|
|
v := ctx.Value(spanContextKey)
|
|
|
|
if v == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return v.(*Span)
|
|
|
|
}
|
|
|
|
|
2020-03-20 06:29:48 -06:00
|
|
|
// Spans creates an exporter that maintains hierarchical span structure in the
|
2020-03-04 14:41:57 -07:00
|
|
|
// context.
|
2020-04-20 13:44:34 -06:00
|
|
|
// It creates new spans on start events, adds events to the current span on
|
|
|
|
// log or label, and closes the span on end events.
|
2020-03-04 14:41:57 -07:00
|
|
|
// The span structure can then be used by other exporters.
|
2020-03-20 06:29:48 -06:00
|
|
|
func Spans(output event.Exporter) event.Exporter {
|
2020-04-20 13:44:34 -06:00
|
|
|
return func(ctx context.Context, ev core.Event, lm label.Map) context.Context {
|
2020-03-20 06:29:48 -06:00
|
|
|
switch {
|
2020-04-21 07:41:57 -06:00
|
|
|
case event.IsLog(ev), event.IsLabel(ev):
|
2020-03-20 06:29:48 -06:00
|
|
|
if span := GetSpan(ctx); span != nil {
|
2020-03-27 16:59:18 -06:00
|
|
|
span.mu.Lock()
|
|
|
|
span.events = append(span.events, ev)
|
|
|
|
span.mu.Unlock()
|
2020-03-20 06:29:48 -06:00
|
|
|
}
|
2020-04-21 07:41:57 -06:00
|
|
|
case event.IsStart(ev):
|
2020-03-20 06:29:48 -06:00
|
|
|
span := &Span{
|
2020-04-21 07:41:57 -06:00
|
|
|
Name: keys.Start.Get(lm),
|
2020-03-27 16:59:18 -06:00
|
|
|
start: ev,
|
2020-03-20 06:29:48 -06:00
|
|
|
}
|
|
|
|
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)
|
2020-04-21 07:41:57 -06:00
|
|
|
case event.IsEnd(ev):
|
2020-03-20 06:29:48 -06:00
|
|
|
if span := GetSpan(ctx); span != nil {
|
2020-03-27 16:59:18 -06:00
|
|
|
span.mu.Lock()
|
|
|
|
span.finish = ev
|
|
|
|
span.mu.Unlock()
|
2020-03-20 06:29:48 -06:00
|
|
|
}
|
2020-04-21 07:41:57 -06:00
|
|
|
case event.IsDetach(ev):
|
2020-03-20 06:29:48 -06:00
|
|
|
ctx = context.WithValue(ctx, spanContextKey, nil)
|
2020-03-01 16:35:55 -07:00
|
|
|
}
|
2020-04-20 13:44:34 -06:00
|
|
|
return output(ctx, ev, lm)
|
2020-03-01 16:35:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SpanContext) Format(f fmt.State, r rune) {
|
|
|
|
fmt.Fprintf(f, "%v:%v", s.TraceID, s.SpanID)
|
|
|
|
}
|
|
|
|
|
2020-04-17 07:32:56 -06:00
|
|
|
func (s *Span) Start() core.Event {
|
2020-03-27 16:59:18 -06:00
|
|
|
// start never changes after construction, so we dont need to hold the mutex
|
|
|
|
return s.start
|
|
|
|
}
|
|
|
|
|
2020-04-17 07:32:56 -06:00
|
|
|
func (s *Span) Finish() core.Event {
|
2020-03-27 16:59:18 -06:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
return s.finish
|
|
|
|
}
|
|
|
|
|
2020-04-17 07:32:56 -06:00
|
|
|
func (s *Span) Events() []core.Event {
|
2020-03-27 16:59:18 -06:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
return s.events
|
|
|
|
}
|
|
|
|
|
2020-03-01 16:35:55 -07:00
|
|
|
func (s *Span) Format(f fmt.State, r rune) {
|
2020-03-27 16:59:18 -06:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
2020-03-01 16:35:55 -07:00
|
|
|
fmt.Fprintf(f, "%v %v", s.Name, s.ID)
|
|
|
|
if s.ParentID.IsValid() {
|
|
|
|
fmt.Fprintf(f, "[%v]", s.ParentID)
|
|
|
|
}
|
2020-03-27 16:59:18 -06:00
|
|
|
fmt.Fprintf(f, " %v->%v", s.start, s.finish)
|
2020-03-01 16:35:55 -07:00
|
|
|
}
|