mirror of
https://github.com/golang/go
synced 2024-11-05 18:26:10 -07:00
a82abb5396
Now key types can be implemented outside the package that holds labels or events, they should be. This prevents the large list of types from poluting the public interface of the core packages. Change-Id: I927f31cb5e4e1d0c29619681015962f890623e5c Reviewed-on: https://go-review.googlesource.com/c/tools/+/229240 Run-TryBot: Ian Cottrell <iancottrell@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
118 lines
2.6 KiB
Go
118 lines
2.6 KiB
Go
// 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 ev.IsLog(), ev.IsLabel():
|
|
if span := GetSpan(ctx); span != nil {
|
|
span.mu.Lock()
|
|
span.events = append(span.events, ev)
|
|
span.mu.Unlock()
|
|
}
|
|
case ev.IsStartSpan():
|
|
span := &Span{
|
|
Name: keys.Name.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 ev.IsEndSpan():
|
|
if span := GetSpan(ctx); span != nil {
|
|
span.mu.Lock()
|
|
span.finish = ev
|
|
span.mu.Unlock()
|
|
}
|
|
case ev.IsDetach():
|
|
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)
|
|
}
|