1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:04:44 -07:00
go/internal/event/export/trace.go
Ian Cottrell a90b7300be internal/event: remove the event.eventType type
Instead of tagging events with their type, instead we infer the type from
the label pattern.
The standard event creators all have a matching test that returns true
if the the labels pattern matches the ones that would be built by the
creator.
Spans and logs already have a unique label pattern, other event types
required a special label marker.
This makes the system much more extensible, and also cleans up some
the API.

Change-Id: I1fbc9ec07aa84ead6c12bbd5ca65b13b605bfa4a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/229242
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
2020-04-27 15:30:19 +00:00

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 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)
}