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 <iancottrell@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Ian Cottrell 2020-04-20 15:44:34 -04:00
parent 7b212d60a1
commit c81623a0cb
33 changed files with 755 additions and 725 deletions

View File

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

View File

@ -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,
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

@ -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")

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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{

View File

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

View File

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

View File

@ -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"}]

View File

@ -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"`

View File

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

View File

@ -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"`

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

@ -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", "")

View File

@ -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()

View File

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

View File

@ -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.