internal/telemetry: use tags instead of special event fields.
Change-Id: I0e6a26c62bd1f6eaa07c38a06152cb7a0f2eedc2
Reviewed-on: https://go-review.googlesource.com/c/tools/+/225579
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go
index a4cafbc..2004716 100644
--- a/internal/lsp/debug/serve.go
+++ b/internal/lsp/debug/serve.go
@@ -543,7 +543,7 @@
func makeGlobalExporter(stderr io.Writer) event.Exporter {
return func(ctx context.Context, ev event.Event, tags event.TagMap) context.Context {
i := GetInstance(ctx)
- if ev.IsLog() && (ev.Error != nil || i == nil) {
+ if ev.IsLog() && (event.Err.Get(ev.Map()) != nil || i == nil) {
fmt.Fprintf(stderr, "%v\n", ev)
}
ctx = protocol.LogEvent(ctx, ev, tags)
diff --git a/internal/lsp/protocol/context.go b/internal/lsp/protocol/context.go
index a1b8822..560de4d 100644
--- a/internal/lsp/protocol/context.go
+++ b/internal/lsp/protocol/context.go
@@ -27,7 +27,7 @@
return ctx
}
msg := &LogMessageParams{Type: Info, Message: fmt.Sprint(ev)}
- if ev.Error != nil {
+ if event.Err.Get(tags) != nil {
msg.Type = Error
}
go client.LogMessage(xcontext.Detach(ctx), msg)
diff --git a/internal/telemetry/event/event.go b/internal/telemetry/event/event.go
index 3f222c4..23329cb 100644
--- a/internal/telemetry/event/event.go
+++ b/internal/telemetry/event/event.go
@@ -13,21 +13,32 @@
type eventType uint8
const (
- LogType = eventType(iota)
- StartSpanType
- EndSpanType
- LabelType
- DetachType
- RecordType
+ invalidType = eventType(iota)
+ LogType // an event that should be recorded in a log
+ StartSpanType // the start of a span of time
+ EndSpanType // the end of a span of time
+ LabelType // some values that should be noted for later events
+ DetachType // an event that causes a context to detach
+ RecordType // a value that should be tracked
)
-type Event struct {
- typ eventType
- At time.Time
- Message string
- Error error
+// 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
- tags []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
}
func (ev Event) IsLog() bool { return ev.typ == LogType }
@@ -38,15 +49,18 @@
func (ev Event) IsRecord() bool { return ev.typ == RecordType }
func (ev Event) Format(f fmt.State, r rune) {
+ tagMap := ev.Map()
if !ev.At.IsZero() {
fmt.Fprint(f, ev.At.Format("2006/01/02 15:04:05 "))
}
- fmt.Fprint(f, ev.Message)
- if ev.Error != nil {
+ msg := Msg.Get(tagMap)
+ err := Err.Get(tagMap)
+ fmt.Fprint(f, msg)
+ if err != nil {
if f.Flag('+') {
- fmt.Fprintf(f, ": %+v", ev.Error)
+ fmt.Fprintf(f, ": %+v", err)
} else {
- fmt.Fprintf(f, ": %v", ev.Error)
+ fmt.Fprintf(f, ": %v", err)
}
}
for it := ev.Tags(); it.Valid(); it.Advance() {
@@ -56,12 +70,21 @@
}
func (ev Event) Tags() TagIterator {
- if len(ev.tags) == 0 {
- return TagIterator{}
- }
- return NewTagIterator(ev.tags...)
+ return ChainTagIterators(
+ NewTagIterator(ev.static[:]...),
+ NewTagIterator(ev.dynamic...))
}
func (ev Event) Map() TagMap {
- return NewTagMap(ev.tags...)
+ return MergeTagMaps(
+ NewTagMap(ev.static[:]...),
+ NewTagMap(ev.dynamic...))
+}
+
+func makeEvent(typ eventType, static sTags, tags []Tag) Event {
+ return Event{
+ typ: typ,
+ static: static,
+ dynamic: tags,
+ }
}
diff --git a/internal/telemetry/event/key.go b/internal/telemetry/event/key.go
index fddabcd..97572c3 100644
--- a/internal/telemetry/event/key.go
+++ b/internal/telemetry/event/key.go
@@ -4,11 +4,17 @@
package event
-import "math"
+import (
+ "math"
+)
var (
+ // Msg is a key used to add message strings to tag 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 = NewErrorKey("error", "")
+ Err = NewErrorKey("error", "an error that occurred")
)
// Key is the interface shared by all key implementations.
@@ -487,4 +493,7 @@
}
// From can be used to get a value from a Tag.
-func (k *ErrorKey) From(t Tag) error { return t.untyped.(error) }
+func (k *ErrorKey) From(t Tag) error {
+ err, _ := t.untyped.(error)
+ return err
+}
diff --git a/internal/telemetry/event/label.go b/internal/telemetry/event/label.go
index 9536ed2..ccdaba5 100644
--- a/internal/telemetry/event/label.go
+++ b/internal/telemetry/event/label.go
@@ -10,8 +10,5 @@
// Label sends a label event to the exporter with the supplied tags.
func Label(ctx context.Context, tags ...Tag) context.Context {
- return dispatch(ctx, Event{
- typ: LabelType,
- tags: tags,
- })
+ return dispatch(ctx, makeEvent(LabelType, sTags{}, tags))
}
diff --git a/internal/telemetry/event/log.go b/internal/telemetry/event/log.go
index 3367f9b..b989032 100644
--- a/internal/telemetry/event/log.go
+++ b/internal/telemetry/event/log.go
@@ -11,20 +11,13 @@
// Log sends a log event with the supplied tag list to the exporter.
func Log(ctx context.Context, tags ...Tag) {
- dispatch(ctx, Event{
- typ: LogType,
- tags: tags,
- })
+ dispatch(ctx, makeEvent(LogType, sTags{}, tags))
}
// Print takes a message and a tag list and combines them into a single event
// before delivering them to the exporter.
func Print(ctx context.Context, message string, tags ...Tag) {
- dispatch(ctx, Event{
- typ: LogType,
- Message: message,
- tags: tags,
- })
+ dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message)}, tags))
}
// Error takes a message and a tag list and combines them into a single event
@@ -35,10 +28,5 @@
err = errors.New(message)
message = ""
}
- dispatch(ctx, Event{
- typ: LogType,
- Message: message,
- Error: err,
- tags: tags,
- })
+ dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message), Err.Of(err)}, tags))
}
diff --git a/internal/telemetry/event/metric.go b/internal/telemetry/event/metric.go
index 48f030e..b00e870 100644
--- a/internal/telemetry/event/metric.go
+++ b/internal/telemetry/event/metric.go
@@ -9,8 +9,5 @@
)
func Record(ctx context.Context, tags ...Tag) {
- dispatch(ctx, Event{
- typ: RecordType,
- tags: tags,
- })
+ dispatch(ctx, makeEvent(RecordType, sTags{}, tags))
}
diff --git a/internal/telemetry/event/trace.go b/internal/telemetry/event/trace.go
index 85cdd53..0331aae 100644
--- a/internal/telemetry/event/trace.go
+++ b/internal/telemetry/event/trace.go
@@ -9,18 +9,12 @@
)
func StartSpan(ctx context.Context, name string, tags ...Tag) (context.Context, func()) {
- ctx = dispatch(ctx, Event{
- typ: StartSpanType,
- Message: name,
- tags: tags,
- })
- return ctx, func() {
- dispatch(ctx, Event{typ: EndSpanType})
- }
+ ctx = dispatch(ctx, makeEvent(StartSpanType, sTags{Name.Of(name)}, tags))
+ return ctx, func() { dispatch(ctx, makeEvent(EndSpanType, sTags{}, 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 dispatch(ctx, Event{typ: DetachType})
+ return dispatch(ctx, makeEvent(DetachType, sTags{}, nil))
}
diff --git a/internal/telemetry/export/log.go b/internal/telemetry/export/log.go
index 5d2bc96..2458022 100644
--- a/internal/telemetry/export/log.go
+++ b/internal/telemetry/export/log.go
@@ -29,7 +29,7 @@
func (w *logWriter) ProcessEvent(ctx context.Context, ev event.Event, tagMap event.TagMap) context.Context {
switch {
case ev.IsLog():
- if w.onlyErrors && ev.Error == nil {
+ if w.onlyErrors && event.Err.Get(tagMap) == nil {
return ctx
}
fmt.Fprintf(w.writer, "%v\n", ev)
diff --git a/internal/telemetry/export/ocagent/ocagent.go b/internal/telemetry/export/ocagent/ocagent.go
index 86c2e8b..4c423eb 100644
--- a/internal/telemetry/export/ocagent/ocagent.go
+++ b/internal/telemetry/export/ocagent/ocagent.go
@@ -200,7 +200,7 @@
Kind: wire.UnspecifiedSpanKind,
StartTime: convertTimestamp(span.Start.At),
EndTime: convertTimestamp(span.Finish.At),
- Attributes: convertAttributes(span.Start.Tags()),
+ Attributes: convertAttributes(event.Filter(span.Start.Tags(), event.Name)),
TimeEvents: convertEvents(span.Events),
SameProcessAsParentSpan: true,
//TODO: StackTrace?
@@ -295,19 +295,20 @@
}
func convertAnnotation(ev event.Event) *wire.Annotation {
- description := ev.Message
- if description == "" && ev.Error != nil {
- description = ev.Error.Error()
- ev.Error = nil
- }
tags := ev.Tags()
- if ev.Error != nil {
- extra := event.NewTagIterator(event.Err.Of(ev.Error))
- tags = event.ChainTagIterators(extra, tags)
- }
- if description == "" && !tags.Valid() {
+ if !tags.Valid() {
return nil
}
+ tagMap := ev.Map()
+ description := event.Msg.Get(tagMap)
+ tags = event.Filter(tags, event.Msg)
+ if description == "" {
+ err := event.Err.Get(tagMap)
+ tags = event.Filter(tags, event.Err)
+ if err != nil {
+ description = err.Error()
+ }
+ }
return &wire.Annotation{
Description: toTruncatableString(description),
Attributes: convertAttributes(tags),
diff --git a/internal/telemetry/export/trace.go b/internal/telemetry/export/trace.go
index 3894b85..ffe86ad 100644
--- a/internal/telemetry/export/trace.go
+++ b/internal/telemetry/export/trace.go
@@ -54,7 +54,7 @@
}
case ev.IsStartSpan():
span := &Span{
- Name: ev.Message,
+ Name: event.Name.Get(tagMap),
Start: ev,
}
if parent := GetSpan(ctx); parent != nil {