From c81623a0cb29ea6eb049bad0ed741d5399b1c578 Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Mon, 20 Apr 2020 15:44:34 -0400 Subject: [PATCH] internal/event: move event/core.Tag to event/label.Label Also moves core.Key to label.Key, but leaves the implementations behind for now. After using for a while, the word Tag conveys slightly the wrong concept, tagging implies the entire set of information, label maps better to a single named piece of information. A label is just a named key/value pair, it is not really tied to the event package, separating it makes it much easier to understand the public symbols of the event and core packages, and allows us to also move the key implementations somewhere else, which otherwise dominate the API. Change-Id: I46275d531cec91e28af6ab1e74a2713505d52533 Reviewed-on: https://go-review.googlesource.com/c/tools/+/229239 Run-TryBot: Ian Cottrell Reviewed-by: Robert Findley TryBot-Result: Gobot Gobot --- internal/event/bench_test.go | 3 +- internal/event/core/event.go | 65 ++-- internal/event/core/export.go | 8 +- internal/event/core/fast.go | 48 +-- internal/event/core/key.go | 318 +++++++++--------- internal/event/core/tag.go | 197 ----------- internal/event/event.go | 43 +-- internal/event/export/eventtest/eventtest.go | 5 +- internal/event/export/log.go | 17 +- internal/event/export/log_test.go | 5 +- internal/event/export/metric/data.go | 103 +++--- internal/event/export/metric/exporter.go | 21 +- internal/event/export/metric/info.go | 19 +- internal/event/export/ocagent/metrics.go | 4 +- internal/event/export/ocagent/ocagent.go | 83 ++--- internal/event/export/ocagent/ocagent_test.go | 15 +- internal/event/export/ocagent/trace_test.go | 5 +- internal/event/export/ocagent/wire/common.go | 10 +- internal/event/export/ocagent/wire/metrics.go | 14 +- internal/event/export/ocagent/wire/trace.go | 6 +- .../event/export/prometheus/prometheus.go | 7 +- internal/event/export/tag.go | 23 +- internal/event/export/trace.go | 11 +- internal/event/label/label.go | 213 ++++++++++++ .../{core/tag_test.go => label/label_test.go} | 163 ++++----- internal/jsonrpc2/jsonrpc2.go | 10 +- internal/lsp/debug/metrics.go | 12 +- internal/lsp/debug/rpc.go | 13 +- internal/lsp/debug/serve.go | 17 +- internal/lsp/debug/tag/tag.go | 2 +- internal/lsp/debug/trace.go | 15 +- internal/lsp/protocol/context.go | 3 +- internal/lsp/source/types_format.go | 2 +- 33 files changed, 755 insertions(+), 725 deletions(-) delete mode 100644 internal/event/core/tag.go create mode 100644 internal/event/label/label.go rename internal/event/{core/tag_test.go => label/label_test.go} (54%) diff --git a/internal/event/bench_test.go b/internal/event/bench_test.go index 8db24e6ece..5df08f5127 100644 --- a/internal/event/bench_test.go +++ b/internal/event/bench_test.go @@ -9,6 +9,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export" + "golang.org/x/tools/internal/event/label" ) type Hooks struct { @@ -147,6 +148,6 @@ func init() { log.SetOutput(ioutil.Discard) } -func noopExporter(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { +func noopExporter(ctx context.Context, ev core.Event, lm label.Map) context.Context { return ctx } diff --git a/internal/event/core/event.go b/internal/event/core/event.go index 109456c386..48286b1028 100644 --- a/internal/event/core/event.go +++ b/internal/event/core/event.go @@ -8,6 +8,8 @@ package core import ( "fmt" "time" + + "golang.org/x/tools/internal/event/label" ) type eventType uint8 @@ -22,27 +24,26 @@ const ( RecordType // a value that should be tracked ) -// sTags is used to hold a small number of tags inside an event whichout -// requiring a separate allocation. -// As tags are often on the stack, this avoids an allocation at all for -// the very common cases of simple events. -// The length needs to be large enough to cope with the majority of events -// but no so large as to cause undue stack pressure. -// A log message with two values will use 3 tags (one for each value and -// one for the message itself). -type sTags [3]Tag - // Event holds the information about an event of note that ocurred. type Event struct { At time.Time - typ eventType - static sTags // inline storage for the first few tags - dynamic []Tag // dynamically sized storage for remaining tags + typ eventType + + // As events are often on the stack, storing the first few labels directly + // in the event can avoid an allocation at all for the very common cases of + // simple events. + // The length needs to be large enough to cope with the majority of events + // but no so large as to cause undue stack pressure. + // A log message with two values will use 3 labels (one for each value and + // one for the message itself). + + static [3]label.Label // inline storage for the first few labels + dynamic []label.Label // dynamically sized storage for remaining labels } -// eventTagMap implements TagMap for a the tags of an Event. -type eventTagMap struct { +// eventLabelMap implements label.Map for a the labels of an Event. +type eventLabelMap struct { event Event } @@ -54,12 +55,12 @@ func (ev Event) IsDetach() bool { return ev.typ == DetachType } func (ev Event) IsRecord() bool { return ev.typ == RecordType } func (ev Event) Format(f fmt.State, r rune) { - tagMap := TagMap(ev) + lm := label.Map(ev) if !ev.At.IsZero() { fmt.Fprint(f, ev.At.Format("2006/01/02 15:04:05 ")) } - msg := Msg.Get(tagMap) - err := Err.Get(tagMap) + msg := Msg.Get(lm) + err := Err.Get(lm) fmt.Fprint(f, msg) if err != nil { if f.Flag('+') { @@ -69,13 +70,13 @@ func (ev Event) Format(f fmt.State, r rune) { } } for index := 0; ev.Valid(index); index++ { - tag := ev.Tag(index) + l := ev.Label(index) // msg and err were both already printed above, so we skip them to avoid // double printing - if !tag.Valid() || tag.Key() == Msg || tag.Key() == Err { + if !l.Valid() || l.Key() == Msg || l.Key() == Err { continue } - fmt.Fprintf(f, "\n\t%v", tag) + fmt.Fprintf(f, "\n\t%v", l) } } @@ -83,31 +84,31 @@ func (ev Event) Valid(index int) bool { return index >= 0 && index < len(ev.static)+len(ev.dynamic) } -func (ev Event) Tag(index int) Tag { +func (ev Event) Label(index int) label.Label { if index < len(ev.static) { return ev.static[index] } return ev.dynamic[index-len(ev.static)] } -func (ev Event) Find(key Key) Tag { - for _, tag := range ev.static { - if tag.Key() == key { - return tag +func (ev Event) Find(key label.Key) label.Label { + for _, l := range ev.static { + if l.Key() == key { + return l } } - for _, tag := range ev.dynamic { - if tag.Key() == key { - return tag + for _, l := range ev.dynamic { + if l.Key() == key { + return l } } - return Tag{} + return label.Label{} } -func MakeEvent(typ eventType, static [3]Tag, tags []Tag) Event { +func MakeEvent(typ eventType, static [3]label.Label, labels []label.Label) Event { return Event{ typ: typ, static: static, - dynamic: tags, + dynamic: labels, } } diff --git a/internal/event/core/export.go b/internal/event/core/export.go index 89783f31ab..f006ed14f6 100644 --- a/internal/event/core/export.go +++ b/internal/event/core/export.go @@ -9,11 +9,13 @@ import ( "sync/atomic" "time" "unsafe" + + "golang.org/x/tools/internal/event/label" ) // Exporter is a function that handles events. // It may return a modified context and event. -type Exporter func(context.Context, Event, TagMap) context.Context +type Exporter func(context.Context, Event, label.Map) context.Context var ( exporter unsafe.Pointer @@ -35,7 +37,7 @@ func SetExporter(e Exporter) { } // deliver is called to deliver an event to the supplied exporter. -// it will fill in the time and generate the basic tag source. +// it will fill in the time. func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context { // add the current time to the event ev.At = time.Now() @@ -56,7 +58,7 @@ func Export(ctx context.Context, ev Event) context.Context { // ExportPair is called to deliver a start event to the supplied exporter. // It also returns a function that will deliver the end event to the same // exporter. -// it will fill in the time and generate the basic tag source. +// It will fill in the time. func ExportPair(ctx context.Context, begin, end Event) (context.Context, func()) { // get the global exporter and abort early if there is not one exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) diff --git a/internal/event/core/fast.go b/internal/event/core/fast.go index 427bec3df8..eef372102c 100644 --- a/internal/event/core/fast.go +++ b/internal/event/core/fast.go @@ -6,49 +6,51 @@ package core import ( "context" + + "golang.org/x/tools/internal/event/label" ) -// Log1 takes a message and one tag delivers a log event to the exporter. +// Log1 takes a message and one label delivers a log event to the exporter. // It is a customized version of Print that is faster and does no allocation. -func Log1(ctx context.Context, message string, t1 Tag) { - Export(ctx, MakeEvent(LogType, sTags{Msg.Of(message), t1}, nil)) +func Log1(ctx context.Context, message string, t1 label.Label) { + Export(ctx, MakeEvent(LogType, [3]label.Label{Msg.Of(message), t1}, nil)) } -// Log2 takes a message and two tags and delivers a log event to the exporter. +// Log2 takes a message and two labels and delivers a log event to the exporter. // It is a customized version of Print that is faster and does no allocation. -func Log2(ctx context.Context, message string, t1 Tag, t2 Tag) { - Export(ctx, MakeEvent(LogType, sTags{Msg.Of(message), t1, t2}, nil)) +func Log2(ctx context.Context, message string, t1 label.Label, t2 label.Label) { + Export(ctx, MakeEvent(LogType, [3]label.Label{Msg.Of(message), t1, t2}, nil)) } -// Metric1 sends a label event to the exporter with the supplied tags. -func Metric1(ctx context.Context, t1 Tag) context.Context { - return Export(ctx, MakeEvent(RecordType, sTags{t1}, nil)) +// Metric1 sends a label event to the exporter with the supplied labels. +func Metric1(ctx context.Context, t1 label.Label) context.Context { + return Export(ctx, MakeEvent(RecordType, [3]label.Label{t1}, nil)) } -// Metric2 sends a label event to the exporter with the supplied tags. -func Metric2(ctx context.Context, t1, t2 Tag) context.Context { - return Export(ctx, MakeEvent(RecordType, sTags{t1, t2}, nil)) +// Metric2 sends a label event to the exporter with the supplied labels. +func Metric2(ctx context.Context, t1, t2 label.Label) context.Context { + return Export(ctx, MakeEvent(RecordType, [3]label.Label{t1, t2}, nil)) } -// Metric3 sends a label event to the exporter with the supplied tags. -func Metric3(ctx context.Context, t1, t2, t3 Tag) context.Context { - return Export(ctx, MakeEvent(RecordType, sTags{t1, t2, t3}, nil)) +// Metric3 sends a label event to the exporter with the supplied labels. +func Metric3(ctx context.Context, t1, t2, t3 label.Label) context.Context { + return Export(ctx, MakeEvent(RecordType, [3]label.Label{t1, t2, t3}, nil)) } -// Start1 sends a span start event with the supplied tag list to the exporter. +// Start1 sends a span start event with the supplied label list to the exporter. // It also returns a function that will end the span, which should normally be // deferred. -func Start1(ctx context.Context, name string, t1 Tag) (context.Context, func()) { +func Start1(ctx context.Context, name string, t1 label.Label) (context.Context, func()) { return ExportPair(ctx, - MakeEvent(StartSpanType, sTags{Name.Of(name), t1}, nil), - MakeEvent(EndSpanType, sTags{}, nil)) + MakeEvent(StartSpanType, [3]label.Label{Name.Of(name), t1}, nil), + MakeEvent(EndSpanType, [3]label.Label{}, nil)) } -// Start2 sends a span start event with the supplied tag list to the exporter. +// Start2 sends a span start event with the supplied label list to the exporter. // It also returns a function that will end the span, which should normally be // deferred. -func Start2(ctx context.Context, name string, t1, t2 Tag) (context.Context, func()) { +func Start2(ctx context.Context, name string, t1, t2 label.Label) (context.Context, func()) { return ExportPair(ctx, - MakeEvent(StartSpanType, sTags{Name.Of(name), t1, t2}, nil), - MakeEvent(EndSpanType, sTags{}, nil)) + MakeEvent(StartSpanType, [3]label.Label{Name.Of(name), t1, t2}, nil), + MakeEvent(EndSpanType, [3]label.Label{}, nil)) } diff --git a/internal/event/core/key.go b/internal/event/core/key.go index 6c28fb25c3..788e48b15b 100644 --- a/internal/event/core/key.go +++ b/internal/event/core/key.go @@ -9,33 +9,19 @@ import ( "io" "math" "strconv" + + "golang.org/x/tools/internal/event/label" ) var ( - // Msg is a key used to add message strings to tag lists. + // Msg is a key used to add message strings to label lists. Msg = NewStringKey("message", "a readable message") // Name is used for things like traces that have a name. Name = NewStringKey("name", "an entity name") - // Err is a key used to add error values to tag lists. + // Err is a key used to add error values to label lists. Err = NewErrorKey("error", "an error that occurred") ) -// Key is used as the identity of a Tag. -// Keys are intended to be compared by pointer only, the name should be unique -// for communicating with external systems, but it is not required or enforced. -type Key interface { - // Name returns the key name. - Name() string - // Description returns a string that can be used to describe the value. - Description() string - - // Format is used in formatting to append the value of the tag to the - // supplied buffer. - // The formatter may use the supplied buf as a scratch area to avoid - // allocations. - Format(w io.Writer, buf []byte, tag Tag) -} - // ValueKey represents a key for untyped values. type ValueKey struct { name string @@ -50,23 +36,23 @@ func NewKey(name, description string) *ValueKey { func (k *ValueKey) Name() string { return k.name } func (k *ValueKey) Description() string { return k.description } -func (k *ValueKey) Format(w io.Writer, buf []byte, tag Tag) { - fmt.Fprint(w, k.From(tag)) +func (k *ValueKey) Format(w io.Writer, buf []byte, l label.Label) { + fmt.Fprint(w, k.From(l)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *ValueKey) Get(tags TagMap) interface{} { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *ValueKey) Get(lm label.Map) interface{} { + if t := lm.Find(k); t.Valid() { return k.From(t) } return nil } -// From can be used to get a value from a Tag. -func (k *ValueKey) From(t Tag) interface{} { return t.UnpackValue() } +// From can be used to get a value from a Label. +func (k *ValueKey) From(t label.Label) interface{} { return t.UnpackValue() } -// Of creates a new Tag with this key and the supplied value. -func (k *ValueKey) Of(value interface{}) Tag { return TagOfValue(k, value) } +// Of creates a new Label with this key and the supplied value. +func (k *ValueKey) Of(value interface{}) label.Label { return label.OfValue(k, value) } // IntKey represents a key type IntKey struct { @@ -82,23 +68,23 @@ func NewIntKey(name, description string) *IntKey { func (k *IntKey) Name() string { return k.name } func (k *IntKey) Description() string { return k.description } -func (k *IntKey) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendInt(buf, int64(k.From(tag)), 10)) +func (k *IntKey) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *IntKey) Of(v int) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *IntKey) Of(v int) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *IntKey) Get(tags TagMap) int { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *IntKey) Get(lm label.Map) int { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *IntKey) From(t Tag) int { return int(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *IntKey) From(t label.Label) int { return int(t.Unpack64()) } // Int8Key represents a key type Int8Key struct { @@ -114,23 +100,23 @@ func NewInt8Key(name, description string) *Int8Key { func (k *Int8Key) Name() string { return k.name } func (k *Int8Key) Description() string { return k.description } -func (k *Int8Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendInt(buf, int64(k.From(tag)), 10)) +func (k *Int8Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *Int8Key) Of(v int8) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *Int8Key) Of(v int8) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *Int8Key) Get(tags TagMap) int8 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *Int8Key) Get(lm label.Map) int8 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *Int8Key) From(t Tag) int8 { return int8(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *Int8Key) From(t label.Label) int8 { return int8(t.Unpack64()) } // Int16Key represents a key type Int16Key struct { @@ -146,23 +132,23 @@ func NewInt16Key(name, description string) *Int16Key { func (k *Int16Key) Name() string { return k.name } func (k *Int16Key) Description() string { return k.description } -func (k *Int16Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendInt(buf, int64(k.From(tag)), 10)) +func (k *Int16Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *Int16Key) Of(v int16) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *Int16Key) Of(v int16) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *Int16Key) Get(tags TagMap) int16 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *Int16Key) Get(lm label.Map) int16 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *Int16Key) From(t Tag) int16 { return int16(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *Int16Key) From(t label.Label) int16 { return int16(t.Unpack64()) } // Int32Key represents a key type Int32Key struct { @@ -178,23 +164,23 @@ func NewInt32Key(name, description string) *Int32Key { func (k *Int32Key) Name() string { return k.name } func (k *Int32Key) Description() string { return k.description } -func (k *Int32Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendInt(buf, int64(k.From(tag)), 10)) +func (k *Int32Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *Int32Key) Of(v int32) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *Int32Key) Of(v int32) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *Int32Key) Get(tags TagMap) int32 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *Int32Key) Get(lm label.Map) int32 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *Int32Key) From(t Tag) int32 { return int32(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *Int32Key) From(t label.Label) int32 { return int32(t.Unpack64()) } // Int64Key represents a key type Int64Key struct { @@ -210,23 +196,23 @@ func NewInt64Key(name, description string) *Int64Key { func (k *Int64Key) Name() string { return k.name } func (k *Int64Key) Description() string { return k.description } -func (k *Int64Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendInt(buf, k.From(tag), 10)) +func (k *Int64Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, k.From(l), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *Int64Key) Of(v int64) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *Int64Key) Of(v int64) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *Int64Key) Get(tags TagMap) int64 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *Int64Key) Get(lm label.Map) int64 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *Int64Key) From(t Tag) int64 { return int64(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *Int64Key) From(t label.Label) int64 { return int64(t.Unpack64()) } // UIntKey represents a key type UIntKey struct { @@ -242,23 +228,23 @@ func NewUIntKey(name, description string) *UIntKey { func (k *UIntKey) Name() string { return k.name } func (k *UIntKey) Description() string { return k.description } -func (k *UIntKey) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendUint(buf, uint64(k.From(tag)), 10)) +func (k *UIntKey) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *UIntKey) Of(v uint) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *UIntKey) Of(v uint) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *UIntKey) Get(tags TagMap) uint { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *UIntKey) Get(lm label.Map) uint { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *UIntKey) From(t Tag) uint { return uint(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *UIntKey) From(t label.Label) uint { return uint(t.Unpack64()) } // UInt8Key represents a key type UInt8Key struct { @@ -274,23 +260,23 @@ func NewUInt8Key(name, description string) *UInt8Key { func (k *UInt8Key) Name() string { return k.name } func (k *UInt8Key) Description() string { return k.description } -func (k *UInt8Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendUint(buf, uint64(k.From(tag)), 10)) +func (k *UInt8Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *UInt8Key) Of(v uint8) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *UInt8Key) Of(v uint8) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *UInt8Key) Get(tags TagMap) uint8 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *UInt8Key) Get(lm label.Map) uint8 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *UInt8Key) From(t Tag) uint8 { return uint8(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *UInt8Key) From(t label.Label) uint8 { return uint8(t.Unpack64()) } // UInt16Key represents a key type UInt16Key struct { @@ -306,23 +292,23 @@ func NewUInt16Key(name, description string) *UInt16Key { func (k *UInt16Key) Name() string { return k.name } func (k *UInt16Key) Description() string { return k.description } -func (k *UInt16Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendUint(buf, uint64(k.From(tag)), 10)) +func (k *UInt16Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *UInt16Key) Of(v uint16) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *UInt16Key) Of(v uint16) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *UInt16Key) Get(tags TagMap) uint16 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *UInt16Key) Get(lm label.Map) uint16 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *UInt16Key) From(t Tag) uint16 { return uint16(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *UInt16Key) From(t label.Label) uint16 { return uint16(t.Unpack64()) } // UInt32Key represents a key type UInt32Key struct { @@ -338,23 +324,23 @@ func NewUInt32Key(name, description string) *UInt32Key { func (k *UInt32Key) Name() string { return k.name } func (k *UInt32Key) Description() string { return k.description } -func (k *UInt32Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendUint(buf, uint64(k.From(tag)), 10)) +func (k *UInt32Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *UInt32Key) Of(v uint32) Tag { return TagOf64(k, uint64(v)) } +// Of creates a new Label with this key and the supplied value. +func (k *UInt32Key) Of(v uint32) label.Label { return label.Of64(k, uint64(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *UInt32Key) Get(tags TagMap) uint32 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *UInt32Key) Get(lm label.Map) uint32 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *UInt32Key) From(t Tag) uint32 { return uint32(t.Unpack64()) } +// From can be used to get a value from a Label. +func (k *UInt32Key) From(t label.Label) uint32 { return uint32(t.Unpack64()) } // UInt64Key represents a key type UInt64Key struct { @@ -370,23 +356,23 @@ func NewUInt64Key(name, description string) *UInt64Key { func (k *UInt64Key) Name() string { return k.name } func (k *UInt64Key) Description() string { return k.description } -func (k *UInt64Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendUint(buf, k.From(tag), 10)) +func (k *UInt64Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, k.From(l), 10)) } -// Of creates a new Tag with this key and the supplied value. -func (k *UInt64Key) Of(v uint64) Tag { return TagOf64(k, v) } +// Of creates a new Label with this key and the supplied value. +func (k *UInt64Key) Of(v uint64) label.Label { return label.Of64(k, v) } -// Get can be used to get a tag for the key from a TagMap. -func (k *UInt64Key) Get(tags TagMap) uint64 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *UInt64Key) Get(lm label.Map) uint64 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *UInt64Key) From(t Tag) uint64 { return t.Unpack64() } +// From can be used to get a value from a Label. +func (k *UInt64Key) From(t label.Label) uint64 { return t.Unpack64() } // Float32Key represents a key type Float32Key struct { @@ -402,25 +388,25 @@ func NewFloat32Key(name, description string) *Float32Key { func (k *Float32Key) Name() string { return k.name } func (k *Float32Key) Description() string { return k.description } -func (k *Float32Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendFloat(buf, float64(k.From(tag)), 'E', -1, 32)) +func (k *Float32Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendFloat(buf, float64(k.From(l)), 'E', -1, 32)) } -// Of creates a new Tag with this key and the supplied value. -func (k *Float32Key) Of(v float32) Tag { - return TagOf64(k, uint64(math.Float32bits(v))) +// Of creates a new Label with this key and the supplied value. +func (k *Float32Key) Of(v float32) label.Label { + return label.Of64(k, uint64(math.Float32bits(v))) } -// Get can be used to get a tag for the key from a TagMap. -func (k *Float32Key) Get(tags TagMap) float32 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *Float32Key) Get(lm label.Map) float32 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *Float32Key) From(t Tag) float32 { +// From can be used to get a value from a Label. +func (k *Float32Key) From(t label.Label) float32 { return math.Float32frombits(uint32(t.Unpack64())) } @@ -438,25 +424,25 @@ func NewFloat64Key(name, description string) *Float64Key { func (k *Float64Key) Name() string { return k.name } func (k *Float64Key) Description() string { return k.description } -func (k *Float64Key) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendFloat(buf, k.From(tag), 'E', -1, 64)) +func (k *Float64Key) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendFloat(buf, k.From(l), 'E', -1, 64)) } -// Of creates a new Tag with this key and the supplied value. -func (k *Float64Key) Of(v float64) Tag { - return TagOf64(k, math.Float64bits(v)) +// Of creates a new Label with this key and the supplied value. +func (k *Float64Key) Of(v float64) label.Label { + return label.Of64(k, math.Float64bits(v)) } -// Get can be used to get a tag for the key from a TagMap. -func (k *Float64Key) Get(tags TagMap) float64 { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *Float64Key) Get(lm label.Map) float64 { + if t := lm.Find(k); t.Valid() { return k.From(t) } return 0 } -// From can be used to get a value from a Tag. -func (k *Float64Key) From(t Tag) float64 { +// From can be used to get a value from a Label. +func (k *Float64Key) From(t label.Label) float64 { return math.Float64frombits(t.Unpack64()) } @@ -474,23 +460,23 @@ func NewStringKey(name, description string) *StringKey { func (k *StringKey) Name() string { return k.name } func (k *StringKey) Description() string { return k.description } -func (k *StringKey) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendQuote(buf, k.From(tag))) +func (k *StringKey) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendQuote(buf, k.From(l))) } -// Of creates a new Tag with this key and the supplied value. -func (k *StringKey) Of(v string) Tag { return TagOfString(k, v) } +// Of creates a new Label with this key and the supplied value. +func (k *StringKey) Of(v string) label.Label { return label.OfString(k, v) } -// Get can be used to get a tag for the key from a TagMap. -func (k *StringKey) Get(tags TagMap) string { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *StringKey) Get(lm label.Map) string { + if t := lm.Find(k); t.Valid() { return k.From(t) } return "" } -// From can be used to get a value from a Tag. -func (k *StringKey) From(t Tag) string { return t.UnpackString() } +// From can be used to get a value from a Label. +func (k *StringKey) From(t label.Label) string { return t.UnpackString() } // BooleanKey represents a key type BooleanKey struct { @@ -506,28 +492,28 @@ func NewBooleanKey(name, description string) *BooleanKey { func (k *BooleanKey) Name() string { return k.name } func (k *BooleanKey) Description() string { return k.description } -func (k *BooleanKey) Format(w io.Writer, buf []byte, tag Tag) { - w.Write(strconv.AppendBool(buf, k.From(tag))) +func (k *BooleanKey) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendBool(buf, k.From(l))) } -// Of creates a new Tag with this key and the supplied value. -func (k *BooleanKey) Of(v bool) Tag { +// Of creates a new Label with this key and the supplied value. +func (k *BooleanKey) Of(v bool) label.Label { if v { - return TagOf64(k, 1) + return label.Of64(k, 1) } - return TagOf64(k, 0) + return label.Of64(k, 0) } -// Get can be used to get a tag for the key from a TagMap. -func (k *BooleanKey) Get(tags TagMap) bool { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *BooleanKey) Get(lm label.Map) bool { + if t := lm.Find(k); t.Valid() { return k.From(t) } return false } -// From can be used to get a value from a Tag. -func (k *BooleanKey) From(t Tag) bool { return t.Unpack64() > 0 } +// From can be used to get a value from a Label. +func (k *BooleanKey) From(t label.Label) bool { return t.Unpack64() > 0 } // ErrorKey represents a key type ErrorKey struct { @@ -543,23 +529,23 @@ func NewErrorKey(name, description string) *ErrorKey { func (k *ErrorKey) Name() string { return k.name } func (k *ErrorKey) Description() string { return k.description } -func (k *ErrorKey) Format(w io.Writer, buf []byte, tag Tag) { - io.WriteString(w, k.From(tag).Error()) +func (k *ErrorKey) Format(w io.Writer, buf []byte, l label.Label) { + io.WriteString(w, k.From(l).Error()) } -// Of creates a new Tag with this key and the supplied value. -func (k *ErrorKey) Of(v error) Tag { return TagOfValue(k, v) } +// Of creates a new Label with this key and the supplied value. +func (k *ErrorKey) Of(v error) label.Label { return label.OfValue(k, v) } -// Get can be used to get a tag for the key from a TagMap. -func (k *ErrorKey) Get(tags TagMap) error { - if t := tags.Find(k); t.Valid() { +// Get can be used to get a label for the key from a label.Map. +func (k *ErrorKey) Get(lm label.Map) error { + if t := lm.Find(k); t.Valid() { return k.From(t) } return nil } -// From can be used to get a value from a Tag. -func (k *ErrorKey) From(t Tag) error { +// From can be used to get a value from a Label. +func (k *ErrorKey) From(t label.Label) error { err, _ := t.UnpackValue().(error) return err } diff --git a/internal/event/core/tag.go b/internal/event/core/tag.go deleted file mode 100644 index 57de6ba888..0000000000 --- a/internal/event/core/tag.go +++ /dev/null @@ -1,197 +0,0 @@ -// 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 core - -import ( - "fmt" - "io" - "reflect" - "unsafe" -) - -// Tag holds a key and value pair. -// It is normally used when passing around lists of tags. -type Tag struct { - key Key - packed uint64 - untyped interface{} -} - -// TagMap is the interface to a collection of Tags indexed by key. -type TagMap interface { - // Find returns the tag that matches the supplied key. - Find(key Key) Tag -} - -// TagList is the interface to something that provides an iterable -// list of tags. -// Iteration should start from 0 and continue until Valid returns false. -type TagList interface { - // Valid returns true if the index is within range for the list. - // It does not imply the tag at that index will itself be valid. - Valid(index int) bool - // Tag returns the tag at the given index. - Tag(index int) Tag -} - -// tagList implements TagList for a list of Tags. -type tagList struct { - tags []Tag -} - -// tagFilter wraps a TagList filtering out specific tags. -type tagFilter struct { - keys []Key - underlying TagList -} - -// tagMap implements TagMap for a simple list of tags. -type tagMap struct { - tags []Tag -} - -// tagMapChain implements TagMap for a list of underlying TagMap. -type tagMapChain struct { - maps []TagMap -} - -// TagOfValue creates a new tag from the key and value. -// This method is for implementing new key types, tag creation should -// normally be done with the Of method of the key. -func TagOfValue(k Key, value interface{}) Tag { return Tag{key: k, untyped: value} } - -// UnpackValue assumes the tag was built using TagOfValue and returns the value -// that was passed to that constructor. -// This method is for implementing new key types, for type safety normal -// access should be done with the From method of the key. -func (t Tag) UnpackValue() interface{} { return t.untyped } - -// TagOf64 creates a new tag from a key and a uint64. This is often -// used for non uint64 values that can be packed into a uint64. -// This method is for implementing new key types, tag creation should -// normally be done with the Of method of the key. -func TagOf64(k Key, v uint64) Tag { return Tag{key: k, packed: v} } - -// Unpack64 assumes the tag was built using TagOf64 and returns the value that -// was passed to that constructor. -// This method is for implementing new key types, for type safety normal -// access should be done with the From method of the key. -func (t Tag) Unpack64() uint64 { return t.packed } - -// TagOfString creates a new tag from a key and a string. -// This method is for implementing new key types, tag creation should -// normally be done with the Of method of the key. -func TagOfString(k Key, v string) Tag { - hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) - return Tag{ - key: k, - packed: uint64(hdr.Len), - untyped: unsafe.Pointer(hdr.Data), - } -} - -// UnpackString assumes the tag was built using TagOfString and returns the -// value that was passed to that constructor. -// This method is for implementing new key types, for type safety normal -// access should be done with the From method of the key. -func (t Tag) UnpackString() string { - var v string - hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) - hdr.Data = uintptr(t.untyped.(unsafe.Pointer)) - hdr.Len = int(t.packed) - return *(*string)(unsafe.Pointer(hdr)) -} - -// Valid returns true if the Tag is a valid one (it has a key). -func (t Tag) Valid() bool { return t.key != nil } - -// Key returns the key of this Tag. -func (t Tag) Key() Key { return t.key } - -// Format is used for debug printing of tags. -func (t Tag) Format(f fmt.State, r rune) { - if !t.Valid() { - io.WriteString(f, `nil`) - return - } - io.WriteString(f, t.Key().Name()) - io.WriteString(f, "=") - var buf [128]byte - t.Key().Format(f, buf[:0], t) -} - -func (l *tagList) Valid(index int) bool { - return index >= 0 && index < len(l.tags) -} - -func (l *tagList) Tag(index int) Tag { - return l.tags[index] -} - -func (f *tagFilter) Valid(index int) bool { - return f.underlying.Valid(index) -} - -func (f *tagFilter) Tag(index int) Tag { - tag := f.underlying.Tag(index) - for _, f := range f.keys { - if tag.Key() == f { - return Tag{} - } - } - return tag -} - -func (l tagMap) Find(key Key) Tag { - for _, tag := range l.tags { - if tag.Key() == key { - return tag - } - } - return Tag{} -} - -func (c tagMapChain) Find(key Key) Tag { - for _, src := range c.maps { - tag := src.Find(key) - if tag.Valid() { - return tag - } - } - return Tag{} -} - -var emptyList = &tagList{} - -func NewTagList(tags ...Tag) TagList { - if len(tags) == 0 { - return emptyList - } - return &tagList{tags: tags} -} - -func Filter(l TagList, keys ...Key) TagList { - if len(keys) == 0 { - return l - } - return &tagFilter{keys: keys, underlying: l} -} - -func NewTagMap(tags ...Tag) TagMap { - return tagMap{tags: tags} -} - -func MergeTagMaps(srcs ...TagMap) TagMap { - var nonNil []TagMap - for _, src := range srcs { - if src != nil { - nonNil = append(nonNil, src) - } - } - if len(nonNil) == 1 { - return nonNil[0] - } - return tagMapChain{maps: nonNil} -} diff --git a/internal/event/event.go b/internal/event/event.go index 4ae08b38d2..0caeb694a7 100644 --- a/internal/event/event.go +++ b/internal/event/event.go @@ -8,11 +8,12 @@ import ( "context" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) // Exporter is a function that handles events. // It may return a modified context and event. -type Exporter func(context.Context, core.Event, core.TagMap) context.Context +type Exporter func(context.Context, core.Event, label.Map) context.Context // SetExporter sets the global exporter function that handles all events. // The exporter is called synchronously from the event call site, so it should @@ -21,45 +22,47 @@ func SetExporter(e Exporter) { core.SetExporter(core.Exporter(e)) } -// Log takes a message and a tag list and combines them into a single event +// Log takes a message and a label list and combines them into a single event // before delivering them to the exporter. -func Log(ctx context.Context, message string, tags ...core.Tag) { - core.Export(ctx, core.MakeEvent(core.LogType, [3]core.Tag{ +func Log(ctx context.Context, message string, labels ...label.Label) { + core.Export(ctx, core.MakeEvent(core.LogType, [3]label.Label{ core.Msg.Of(message), - }, tags)) + }, labels)) } -// Error takes a message and a tag list and combines them into a single event +// Error takes a message and a label list and combines them into a single event // before delivering them to the exporter. It captures the error in the // delivered event. -func Error(ctx context.Context, message string, err error, tags ...core.Tag) { - core.Export(ctx, core.MakeEvent(core.LogType, [3]core.Tag{ +func Error(ctx context.Context, message string, err error, labels ...label.Label) { + core.Export(ctx, core.MakeEvent(core.LogType, [3]label.Label{ core.Msg.Of(message), core.Err.Of(err), - }, tags)) + }, labels)) } -// Metric sends a label event to the exporter with the supplied tags. -func Metric(ctx context.Context, tags ...core.Tag) { - core.Export(ctx, core.MakeEvent(core.RecordType, [3]core.Tag{}, tags)) +// Metric sends a label event to the exporter with the supplied labels. +func Metric(ctx context.Context, labels ...label.Label) { + core.Export(ctx, core.MakeEvent(core.RecordType, [3]label.Label{}, labels)) } -// Label sends a label event to the exporter with the supplied tags. -func Label(ctx context.Context, tags ...core.Tag) context.Context { - return core.Export(ctx, core.MakeEvent(core.LabelType, [3]core.Tag{}, tags)) +// Label sends a label event to the exporter with the supplied labels. +func Label(ctx context.Context, labels ...label.Label) context.Context { + return core.Export(ctx, core.MakeEvent(core.LabelType, [3]label.Label{}, labels)) } -// Start sends a span start event with the supplied tag list to the exporter. +// Start sends a span start event with the supplied label list to the exporter. // It also returns a function that will end the span, which should normally be // deferred. -func Start(ctx context.Context, name string, tags ...core.Tag) (context.Context, func()) { +func Start(ctx context.Context, name string, labels ...label.Label) (context.Context, func()) { return core.ExportPair(ctx, - core.MakeEvent(core.StartSpanType, [3]core.Tag{core.Name.Of(name)}, tags), - core.MakeEvent(core.EndSpanType, [3]core.Tag{}, nil)) + core.MakeEvent(core.StartSpanType, [3]label.Label{ + core.Name.Of(name), + }, labels), + core.MakeEvent(core.EndSpanType, [3]label.Label{}, nil)) } // Detach returns a context without an associated span. // This allows the creation of spans that are not children of the current span. func Detach(ctx context.Context) context.Context { - return core.Export(ctx, core.MakeEvent(core.DetachType, [3]core.Tag{}, nil)) + return core.Export(ctx, core.MakeEvent(core.DetachType, [3]label.Label{}, nil)) } diff --git a/internal/event/export/eventtest/eventtest.go b/internal/event/export/eventtest/eventtest.go index d0061f7746..9e9da529bd 100644 --- a/internal/event/export/eventtest/eventtest.go +++ b/internal/event/export/eventtest/eventtest.go @@ -24,6 +24,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export" + "golang.org/x/tools/internal/event/label" ) func init() { @@ -48,11 +49,11 @@ type testExporter struct { logger event.Exporter } -func (w *testExporter) processEvent(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { +func (w *testExporter) processEvent(ctx context.Context, ev core.Event, tm label.Map) context.Context { w.mu.Lock() defer w.mu.Unlock() // build our log message in buffer - result := w.logger(ctx, ev, tagMap) + result := w.logger(ctx, ev, tm) v := ctx.Value(testingKey) // get the testing.TB if w.buffer.Len() > 0 && v != nil { diff --git a/internal/event/export/log.go b/internal/event/export/log.go index 22076aafaa..25912c920f 100644 --- a/internal/event/export/log.go +++ b/internal/event/export/log.go @@ -12,6 +12,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) // LogWriter returns an Exporter that logs events to the supplied writer. @@ -30,10 +31,10 @@ type logWriter struct { onlyErrors bool } -func (w *logWriter) ProcessEvent(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { +func (w *logWriter) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context { switch { case ev.IsLog(): - if w.onlyErrors && core.Err.Get(tagMap) == nil { + if w.onlyErrors && core.Err.Get(lm) == nil { return ctx } w.mu.Lock() @@ -43,21 +44,21 @@ func (w *logWriter) ProcessEvent(ctx context.Context, ev core.Event, tagMap core if !ev.At.IsZero() { w.writer.Write(ev.At.AppendFormat(buf, "2006/01/02 15:04:05 ")) } - msg := core.Msg.Get(tagMap) + msg := core.Msg.Get(lm) io.WriteString(w.writer, msg) - if err := core.Err.Get(tagMap); err != nil { + if err := core.Err.Get(lm); err != nil { io.WriteString(w.writer, ": ") io.WriteString(w.writer, err.Error()) } for index := 0; ev.Valid(index); index++ { - tag := ev.Tag(index) - if !tag.Valid() || tag.Key() == core.Msg || tag.Key() == core.Err { + l := ev.Label(index) + if !l.Valid() || l.Key() == core.Msg || l.Key() == core.Err { continue } io.WriteString(w.writer, "\n\t") - io.WriteString(w.writer, tag.Key().Name()) + io.WriteString(w.writer, l.Key().Name()) io.WriteString(w.writer, "=") - tag.Key().Format(w.writer, buf, tag) + l.Key().Format(w.writer, buf, l) } io.WriteString(w.writer, "\n") diff --git a/internal/event/export/log_test.go b/internal/event/export/log_test.go index 34029b6443..deef2329f6 100644 --- a/internal/event/export/log_test.go +++ b/internal/event/export/log_test.go @@ -13,6 +13,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export" + "golang.org/x/tools/internal/event/label" ) func ExampleLog() { @@ -31,8 +32,8 @@ func ExampleLog() { func timeFixer(output event.Exporter) event.Exporter { at, _ := time.Parse(time.RFC3339Nano, "2020-03-05T14:27:48Z") - return func(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { + return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { ev.At = at - return output(ctx, ev, tagMap) + return output(ctx, ev, lm) } } diff --git a/internal/event/export/metric/data.go b/internal/event/export/metric/data.go index c9603556b8..95582fe391 100644 --- a/internal/event/export/metric/data.go +++ b/internal/event/export/metric/data.go @@ -10,6 +10,7 @@ import ( "time" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) // Data represents a single point in the time series of a metric. @@ -22,7 +23,7 @@ type Data interface { //TODO: rethink the concept of metric handles Handle() string // Groups reports the rows that currently exist for this metric. - Groups() [][]core.Tag + Groups() [][]label.Label } // Int64Data is a concrete implementation of Data for int64 scalar metrics. @@ -36,7 +37,7 @@ type Int64Data struct { // End is the last time this metric was updated. EndTime time.Time - groups [][]core.Tag + groups [][]label.Label key *core.Int64Key } @@ -51,7 +52,7 @@ type Float64Data struct { // End is the last time this metric was updated. EndTime time.Time - groups [][]core.Tag + groups [][]label.Label key *core.Float64Key } @@ -64,7 +65,7 @@ type HistogramInt64Data struct { // End is the last time this metric was updated. EndTime time.Time - groups [][]core.Tag + groups [][]label.Label key *core.Int64Key } @@ -91,7 +92,7 @@ type HistogramFloat64Data struct { // End is the last time this metric was updated. EndTime time.Time - groups [][]core.Tag + groups [][]label.Label key *core.Float64Key } @@ -109,44 +110,44 @@ type HistogramFloat64Row struct { Max float64 } -func tagListEqual(a, b []core.Tag) bool { +func labelListEqual(a, b []label.Label) bool { //TODO: make this more efficient return fmt.Sprint(a) == fmt.Sprint(b) } -func tagListLess(a, b []core.Tag) bool { +func labelListLess(a, b []label.Label) bool { //TODO: make this more efficient return fmt.Sprint(a) < fmt.Sprint(b) } -func getGroup(tagMap core.TagMap, g *[][]core.Tag, keys []core.Key) (int, bool) { - group := make([]core.Tag, len(keys)) +func getGroup(lm label.Map, g *[][]label.Label, keys []label.Key) (int, bool) { + group := make([]label.Label, len(keys)) for i, key := range keys { - tag := tagMap.Find(key) - if tag.Valid() { - group[i] = tag + l := lm.Find(key) + if l.Valid() { + group[i] = l } } old := *g index := sort.Search(len(old), func(i int) bool { - return !tagListLess(old[i], group) + return !labelListLess(old[i], group) }) - if index < len(old) && tagListEqual(group, old[index]) { + if index < len(old) && labelListEqual(group, old[index]) { // not a new group return index, false } - *g = make([][]core.Tag, len(old)+1) + *g = make([][]label.Label, len(old)+1) copy(*g, old[:index]) copy((*g)[index+1:], old[index:]) (*g)[index] = group return index, true } -func (data *Int64Data) Handle() string { return data.Info.Name } -func (data *Int64Data) Groups() [][]core.Tag { return data.groups } +func (data *Int64Data) Handle() string { return data.Info.Name } +func (data *Int64Data) Groups() [][]label.Label { return data.groups } -func (data *Int64Data) modify(at time.Time, tagMap core.TagMap, f func(v int64) int64) Data { - index, insert := getGroup(tagMap, &data.groups, data.Info.Keys) +func (data *Int64Data) modify(at time.Time, lm label.Map, f func(v int64) int64) Data { + index, insert := getGroup(lm, &data.groups, data.Info.Keys) old := data.Rows if insert { data.Rows = make([]int64, len(old)+1) @@ -162,29 +163,29 @@ func (data *Int64Data) modify(at time.Time, tagMap core.TagMap, f func(v int64) return &frozen } -func (data *Int64Data) count(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v int64) int64 { +func (data *Int64Data) count(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v int64) int64 { return v + 1 }) } -func (data *Int64Data) sum(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v int64) int64 { - return v + data.key.From(tag) +func (data *Int64Data) sum(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v int64) int64 { + return v + data.key.From(l) }) } -func (data *Int64Data) latest(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v int64) int64 { - return data.key.From(tag) +func (data *Int64Data) latest(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v int64) int64 { + return data.key.From(l) }) } -func (data *Float64Data) Handle() string { return data.Info.Name } -func (data *Float64Data) Groups() [][]core.Tag { return data.groups } +func (data *Float64Data) Handle() string { return data.Info.Name } +func (data *Float64Data) Groups() [][]label.Label { return data.groups } -func (data *Float64Data) modify(at time.Time, tagMap core.TagMap, f func(v float64) float64) Data { - index, insert := getGroup(tagMap, &data.groups, data.Info.Keys) +func (data *Float64Data) modify(at time.Time, lm label.Map, f func(v float64) float64) Data { + index, insert := getGroup(lm, &data.groups, data.Info.Keys) old := data.Rows if insert { data.Rows = make([]float64, len(old)+1) @@ -200,23 +201,23 @@ func (data *Float64Data) modify(at time.Time, tagMap core.TagMap, f func(v float return &frozen } -func (data *Float64Data) sum(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v float64) float64 { - return v + data.key.From(tag) +func (data *Float64Data) sum(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v float64) float64 { + return v + data.key.From(l) }) } -func (data *Float64Data) latest(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v float64) float64 { - return data.key.From(tag) +func (data *Float64Data) latest(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v float64) float64 { + return data.key.From(l) }) } -func (data *HistogramInt64Data) Handle() string { return data.Info.Name } -func (data *HistogramInt64Data) Groups() [][]core.Tag { return data.groups } +func (data *HistogramInt64Data) Handle() string { return data.Info.Name } +func (data *HistogramInt64Data) Groups() [][]label.Label { return data.groups } -func (data *HistogramInt64Data) modify(at time.Time, tagMap core.TagMap, f func(v *HistogramInt64Row)) Data { - index, insert := getGroup(tagMap, &data.groups, data.Info.Keys) +func (data *HistogramInt64Data) modify(at time.Time, lm label.Map, f func(v *HistogramInt64Row)) Data { + index, insert := getGroup(lm, &data.groups, data.Info.Keys) old := data.Rows var v HistogramInt64Row if insert { @@ -238,9 +239,9 @@ func (data *HistogramInt64Data) modify(at time.Time, tagMap core.TagMap, f func( return &frozen } -func (data *HistogramInt64Data) record(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v *HistogramInt64Row) { - value := data.key.From(tag) +func (data *HistogramInt64Data) record(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v *HistogramInt64Row) { + value := data.key.From(l) v.Sum += value if v.Min > value || v.Count == 0 { v.Min = value @@ -257,11 +258,11 @@ func (data *HistogramInt64Data) record(at time.Time, tagMap core.TagMap, tag cor }) } -func (data *HistogramFloat64Data) Handle() string { return data.Info.Name } -func (data *HistogramFloat64Data) Groups() [][]core.Tag { return data.groups } +func (data *HistogramFloat64Data) Handle() string { return data.Info.Name } +func (data *HistogramFloat64Data) Groups() [][]label.Label { return data.groups } -func (data *HistogramFloat64Data) modify(at time.Time, tagMap core.TagMap, f func(v *HistogramFloat64Row)) Data { - index, insert := getGroup(tagMap, &data.groups, data.Info.Keys) +func (data *HistogramFloat64Data) modify(at time.Time, lm label.Map, f func(v *HistogramFloat64Row)) Data { + index, insert := getGroup(lm, &data.groups, data.Info.Keys) old := data.Rows var v HistogramFloat64Row if insert { @@ -283,9 +284,9 @@ func (data *HistogramFloat64Data) modify(at time.Time, tagMap core.TagMap, f fun return &frozen } -func (data *HistogramFloat64Data) record(at time.Time, tagMap core.TagMap, tag core.Tag) Data { - return data.modify(at, tagMap, func(v *HistogramFloat64Row) { - value := data.key.From(tag) +func (data *HistogramFloat64Data) record(at time.Time, lm label.Map, l label.Label) Data { + return data.modify(at, lm, func(v *HistogramFloat64Row) { + value := data.key.From(l) v.Sum += value if v.Min > value || v.Count == 0 { v.Min = value diff --git a/internal/event/export/metric/exporter.go b/internal/event/export/metric/exporter.go index c3653d98f4..cfcb20797b 100644 --- a/internal/event/export/metric/exporter.go +++ b/internal/event/export/metric/exporter.go @@ -12,6 +12,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) var Entries = core.NewKey("metric_entries", "The set of metrics calculated for an event") @@ -20,9 +21,9 @@ type Config struct { subscribers map[interface{}][]subscriber } -type subscriber func(time.Time, core.TagMap, core.Tag) Data +type subscriber func(time.Time, label.Map, label.Label) Data -func (e *Config) subscribe(key core.Key, s subscriber) { +func (e *Config) subscribe(key label.Key, s subscriber) { if e.subscribers == nil { e.subscribers = make(map[interface{}][]subscriber) } @@ -31,26 +32,26 @@ func (e *Config) subscribe(key core.Key, s subscriber) { func (e *Config) Exporter(output event.Exporter) event.Exporter { var mu sync.Mutex - return func(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { + return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { if !ev.IsRecord() { - return output(ctx, ev, tagMap) + return output(ctx, ev, lm) } mu.Lock() defer mu.Unlock() var metrics []Data for index := 0; ev.Valid(index); index++ { - tag := ev.Tag(index) - if !tag.Valid() { + l := ev.Label(index) + if !l.Valid() { continue } - id := tag.Key() + id := l.Key() if list := e.subscribers[id]; len(list) > 0 { for _, s := range list { - metrics = append(metrics, s(ev.At, tagMap, tag)) + metrics = append(metrics, s(ev.At, lm, l)) } } } - tagMap = core.MergeTagMaps(core.NewTagMap(Entries.Of(metrics)), tagMap) - return output(ctx, ev, tagMap) + lm = label.MergeMaps(label.NewMap(Entries.Of(metrics)), lm) + return output(ctx, ev, lm) } } diff --git a/internal/event/export/metric/info.go b/internal/event/export/metric/info.go index 2d423d1f5c..ef88d85efc 100644 --- a/internal/event/export/metric/info.go +++ b/internal/event/export/metric/info.go @@ -4,7 +4,10 @@ package metric -import "golang.org/x/tools/internal/event/core" +import ( + "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" +) // Scalar represents the construction information for a scalar metric. type Scalar struct { @@ -12,8 +15,8 @@ type Scalar struct { Name string // Description can be used by observers to describe the metric to users. Description string - // Keys is the set of tags that collectively describe rows of the metric. - Keys []core.Key + // Keys is the set of labels that collectively describe rows of the metric. + Keys []label.Key } // HistogramInt64 represents the construction information for an int64 histogram metric. @@ -22,8 +25,8 @@ type HistogramInt64 struct { Name string // Description can be used by observers to describe the metric to users. Description string - // Keys is the set of tags that collectively describe rows of the metric. - Keys []core.Key + // Keys is the set of labels that collectively describe rows of the metric. + Keys []label.Key // Buckets holds the inclusive upper bound of each bucket in the histogram. Buckets []int64 } @@ -34,8 +37,8 @@ type HistogramFloat64 struct { Name string // Description can be used by observers to describe the metric to users. Description string - // Keys is the set of tags that collectively describe rows of the metric. - Keys []core.Key + // Keys is the set of labels that collectively describe rows of the metric. + Keys []label.Key // Buckets holds the inclusive upper bound of each bucket in the histogram. Buckets []float64 } @@ -43,7 +46,7 @@ type HistogramFloat64 struct { // Count creates a new metric based on the Scalar information that counts // the number of times the supplied int64 measure is set. // Metrics of this type will use Int64Data. -func (info Scalar) Count(e *Config, key core.Key) { +func (info Scalar) Count(e *Config, key label.Key) { data := &Int64Data{Info: &info, key: nil} e.subscribe(key, data.count) } diff --git a/internal/event/export/ocagent/metrics.go b/internal/event/export/ocagent/metrics.go index 3250c4f948..78d65994db 100644 --- a/internal/event/export/ocagent/metrics.go +++ b/internal/event/export/ocagent/metrics.go @@ -7,9 +7,9 @@ package ocagent import ( "time" - "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export/metric" "golang.org/x/tools/internal/event/export/ocagent/wire" + "golang.org/x/tools/internal/event/label" ) // dataToMetricDescriptor return a *wire.MetricDescriptor based on data. @@ -201,7 +201,7 @@ func distributionToPoints(counts []int64, count int64, sum float64, bucketBounds // infoKeysToLabelKeys returns an array of *wire.LabelKeys containing the // string values of the elements of labelKeys. -func infoKeysToLabelKeys(infoKeys []core.Key) []*wire.LabelKey { +func infoKeysToLabelKeys(infoKeys []label.Key) []*wire.LabelKey { labelKeys := make([]*wire.LabelKey, 0, len(infoKeys)) for _, key := range infoKeys { labelKeys = append(labelKeys, &wire.LabelKey{ diff --git a/internal/event/export/ocagent/ocagent.go b/internal/event/export/ocagent/ocagent.go index 0f1059260c..fabb7c1abe 100644 --- a/internal/event/export/ocagent/ocagent.go +++ b/internal/event/export/ocagent/ocagent.go @@ -22,6 +22,7 @@ import ( "golang.org/x/tools/internal/event/export" "golang.org/x/tools/internal/event/export/metric" "golang.org/x/tools/internal/event/export/ocagent/wire" + "golang.org/x/tools/internal/event/label" ) type Config struct { @@ -85,7 +86,7 @@ func Connect(config *Config) *Exporter { return exporter } -func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { +func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context { switch { case ev.IsEndSpan(): e.mu.Lock() @@ -97,7 +98,7 @@ func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, tagMap core. case ev.IsRecord(): e.mu.Lock() defer e.mu.Unlock() - data := metric.Entries.Get(tagMap).([]metric.Data) + data := metric.Entries.Get(lm).([]metric.Data) e.metrics = append(e.metrics, data...) } return ctx @@ -200,7 +201,7 @@ func convertSpan(span *export.Span) *wire.Span { Kind: wire.UnspecifiedSpanKind, StartTime: convertTimestamp(span.Start().At), EndTime: convertTimestamp(span.Finish().At), - Attributes: convertAttributes(core.Filter(span.Start(), core.Name)), + Attributes: convertAttributes(label.Filter(span.Start(), core.Name)), TimeEvents: convertEvents(span.Events()), SameProcessAsParentSpan: true, //TODO: StackTrace? @@ -227,68 +228,68 @@ func convertMetric(data metric.Data, start time.Time) *wire.Metric { } } -func skipToValidTag(l core.TagList) (int, core.Tag) { - // skip to the first valid tag - for index := 0; l.Valid(index); index++ { - if tag := l.Tag(index); tag.Valid() { - return index, tag +func skipToValidLabel(list label.List) (int, label.Label) { + // skip to the first valid label + for index := 0; list.Valid(index); index++ { + if l := list.Label(index); l.Valid() { + return index, l } } - return -1, core.Tag{} + return -1, label.Label{} } -func convertAttributes(l core.TagList) *wire.Attributes { - index, tag := skipToValidTag(l) - if !tag.Valid() { +func convertAttributes(list label.List) *wire.Attributes { + index, l := skipToValidLabel(list) + if !l.Valid() { return nil } attributes := make(map[string]wire.Attribute) for { - if tag.Valid() { - attributes[tag.Key().Name()] = convertAttribute(tag) + if l.Valid() { + attributes[l.Key().Name()] = convertAttribute(l) } index++ - if !l.Valid(index) { + if !list.Valid(index) { return &wire.Attributes{AttributeMap: attributes} } - tag = l.Tag(index) + l = list.Label(index) } } -func convertAttribute(tag core.Tag) wire.Attribute { - switch key := tag.Key().(type) { +func convertAttribute(l label.Label) wire.Attribute { + switch key := l.Key().(type) { case *core.IntKey: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.Int8Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.Int16Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.Int32Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.Int64Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.UIntKey: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.UInt8Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.UInt16Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.UInt32Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.UInt64Key: - return wire.IntAttribute{IntValue: int64(key.From(tag))} + return wire.IntAttribute{IntValue: int64(key.From(l))} case *core.Float32Key: - return wire.DoubleAttribute{DoubleValue: float64(key.From(tag))} + return wire.DoubleAttribute{DoubleValue: float64(key.From(l))} case *core.Float64Key: - return wire.DoubleAttribute{DoubleValue: key.From(tag)} + return wire.DoubleAttribute{DoubleValue: key.From(l)} case *core.BooleanKey: - return wire.BoolAttribute{BoolValue: key.From(tag)} + return wire.BoolAttribute{BoolValue: key.From(l)} case *core.StringKey: - return wire.StringAttribute{StringValue: toTruncatableString(key.From(tag))} + return wire.StringAttribute{StringValue: toTruncatableString(key.From(l))} case *core.ErrorKey: - return wire.StringAttribute{StringValue: toTruncatableString(key.From(tag).Error())} + return wire.StringAttribute{StringValue: toTruncatableString(key.From(l).Error())} case *core.ValueKey: - return wire.StringAttribute{StringValue: toTruncatableString(fmt.Sprint(key.From(tag)))} + return wire.StringAttribute{StringValue: toTruncatableString(fmt.Sprint(key.From(l)))} default: return wire.StringAttribute{StringValue: toTruncatableString(fmt.Sprintf("%T", key))} } @@ -311,21 +312,21 @@ func convertEvent(ev core.Event) wire.TimeEvent { } func convertAnnotation(ev core.Event) *wire.Annotation { - if _, tag := skipToValidTag(ev); !tag.Valid() { + if _, l := skipToValidLabel(ev); !l.Valid() { return nil } - tagMap := core.TagMap(ev) - description := core.Msg.Get(tagMap) - tags := core.Filter(ev, core.Msg) + lm := label.Map(ev) + description := core.Msg.Get(lm) + labels := label.Filter(ev, core.Msg) if description == "" { - err := core.Err.Get(tagMap) - tags = core.Filter(tags, core.Err) + err := core.Err.Get(lm) + labels = label.Filter(labels, core.Err) if err != nil { description = err.Error() } } return &wire.Annotation{ Description: toTruncatableString(description), - Attributes: convertAttributes(tags), + Attributes: convertAttributes(labels), } } diff --git a/internal/event/export/ocagent/ocagent_test.go b/internal/event/export/ocagent/ocagent_test.go index c1f2f959ff..a4cdafed17 100644 --- a/internal/event/export/ocagent/ocagent_test.go +++ b/internal/event/export/ocagent/ocagent_test.go @@ -20,6 +20,7 @@ import ( "golang.org/x/tools/internal/event/export" "golang.org/x/tools/internal/event/export/metric" "golang.org/x/tools/internal/event/export/ocagent" + "golang.org/x/tools/internal/event/label" ) const testNodeStr = `{ @@ -72,21 +73,21 @@ var ( metricLatency = metric.HistogramFloat64{ Name: "latency_ms", Description: "The latency of calls in milliseconds", - Keys: []core.Key{keyMethod, keyRoute}, + Keys: []label.Key{keyMethod, keyRoute}, Buckets: []float64{0, 5, 10, 25, 50}, } metricBytesIn = metric.HistogramInt64{ Name: "latency_ms", Description: "The latency of calls in milliseconds", - Keys: []core.Key{keyMethod, keyRoute}, + Keys: []label.Key{keyMethod, keyRoute}, Buckets: []int64{0, 10, 50, 100, 500, 1000, 2000}, } metricRecursiveCalls = metric.Scalar{ Name: "latency_ms", Description: "The latency of calls in milliseconds", - Keys: []core.Key{keyMethod, keyRoute}, + Keys: []label.Key{keyMethod, keyRoute}, } ) @@ -125,7 +126,7 @@ func timeFixer(output event.Exporter) event.Exporter { start, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:30Z") at, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:40Z") end, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:50Z") - return func(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { + return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { switch { case ev.IsStartSpan(): ev.At = start @@ -134,17 +135,17 @@ func timeFixer(output event.Exporter) event.Exporter { default: ev.At = at } - return output(ctx, ev, tagMap) + return output(ctx, ev, lm) } } func spanFixer(output event.Exporter) event.Exporter { - return func(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { + return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { if ev.IsStartSpan() { span := export.GetSpan(ctx) span.ID = export.SpanContext{} } - return output(ctx, ev, tagMap) + return output(ctx, ev, lm) } } diff --git a/internal/event/export/ocagent/trace_test.go b/internal/event/export/ocagent/trace_test.go index 0f04bee4d4..f8e9781bef 100644 --- a/internal/event/export/ocagent/trace_test.go +++ b/internal/event/export/ocagent/trace_test.go @@ -11,6 +11,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) func TestTrace(t *testing.T) { @@ -37,9 +38,9 @@ func TestTrace(t *testing.T) { want string }{ { - name: "no tags", + name: "no labels", run: func(ctx context.Context) { - core.Export(ctx, core.MakeEvent(core.LogType, [3]core.Tag{}, nil)) + core.Export(ctx, core.MakeEvent(core.LogType, [3]label.Label{}, nil)) }, want: prefix + ` "timeEvent":[{"time":"1970-01-01T00:00:40Z"}] diff --git a/internal/event/export/ocagent/wire/common.go b/internal/event/export/ocagent/wire/common.go index 61dbfcd9e7..f22b535654 100644 --- a/internal/event/export/ocagent/wire/common.go +++ b/internal/event/export/ocagent/wire/common.go @@ -45,13 +45,13 @@ type DoubleAttribute struct { } type Attribute interface { - tagAttribute() + labelAttribute() } -func (StringAttribute) tagAttribute() {} -func (IntAttribute) tagAttribute() {} -func (BoolAttribute) tagAttribute() {} -func (DoubleAttribute) tagAttribute() {} +func (StringAttribute) labelAttribute() {} +func (IntAttribute) labelAttribute() {} +func (BoolAttribute) labelAttribute() {} +func (DoubleAttribute) labelAttribute() {} type StackTrace struct { StackFrames *StackFrames `json:"stack_frames,omitempty"` diff --git a/internal/event/export/ocagent/wire/metrics.go b/internal/event/export/ocagent/wire/metrics.go index 1c5cf41eda..4cfdb88bf4 100644 --- a/internal/event/export/ocagent/wire/metrics.go +++ b/internal/event/export/ocagent/wire/metrics.go @@ -122,13 +122,13 @@ type PointSummaryValue struct { } type PointValue interface { - tagPointValue() + labelPointValue() } -func (PointInt64Value) tagPointValue() {} -func (PointDoubleValue) tagPointValue() {} -func (PointDistributionValue) tagPointValue() {} -func (PointSummaryValue) tagPointValue() {} +func (PointInt64Value) labelPointValue() {} +func (PointDoubleValue) labelPointValue() {} +func (PointDistributionValue) labelPointValue() {} +func (PointSummaryValue) labelPointValue() {} type DistributionValue struct { Count int64 `json:"count,omitempty"` @@ -143,10 +143,10 @@ type BucketOptionsExplicit struct { } type BucketOptions interface { - tagBucketOptions() + labelBucketOptions() } -func (*BucketOptionsExplicit) tagBucketOptions() {} +func (*BucketOptionsExplicit) labelBucketOptions() {} var _ BucketOptions = (*BucketOptionsExplicit)(nil) var _ json.Marshaler = (*BucketOptionsExplicit)(nil) diff --git a/internal/event/export/ocagent/wire/trace.go b/internal/event/export/ocagent/wire/trace.go index c1a79a58bb..88856673a1 100644 --- a/internal/event/export/ocagent/wire/trace.go +++ b/internal/event/export/ocagent/wire/trace.go @@ -79,11 +79,11 @@ const ( ) type TimeEventValue interface { - tagTimeEventValue() + labelTimeEventValue() } -func (Annotation) tagTimeEventValue() {} -func (MessageEvent) tagTimeEventValue() {} +func (Annotation) labelTimeEventValue() {} +func (MessageEvent) labelTimeEventValue() {} type Links struct { Link []*Link `json:"link,omitempty"` diff --git a/internal/event/export/prometheus/prometheus.go b/internal/event/export/prometheus/prometheus.go index 129f260767..c8272c71dc 100644 --- a/internal/event/export/prometheus/prometheus.go +++ b/internal/event/export/prometheus/prometheus.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export/metric" + "golang.org/x/tools/internal/event/label" ) func New() *Exporter { @@ -25,13 +26,13 @@ type Exporter struct { metrics []metric.Data } -func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { +func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, ln label.Map) context.Context { if !ev.IsRecord() { return ctx } e.mu.Lock() defer e.mu.Unlock() - metrics := metric.Entries.Get(tagMap).([]metric.Data) + metrics := metric.Entries.Get(ln).([]metric.Data) for _, data := range metrics { name := data.Handle() // We keep the metrics in name sorted order so the page is stable and easy @@ -64,7 +65,7 @@ func (e *Exporter) header(w http.ResponseWriter, name, description string, isGau fmt.Fprintf(w, "# TYPE %s %s\n", name, kind) } -func (e *Exporter) row(w http.ResponseWriter, name string, group []core.Tag, extra string, value interface{}) { +func (e *Exporter) row(w http.ResponseWriter, name string, group []label.Label, extra string, value interface{}) { fmt.Fprint(w, name) buf := &bytes.Buffer{} fmt.Fprint(buf, group) diff --git a/internal/event/export/tag.go b/internal/event/export/tag.go index bc2ecb4b8f..09a201ac17 100644 --- a/internal/event/export/tag.go +++ b/internal/event/export/tag.go @@ -9,28 +9,29 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) // Labels builds an exporter that manipulates the context using the event. -// If the event is type IsTag or IsStartSpan then it returns a context updated -// with tag values from the event. -// For all other event types the event tags will be updated with values from the +// If the event is type IsLabel or IsStartSpan then it returns a context updated +// with label values from the event. +// For all other event types the event labels will be updated with values from the // context if they are missing. func Labels(output event.Exporter) event.Exporter { - return func(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { - stored, _ := ctx.Value(labelContextKey).(core.TagMap) + return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { + stored, _ := ctx.Value(labelContextKey).(label.Map) if ev.IsLabel() || ev.IsStartSpan() { - // update the tag source stored in the context - fromEvent := core.TagMap(ev) + // update the label map stored in the context + fromEvent := label.Map(ev) if stored == nil { stored = fromEvent } else { - stored = core.MergeTagMaps(fromEvent, stored) + stored = label.MergeMaps(fromEvent, stored) } ctx = context.WithValue(ctx, labelContextKey, stored) } - // add the stored tag context to the tag source - tagMap = core.MergeTagMaps(tagMap, stored) - return output(ctx, ev, tagMap) + // add the stored label context to the label map + lm = label.MergeMaps(lm, stored) + return output(ctx, ev, lm) } } diff --git a/internal/event/export/trace.go b/internal/event/export/trace.go index 528fdad82d..aa2b4a6221 100644 --- a/internal/event/export/trace.go +++ b/internal/event/export/trace.go @@ -11,6 +11,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) type SpanContext struct { @@ -45,11 +46,11 @@ func GetSpan(ctx context.Context) *Span { // Spans creates an exporter that maintains hierarchical span structure in the // context. -// It creates new spans on EventStartSpan, adds events to the current span on -// EventLog or EventTag, and closes the span on EventEndSpan. +// 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, tagMap core.TagMap) context.Context { + 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 { @@ -59,7 +60,7 @@ func Spans(output event.Exporter) event.Exporter { } case ev.IsStartSpan(): span := &Span{ - Name: core.Name.Get(tagMap), + Name: core.Name.Get(lm), start: ev, } if parent := GetSpan(ctx); parent != nil { @@ -79,7 +80,7 @@ func Spans(output event.Exporter) event.Exporter { case ev.IsDetach(): ctx = context.WithValue(ctx, spanContextKey, nil) } - return output(ctx, ev, tagMap) + return output(ctx, ev, lm) } } diff --git a/internal/event/label/label.go b/internal/event/label/label.go new file mode 100644 index 0000000000..b55c12eb25 --- /dev/null +++ b/internal/event/label/label.go @@ -0,0 +1,213 @@ +// 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 label + +import ( + "fmt" + "io" + "reflect" + "unsafe" +) + +// Key is used as the identity of a Label. +// Keys are intended to be compared by pointer only, the name should be unique +// for communicating with external systems, but it is not required or enforced. +type Key interface { + // Name returns the key name. + Name() string + // Description returns a string that can be used to describe the value. + Description() string + + // Format is used in formatting to append the value of the label to the + // supplied buffer. + // The formatter may use the supplied buf as a scratch area to avoid + // allocations. + Format(w io.Writer, buf []byte, l Label) +} + +// Label holds a key and value pair. +// It is normally used when passing around lists of labels. +type Label struct { + key Key + packed uint64 + untyped interface{} +} + +// Map is the interface to a collection of Labels indexed by key. +type Map interface { + // Find returns the label that matches the supplied key. + Find(key Key) Label +} + +// List is the interface to something that provides an iterable +// list of labels. +// Iteration should start from 0 and continue until Valid returns false. +type List interface { + // Valid returns true if the index is within range for the list. + // It does not imply the label at that index will itself be valid. + Valid(index int) bool + // Label returns the label at the given index. + Label(index int) Label +} + +// list implements LabelList for a list of Labels. +type list struct { + labels []Label +} + +// filter wraps a LabelList filtering out specific labels. +type filter struct { + keys []Key + underlying List +} + +// listMap implements LabelMap for a simple list of labels. +type listMap struct { + labels []Label +} + +// mapChain implements LabelMap for a list of underlying LabelMap. +type mapChain struct { + maps []Map +} + +// OfValue creates a new label from the key and value. +// This method is for implementing new key types, label creation should +// normally be done with the Of method of the key. +func OfValue(k Key, value interface{}) Label { return Label{key: k, untyped: value} } + +// UnpackValue assumes the label was built using LabelOfValue and returns the value +// that was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Label) UnpackValue() interface{} { return t.untyped } + +// Of64 creates a new label from a key and a uint64. This is often +// used for non uint64 values that can be packed into a uint64. +// This method is for implementing new key types, label creation should +// normally be done with the Of method of the key. +func Of64(k Key, v uint64) Label { return Label{key: k, packed: v} } + +// Unpack64 assumes the label was built using LabelOf64 and returns the value that +// was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Label) Unpack64() uint64 { return t.packed } + +// OfString creates a new label from a key and a string. +// This method is for implementing new key types, label creation should +// normally be done with the Of method of the key. +func OfString(k Key, v string) Label { + hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) + return Label{ + key: k, + packed: uint64(hdr.Len), + untyped: unsafe.Pointer(hdr.Data), + } +} + +// UnpackString assumes the label was built using LabelOfString and returns the +// value that was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Label) UnpackString() string { + var v string + hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) + hdr.Data = uintptr(t.untyped.(unsafe.Pointer)) + hdr.Len = int(t.packed) + return *(*string)(unsafe.Pointer(hdr)) +} + +// Valid returns true if the Label is a valid one (it has a key). +func (t Label) Valid() bool { return t.key != nil } + +// Key returns the key of this Label. +func (t Label) Key() Key { return t.key } + +// Format is used for debug printing of labels. +func (t Label) Format(f fmt.State, r rune) { + if !t.Valid() { + io.WriteString(f, `nil`) + return + } + io.WriteString(f, t.Key().Name()) + io.WriteString(f, "=") + var buf [128]byte + t.Key().Format(f, buf[:0], t) +} + +func (l *list) Valid(index int) bool { + return index >= 0 && index < len(l.labels) +} + +func (l *list) Label(index int) Label { + return l.labels[index] +} + +func (f *filter) Valid(index int) bool { + return f.underlying.Valid(index) +} + +func (f *filter) Label(index int) Label { + l := f.underlying.Label(index) + for _, f := range f.keys { + if l.Key() == f { + return Label{} + } + } + return l +} + +func (lm listMap) Find(key Key) Label { + for _, l := range lm.labels { + if l.Key() == key { + return l + } + } + return Label{} +} + +func (c mapChain) Find(key Key) Label { + for _, src := range c.maps { + l := src.Find(key) + if l.Valid() { + return l + } + } + return Label{} +} + +var emptyList = &list{} + +func NewList(labels ...Label) List { + if len(labels) == 0 { + return emptyList + } + return &list{labels: labels} +} + +func Filter(l List, keys ...Key) List { + if len(keys) == 0 { + return l + } + return &filter{keys: keys, underlying: l} +} + +func NewMap(labels ...Label) Map { + return listMap{labels: labels} +} + +func MergeMaps(srcs ...Map) Map { + var nonNil []Map + for _, src := range srcs { + if src != nil { + nonNil = append(nonNil, src) + } + } + if len(nonNil) == 1 { + return nonNil[0] + } + return mapChain{maps: nonNil} +} diff --git a/internal/event/core/tag_test.go b/internal/event/label/label_test.go similarity index 54% rename from internal/event/core/tag_test.go rename to internal/event/label/label_test.go index c03b146b53..92b68dc873 100644 --- a/internal/event/core/tag_test.go +++ b/internal/event/label/label_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package core_test +package label_test import ( "bytes" @@ -10,6 +10,7 @@ import ( "testing" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" ) var ( @@ -19,59 +20,59 @@ var ( A = AKey.Of("a") B = BKey.Of("b") C = CKey.Of("c") - all = []core.Tag{A, B, C} + all = []label.Label{A, B, C} ) -func TestTagList(t *testing.T) { +func TestList(t *testing.T) { for _, test := range []struct { name string - tags []core.Tag + labels []label.Label expect string }{{ name: "empty", }, { name: "single", - tags: []core.Tag{A}, + labels: []label.Label{A}, expect: `A="a"`, }, { name: "invalid", - tags: []core.Tag{{}}, + labels: []label.Label{{}}, expect: ``, }, { name: "two", - tags: []core.Tag{A, B}, + labels: []label.Label{A, B}, expect: `A="a", B="b"`, }, { name: "three", - tags: []core.Tag{A, B, C}, + labels: []label.Label{A, B, C}, expect: `A="a", B="b", C="c"`, }, { name: "missing A", - tags: []core.Tag{{}, B, C}, + labels: []label.Label{{}, B, C}, expect: `B="b", C="c"`, }, { name: "missing B", - tags: []core.Tag{A, {}, C}, + labels: []label.Label{A, {}, C}, expect: `A="a", C="c"`, }, { name: "missing C", - tags: []core.Tag{A, B, {}}, + labels: []label.Label{A, B, {}}, expect: `A="a", B="b"`, }, { name: "missing AB", - tags: []core.Tag{{}, {}, C}, + labels: []label.Label{{}, {}, C}, expect: `C="c"`, }, { name: "missing AC", - tags: []core.Tag{{}, B, {}}, + labels: []label.Label{{}, B, {}}, expect: `B="b"`, }, { name: "missing BC", - tags: []core.Tag{A, {}, {}}, + labels: []label.Label{A, {}, {}}, expect: `A="a"`, }} { t.Run(test.name, func(t *testing.T) { - got := printList(core.NewTagList(test.tags...)) + got := printList(label.NewList(test.labels...)) if got != test.expect { t.Errorf("got %q want %q", got, test.expect) } @@ -79,44 +80,44 @@ func TestTagList(t *testing.T) { } } -func TestTagFilter(t *testing.T) { +func TestFilter(t *testing.T) { for _, test := range []struct { name string - tags []core.Tag - filters []core.Key + labels []label.Label + filters []label.Key expect string }{{ name: "no filters", - tags: all, + labels: all, expect: `A="a", B="b", C="c"`, }, { - name: "no tags", - filters: []core.Key{AKey}, + name: "no labels", + filters: []label.Key{AKey}, expect: ``, }, { name: "filter A", - tags: all, - filters: []core.Key{AKey}, + labels: all, + filters: []label.Key{AKey}, expect: `B="b", C="c"`, }, { name: "filter B", - tags: all, - filters: []core.Key{BKey}, + labels: all, + filters: []label.Key{BKey}, expect: `A="a", C="c"`, }, { name: "filter C", - tags: all, - filters: []core.Key{CKey}, + labels: all, + filters: []label.Key{CKey}, expect: `A="a", B="b"`, }, { name: "filter AC", - tags: all, - filters: []core.Key{AKey, CKey}, + labels: all, + filters: []label.Key{AKey, CKey}, expect: `B="b"`, }} { t.Run(test.name, func(t *testing.T) { - tags := core.NewTagList(test.tags...) - got := printList(core.Filter(tags, test.filters...)) + labels := label.NewList(test.labels...) + got := printList(label.Filter(labels, test.filters...)) if got != test.expect { t.Errorf("got %q want %q", got, test.expect) } @@ -124,55 +125,55 @@ func TestTagFilter(t *testing.T) { } } -func TestTagMap(t *testing.T) { +func TestMap(t *testing.T) { for _, test := range []struct { name string - tags []core.Tag - keys []core.Key + labels []label.Label + keys []label.Key expect string }{{ - name: "no tags", - keys: []core.Key{AKey}, + name: "no labels", + keys: []label.Key{AKey}, expect: `nil`, }, { name: "match A", - tags: all, - keys: []core.Key{AKey}, + labels: all, + keys: []label.Key{AKey}, expect: `A="a"`, }, { name: "match B", - tags: all, - keys: []core.Key{BKey}, + labels: all, + keys: []label.Key{BKey}, expect: `B="b"`, }, { name: "match C", - tags: all, - keys: []core.Key{CKey}, + labels: all, + keys: []label.Key{CKey}, expect: `C="c"`, }, { name: "match ABC", - tags: all, - keys: []core.Key{AKey, BKey, CKey}, + labels: all, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", B="b", C="c"`, }, { name: "missing A", - tags: []core.Tag{{}, B, C}, - keys: []core.Key{AKey, BKey, CKey}, + labels: []label.Label{{}, B, C}, + keys: []label.Key{AKey, BKey, CKey}, expect: `nil, B="b", C="c"`, }, { name: "missing B", - tags: []core.Tag{A, {}, C}, - keys: []core.Key{AKey, BKey, CKey}, + labels: []label.Label{A, {}, C}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", nil, C="c"`, }, { name: "missing C", - tags: []core.Tag{A, B, {}}, - keys: []core.Key{AKey, BKey, CKey}, + labels: []label.Label{A, B, {}}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", B="b", nil`, }} { t.Run(test.name, func(t *testing.T) { - tagMap := core.NewTagMap(test.tags...) - got := printTagMap(tagMap, test.keys) + lm := label.NewMap(test.labels...) + got := printMap(lm, test.keys) if got != test.expect { t.Errorf("got %q want %q", got, test.expect) } @@ -180,60 +181,60 @@ func TestTagMap(t *testing.T) { } } -func TestTagMapMerge(t *testing.T) { +func TestMapMerge(t *testing.T) { for _, test := range []struct { name string - maps []core.TagMap - keys []core.Key + maps []label.Map + keys []label.Key expect string }{{ name: "no maps", - keys: []core.Key{AKey}, + keys: []label.Key{AKey}, expect: `nil`, }, { name: "one map", - maps: []core.TagMap{core.NewTagMap(all...)}, - keys: []core.Key{AKey}, + maps: []label.Map{label.NewMap(all...)}, + keys: []label.Key{AKey}, expect: `A="a"`, }, { name: "invalid map", - maps: []core.TagMap{core.NewTagMap()}, - keys: []core.Key{AKey}, + maps: []label.Map{label.NewMap()}, + keys: []label.Key{AKey}, expect: `nil`, }, { name: "two maps", - maps: []core.TagMap{core.NewTagMap(B, C), core.NewTagMap(A)}, - keys: []core.Key{AKey, BKey, CKey}, + maps: []label.Map{label.NewMap(B, C), label.NewMap(A)}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", B="b", C="c"`, }, { name: "invalid start map", - maps: []core.TagMap{core.NewTagMap(), core.NewTagMap(B, C)}, - keys: []core.Key{AKey, BKey, CKey}, + maps: []label.Map{label.NewMap(), label.NewMap(B, C)}, + keys: []label.Key{AKey, BKey, CKey}, expect: `nil, B="b", C="c"`, }, { name: "invalid mid map", - maps: []core.TagMap{core.NewTagMap(A), core.NewTagMap(), core.NewTagMap(C)}, - keys: []core.Key{AKey, BKey, CKey}, + maps: []label.Map{label.NewMap(A), label.NewMap(), label.NewMap(C)}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", nil, C="c"`, }, { name: "invalid end map", - maps: []core.TagMap{core.NewTagMap(A, B), core.NewTagMap()}, - keys: []core.Key{AKey, BKey, CKey}, + maps: []label.Map{label.NewMap(A, B), label.NewMap()}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", B="b", nil`, }, { name: "three maps one nil", - maps: []core.TagMap{core.NewTagMap(A), core.NewTagMap(B), nil}, - keys: []core.Key{AKey, BKey, CKey}, + maps: []label.Map{label.NewMap(A), label.NewMap(B), nil}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", B="b", nil`, }, { name: "two maps one nil", - maps: []core.TagMap{core.NewTagMap(A, B), nil}, - keys: []core.Key{AKey, BKey, CKey}, + maps: []label.Map{label.NewMap(A, B), nil}, + keys: []label.Key{AKey, BKey, CKey}, expect: `A="a", B="b", nil`, }} { t.Run(test.name, func(t *testing.T) { - tagMap := core.MergeTagMaps(test.maps...) - got := printTagMap(tagMap, test.keys) + tagMap := label.MergeMaps(test.maps...) + got := printMap(tagMap, test.keys) if got != test.expect { t.Errorf("got %q want %q", got, test.expect) } @@ -241,28 +242,28 @@ func TestTagMapMerge(t *testing.T) { } } -func printList(l core.TagList) string { +func printList(list label.List) string { buf := &bytes.Buffer{} - for index := 0; l.Valid(index); index++ { - tag := l.Tag(index) - if !tag.Valid() { + for index := 0; list.Valid(index); index++ { + l := list.Label(index) + if !l.Valid() { continue } if buf.Len() > 0 { buf.WriteString(", ") } - fmt.Fprint(buf, tag) + fmt.Fprint(buf, l) } return buf.String() } -func printTagMap(tagMap core.TagMap, keys []core.Key) string { +func printMap(lm label.Map, keys []label.Key) string { buf := &bytes.Buffer{} for _, key := range keys { if buf.Len() > 0 { buf.WriteString(", ") } - fmt.Fprint(buf, tagMap.Find(key)) + fmt.Fprint(buf, lm.Find(key)) } return buf.String() } diff --git a/internal/jsonrpc2/jsonrpc2.go b/internal/jsonrpc2/jsonrpc2.go index 43cfccdb48..88a1f4910a 100644 --- a/internal/jsonrpc2/jsonrpc2.go +++ b/internal/jsonrpc2/jsonrpc2.go @@ -15,7 +15,7 @@ import ( "sync/atomic" "golang.org/x/tools/internal/event" - "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" "golang.org/x/tools/internal/lsp/debug/tag" ) @@ -173,17 +173,17 @@ func (c *Conn) Run(runCtx context.Context, handler Handler) error { } switch msg := msg.(type) { case Request: - tags := []core.Tag{ + labels := []label.Label{ tag.Method.Of(msg.Method()), tag.RPCDirection.Of(tag.Inbound), {}, // reserved for ID if present } if call, ok := msg.(*Call); ok { - tags[len(tags)-1] = tag.RPCID.Of(fmt.Sprintf("%q", call.ID())) + labels[len(labels)-1] = tag.RPCID.Of(fmt.Sprintf("%q", call.ID())) } else { - tags = tags[:len(tags)-1] + labels = labels[:len(labels)-1] } - reqCtx, spanDone := event.Start(runCtx, msg.Method(), tags...) + reqCtx, spanDone := event.Start(runCtx, msg.Method(), labels...) event.Metric(reqCtx, tag.Started.Of(1), tag.ReceivedBytes.Of(n)) diff --git a/internal/lsp/debug/metrics.go b/internal/lsp/debug/metrics.go index 94b582ead0..8efc1d495e 100644 --- a/internal/lsp/debug/metrics.go +++ b/internal/lsp/debug/metrics.go @@ -5,8 +5,8 @@ package debug import ( - "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export/metric" + "golang.org/x/tools/internal/event/label" "golang.org/x/tools/internal/lsp/debug/tag" ) @@ -18,34 +18,34 @@ var ( receivedBytes = metric.HistogramInt64{ Name: "received_bytes", Description: "Distribution of received bytes, by method.", - Keys: []core.Key{tag.RPCDirection, tag.Method}, + Keys: []label.Key{tag.RPCDirection, tag.Method}, Buckets: bytesDistribution, } sentBytes = metric.HistogramInt64{ Name: "sent_bytes", Description: "Distribution of sent bytes, by method.", - Keys: []core.Key{tag.RPCDirection, tag.Method}, + Keys: []label.Key{tag.RPCDirection, tag.Method}, Buckets: bytesDistribution, } latency = metric.HistogramFloat64{ Name: "latency", Description: "Distribution of latency in milliseconds, by method.", - Keys: []core.Key{tag.RPCDirection, tag.Method}, + Keys: []label.Key{tag.RPCDirection, tag.Method}, Buckets: millisecondsDistribution, } started = metric.Scalar{ Name: "started", Description: "Count of RPCs started by method.", - Keys: []core.Key{tag.RPCDirection, tag.Method}, + Keys: []label.Key{tag.RPCDirection, tag.Method}, } completed = metric.Scalar{ Name: "completed", Description: "Count of RPCs completed by method and status.", - Keys: []core.Key{tag.RPCDirection, tag.Method, tag.StatusCode}, + Keys: []label.Key{tag.RPCDirection, tag.Method, tag.StatusCode}, } ) diff --git a/internal/lsp/debug/rpc.go b/internal/lsp/debug/rpc.go index 4bbca75dde..de90a6cf32 100644 --- a/internal/lsp/debug/rpc.go +++ b/internal/lsp/debug/rpc.go @@ -15,6 +15,7 @@ import ( "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export" + "golang.org/x/tools/internal/event/label" "golang.org/x/tools/internal/lsp/debug/tag" ) @@ -77,7 +78,7 @@ type rpcCodeBucket struct { Count int64 } -func (r *rpcs) ProcessEvent(ctx context.Context, ev core.Event, tagMap core.TagMap) context.Context { +func (r *rpcs) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context { r.mu.Lock() defer r.mu.Unlock() switch { @@ -91,8 +92,8 @@ func (r *rpcs) ProcessEvent(ctx context.Context, ev core.Event, tagMap core.TagM endRPC(ctx, ev, span, stats) } case ev.IsRecord(): - sent := byteUnits(tag.SentBytes.Get(tagMap)) - rec := byteUnits(tag.ReceivedBytes.Get(tagMap)) + sent := byteUnits(tag.SentBytes.Get(lm)) + rec := byteUnits(tag.ReceivedBytes.Get(lm)) if sent != 0 || rec != 0 { if _, stats := r.getRPCSpan(ctx, ev); stats != nil { stats.Sent += sent @@ -161,13 +162,13 @@ func (r *rpcs) getRPCSpan(ctx context.Context, ev core.Event) (*export.Span, *rp return span, r.getRPCStats(span.Start()) } -func (r *rpcs) getRPCStats(tagMap core.TagMap) *rpcStats { - method := tag.Method.Get(tagMap) +func (r *rpcs) getRPCStats(lm label.Map) *rpcStats { + method := tag.Method.Get(lm) if method == "" { return nil } set := &r.Inbound - if tag.RPCDirection.Get(tagMap) != tag.Inbound { + if tag.RPCDirection.Get(lm) != tag.Inbound { set = &r.Outbound } // get the record for this method diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go index 3cdc914ce0..85aeca6ed6 100644 --- a/internal/lsp/debug/serve.go +++ b/internal/lsp/debug/serve.go @@ -32,6 +32,7 @@ import ( "golang.org/x/tools/internal/event/export/metric" "golang.org/x/tools/internal/event/export/ocagent" "golang.org/x/tools/internal/event/export/prometheus" + "golang.org/x/tools/internal/event/label" "golang.org/x/tools/internal/lsp/debug/tag" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/span" @@ -543,7 +544,7 @@ func (i *Instance) writeMemoryDebug(threshold uint64) error { } func makeGlobalExporter(stderr io.Writer) event.Exporter { - return func(ctx context.Context, ev core.Event, tags core.TagMap) context.Context { + return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { i := GetInstance(ctx) if ev.IsLog() { @@ -556,27 +557,27 @@ func makeGlobalExporter(stderr io.Writer) event.Exporter { fmt.Fprintf(stderr, "%v\n", ev) } } - ctx = protocol.LogEvent(ctx, ev, tags) + ctx = protocol.LogEvent(ctx, ev, lm) if i == nil { return ctx } - return i.exporter(ctx, ev, tags) + return i.exporter(ctx, ev, lm) } } func makeInstanceExporter(i *Instance) event.Exporter { - exporter := func(ctx context.Context, ev core.Event, tags core.TagMap) context.Context { + exporter := func(ctx context.Context, ev core.Event, lm label.Map) context.Context { if i.ocagent != nil { - ctx = i.ocagent.ProcessEvent(ctx, ev, tags) + ctx = i.ocagent.ProcessEvent(ctx, ev, lm) } if i.prometheus != nil { - ctx = i.prometheus.ProcessEvent(ctx, ev, tags) + ctx = i.prometheus.ProcessEvent(ctx, ev, lm) } if i.rpcs != nil { - ctx = i.rpcs.ProcessEvent(ctx, ev, tags) + ctx = i.rpcs.ProcessEvent(ctx, ev, lm) } if i.traces != nil { - ctx = i.traces.ProcessEvent(ctx, ev, tags) + ctx = i.traces.ProcessEvent(ctx, ev, lm) } return ctx } diff --git a/internal/lsp/debug/tag/tag.go b/internal/lsp/debug/tag/tag.go index 4250a1c7b1..43883c5893 100644 --- a/internal/lsp/debug/tag/tag.go +++ b/internal/lsp/debug/tag/tag.go @@ -10,7 +10,7 @@ import ( ) var ( - // create the tag keys we use + // create the label keys we use Method = core.NewStringKey("method", "") StatusCode = core.NewStringKey("status.code", "") StatusMessage = core.NewStringKey("status.message", "") diff --git a/internal/lsp/debug/trace.go b/internal/lsp/debug/trace.go index 2ad2cda7df..8213df758d 100644 --- a/internal/lsp/debug/trace.go +++ b/internal/lsp/debug/trace.go @@ -17,6 +17,7 @@ import ( "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export" + "golang.org/x/tools/internal/event/label" ) var traceTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(` @@ -73,7 +74,7 @@ type traceEvent struct { Tags string } -func (t *traces) ProcessEvent(ctx context.Context, ev core.Event, tags core.TagMap) context.Context { +func (t *traces) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context { t.mu.Lock() defer t.mu.Unlock() span := export.GetSpan(ctx) @@ -94,7 +95,7 @@ func (t *traces) ProcessEvent(ctx context.Context, ev core.Event, tags core.TagM ParentID: span.ParentID, Name: span.Name, Start: span.Start().At, - Tags: renderTags(span.Start()), + Tags: renderLabels(span.Start()), } t.unfinished[span.ID] = td // and wire up parents if we have them @@ -124,7 +125,7 @@ func (t *traces) ProcessEvent(ctx context.Context, ev core.Event, tags core.TagM for i, event := range events { td.Events[i] = traceEvent{ Time: event.At, - Tags: renderTags(event), + Tags: renderLabels(event), } } @@ -170,11 +171,11 @@ func fillOffsets(td *traceData, start time.Time) { } } -func renderTags(tags core.TagList) string { +func renderLabels(labels label.List) string { buf := &bytes.Buffer{} - for index := 0; tags.Valid(index); index++ { - if tag := tags.Tag(index); tag.Valid() { - fmt.Fprintf(buf, "%v ", tag) + for index := 0; labels.Valid(index); index++ { + if l := labels.Label(index); l.Valid() { + fmt.Fprintf(buf, "%v ", l) } } return buf.String() diff --git a/internal/lsp/protocol/context.go b/internal/lsp/protocol/context.go index d526e2cf02..00b8fd81e2 100644 --- a/internal/lsp/protocol/context.go +++ b/internal/lsp/protocol/context.go @@ -5,6 +5,7 @@ import ( "fmt" "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/label" "golang.org/x/tools/internal/xcontext" ) @@ -18,7 +19,7 @@ func WithClient(ctx context.Context, client Client) context.Context { return context.WithValue(ctx, clientKey, client) } -func LogEvent(ctx context.Context, ev core.Event, tags core.TagMap) context.Context { +func LogEvent(ctx context.Context, ev core.Event, tags label.Map) context.Context { if !ev.IsLog() { return ctx } diff --git a/internal/lsp/source/types_format.go b/internal/lsp/source/types_format.go index a536ffd9fd..51c6b9f30c 100644 --- a/internal/lsp/source/types_format.go +++ b/internal/lsp/source/types_format.go @@ -14,9 +14,9 @@ import ( "go/types" "strings" + "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/lsp/debug/tag" "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/telemetry/event" ) // formatType returns the detail and kind for a types.Type.