event: move the special values back to direct embedding in the event

Change-Id: I93ebd8f0749fb483a9e56051cc2b7f2a7da7d4bc
Reviewed-on: https://go-review.googlesource.com/c/exp/+/327754
Trust: Ian Cottrell <iancottrell@google.com>
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/event/adapter/gokit/gokit_test.go b/event/adapter/gokit/gokit_test.go
index d2b5390..f8d6cad 100644
--- a/event/adapter/gokit/gokit_test.go
+++ b/event/adapter/gokit/gokit_test.go
@@ -21,13 +21,14 @@
 	ctx, h := eventtest.NewCapture()
 	log.Log(ctx, "msg", "mess", "level", 1, "name", "n/m", "traceID", 17, "resource", "R")
 	want := []event.Event{{
-		At: eventtest.InitialTime,
+		At:      eventtest.InitialTime,
+		Kind:    event.LogKind,
+		Message: "mess",
 		Labels: []event.Label{
 			keys.Value("level").Of(1),
 			keys.Value("name").Of("n/m"),
 			keys.Value("traceID").Of(17),
 			keys.Value("resource").Of("R"),
-			event.Message.Of("mess"),
 		},
 	}}
 	if diff := cmp.Diff(want, h.Got); diff != "" {
diff --git a/event/adapter/logfmt/logfmt.go b/event/adapter/logfmt/logfmt.go
index 83102e4..e12b580 100644
--- a/event/adapter/logfmt/logfmt.go
+++ b/event/adapter/logfmt/logfmt.go
@@ -73,6 +73,23 @@
 		}
 		p.Label(w, l)
 	}
+
+	if ev.TraceID != 0 {
+		p.label(w, "trace", event.Uint64Of(ev.TraceID))
+	}
+
+	if ev.Message != "" {
+		p.label(w, "msg", event.StringOf(ev.Message))
+	}
+
+	if ev.Name != "" {
+		p.label(w, "name", event.StringOf(ev.Name))
+	}
+
+	if ev.Kind == event.TraceKind && ev.TraceID == 0 {
+		p.label(w, "end", event.Value{})
+	}
+
 	io.WriteString(w, "\n")
 }
 
diff --git a/event/adapter/logr/logr.go b/event/adapter/logr/logr.go
index 115a4a3..2dfb62a 100644
--- a/event/adapter/logr/logr.go
+++ b/event/adapter/logr/logr.go
@@ -89,12 +89,12 @@
 // while the err field should be used to attach the actual error that
 // triggered this log line, if present.
 func (l *logger) Error(err error, msg string, keysAndValues ...interface{}) {
-	l.log(msg, l.builder.Clone().With(event.Error.Of(err)), keysAndValues)
+	l.log(msg, l.builder.Clone().Error(err), keysAndValues)
 }
 
 func (l *logger) log(msg string, b event.Builder, keysAndValues []interface{}) {
 	b.With(convertVerbosity(l.verbosity))
-	b.With(event.Name.Of(l.name))
+	b.Name(l.name)
 	addLabels(b, keysAndValues)
 	b.Log(msg)
 }
diff --git a/event/adapter/logr/logr_test.go b/event/adapter/logr/logr_test.go
index c35fe9a..8b897e4 100644
--- a/event/adapter/logr/logr_test.go
+++ b/event/adapter/logr/logr_test.go
@@ -23,13 +23,14 @@
 	log = log.WithName("m")
 	log.Info("mess", "traceID", 17, "resource", "R")
 	want := []event.Event{{
-		At: eventtest.InitialTime,
+		At:      eventtest.InitialTime,
+		Kind:    event.LogKind,
+		Message: "mess",
+		Name:    "n/m",
 		Labels: []event.Label{
 			severity.Debug,
-			event.Name.Of("n/m"),
 			keys.Value("traceID").Of(17),
 			keys.Value("resource").Of("R"),
-			event.Message.Of("mess"),
 		},
 	}}
 	if diff := cmp.Diff(want, th.Got); diff != "" {
diff --git a/event/adapter/logrus/logrus_test.go b/event/adapter/logrus/logrus_test.go
index b2249af..babc686 100644
--- a/event/adapter/logrus/logrus_test.go
+++ b/event/adapter/logrus/logrus_test.go
@@ -29,11 +29,12 @@
 	log.WithContext(ctx).WithField("traceID", 17).WithField("resource", "R").Info("mess")
 
 	want := []event.Event{{
+		Kind:    event.LogKind,
+		Message: "mess",
 		Labels: []event.Label{
 			severity.Info,
 			keys.Value("traceID").Of(17),
 			keys.Value("resource").Of("R"),
-			event.Message.Of("mess"),
 		},
 	}}
 	// logrus fields are stored in a map, so we have to sort to overcome map
diff --git a/event/adapter/zap/zap.go b/event/adapter/zap/zap.go
index de8d603..22304dd 100644
--- a/event/adapter/zap/zap.go
+++ b/event/adapter/zap/zap.go
@@ -53,7 +53,7 @@
 	b := c.builder.Clone().
 		At(e.Time).
 		With(convertLevel(e.Level)).
-		With(event.Name.Of(e.LoggerName))
+		Name(e.LoggerName)
 	// TODO: add these additional labels more efficiently.
 	if e.Stack != "" {
 		b.With(keys.String("stack").Of(e.Stack))
diff --git a/event/adapter/zap/zap_test.go b/event/adapter/zap/zap_test.go
index c504434..4ae028a 100644
--- a/event/adapter/zap/zap_test.go
+++ b/event/adapter/zap/zap_test.go
@@ -25,13 +25,14 @@
 	log = log.Named("n/m")
 	log.Info("mess", zap.Float64("pi", 3.14))
 	want := []event.Event{{
+		Kind:    event.LogKind,
+		Message: "mess",
+		Name:    "n/m",
 		Labels: []event.Label{
 			keys.Int64("traceID").Of(17),
 			keys.String("resource").Of("R"),
 			severity.Info,
-			event.Name.Of("n/m"),
 			keys.Float64("pi").Of(3.14),
-			event.Message.Of("mess"),
 		},
 	}}
 	if diff := cmp.Diff(want, h.Got, cmpopts.IgnoreFields(event.Event{}, "At")); diff != "" {
diff --git a/event/builder.go b/event/builder.go
index a0567e3..0c39d20 100644
--- a/event/builder.go
+++ b/event/builder.go
@@ -103,6 +103,20 @@
 	return b
 }
 
+func (b Builder) Name(name string) Builder {
+	if b.data != nil {
+		b.data.Event.Name = name
+	}
+	return b
+}
+
+func (b Builder) Error(err error) Builder {
+	if b.data != nil {
+		b.data.Event.Error = err
+	}
+	return b
+}
+
 func (b builderCommon) addLabel(label Label) {
 	if b.data != nil {
 		b.data.Event.Labels = append(b.data.Event.Labels, label)
@@ -161,7 +175,8 @@
 	if b.data.exporter.loggingEnabled() {
 		b.data.exporter.mu.Lock()
 		defer b.data.exporter.mu.Unlock()
-		b.data.Event.Labels = append(b.data.Event.Labels, Message.Of(message))
+		b.data.Event.Kind = LogKind
+		b.data.Event.Message = message
 		b.data.exporter.prepare(&b.data.Event)
 		b.data.exporter.handler.Log(b.ctx, &b.data.Event)
 	}
@@ -180,7 +195,8 @@
 		// Duplicate code from Log so Exporter.deliver's invocation of runtime.Callers is correct.
 		b.data.exporter.mu.Lock()
 		defer b.data.exporter.mu.Unlock()
-		b.data.Event.Labels = append(b.data.Event.Labels, Message.Of(message))
+		b.data.Event.Kind = LogKind
+		b.data.Event.Message = message
 		b.data.exporter.prepare(&b.data.Event)
 		b.data.exporter.handler.Log(b.ctx, &b.data.Event)
 	}
@@ -199,6 +215,7 @@
 			b.data.Event.Namespace = mv.m.Descriptor().Namespace()
 		}
 		b.data.Event.Labels = append(b.data.Event.Labels, MetricVal.Of(mv.v), MetricKey.Of(mv.m))
+		b.data.Event.Kind = MetricKind
 		b.data.exporter.prepare(&b.data.Event)
 		b.data.exporter.handler.Metric(b.ctx, &b.data.Event)
 	}
@@ -235,7 +252,7 @@
 		}
 		b.data.exporter.mu.Lock()
 		defer b.data.exporter.mu.Unlock()
-		b.data.Event.Labels = append(b.data.Event.Labels, End.Value())
+		b.data.Event.Kind = TraceKind
 		b.data.exporter.prepare(&b.data.Event)
 		b.data.exporter.handler.End(b.ctx, &b.data.Event)
 	}
@@ -279,10 +296,11 @@
 		// create the end builder
 		endBuilder = b.Clone()
 		endBuilder.data.Event.Parent = traceID
-		b.data.Event.Labels = append(b.data.Event.Labels, Trace.Of(traceID))
+		b.data.Event.Kind = TraceKind
+		b.data.Event.TraceID = traceID
 		b.data.exporter.prepare(&b.data.Event)
 		// and now deliver the start event
-		b.data.Event.Labels = append(b.data.Event.Labels, Name.Of(name))
+		b.data.Event.Name = name
 		now := time.Now()
 		ctx = newContext(ctx, b.data.exporter, traceID, now)
 		ctx = b.data.exporter.handler.Start(ctx, &b.data.Event)
diff --git a/event/builder_test.go b/event/builder_test.go
index c7d698f..c467adb 100644
--- a/event/builder_test.go
+++ b/event/builder_test.go
@@ -180,13 +180,13 @@
 			}
 			b.Run("direct", func(b *testing.B) {
 				for i := 0; i < b.N; i++ {
-					event.To(ctx).With(event.Name.Of("foo")).Metric(c.Record(1))
+					event.To(ctx).Name("foo").Metric(c.Record(1))
 				}
 			})
 			b.Run("cloned", func(b *testing.B) {
 				bu := event.To(ctx)
 				for i := 0; i < b.N; i++ {
-					bu.Clone().With(event.Name.Of("foo")).Metric(c.Record(1))
+					bu.Clone().Name("foo").Metric(c.Record(1))
 				}
 			})
 		})
diff --git a/event/common.go b/event/common.go
index b7be86c..4eb9ea0 100644
--- a/event/common.go
+++ b/event/common.go
@@ -5,71 +5,26 @@
 package event
 
 const (
-	Message        = stringKey("msg")
-	Name           = stringKey("name")
-	Trace          = traceKey("trace")
-	End            = tagKey("end")
 	MetricKey      = interfaceKey("metric")
 	MetricVal      = valueKey("metricValue")
 	DurationMetric = interfaceKey("durationMetric")
-	Error          = errorKey("error")
+)
+
+type Kind int
+
+const (
+	unknownKind = Kind(iota)
+
+	LogKind
+	MetricKind
+	TraceKind
 )
 
 type (
-	stringKey    string
-	traceKey     string
-	tagKey       string
 	valueKey     string
 	interfaceKey string
-	errorKey     string
 )
 
-// Of creates a new message Label.
-func (k stringKey) Of(msg string) Label {
-	return Label{Name: string(k), Value: StringOf(msg)}
-}
-
-func (k stringKey) Matches(ev *Event) bool {
-	_, found := k.Find(ev)
-	return found
-}
-
-func (k stringKey) Find(ev *Event) (string, bool) {
-	for i := len(ev.Labels) - 1; i >= 0; i-- {
-		if ev.Labels[i].Name == string(k) {
-			return ev.Labels[i].Value.String(), true
-		}
-	}
-	return "", false
-}
-
-// Of creates a new start Label.
-func (k traceKey) Of(id uint64) Label {
-	return Label{Name: string(k), Value: Uint64Of(id)}
-}
-
-func (k traceKey) Matches(ev *Event) bool {
-	_, found := k.Find(ev)
-	return found
-}
-
-func (k traceKey) Find(ev *Event) (uint64, bool) {
-	if v, ok := lookupValue(string(k), ev.Labels); ok {
-		return v.Uint64(), true
-	}
-	return 0, false
-}
-
-// Value creates a new tag Label.
-func (k tagKey) Value() Label {
-	return Label{Name: string(k)}
-}
-
-func (k tagKey) Matches(ev *Event) bool {
-	_, ok := lookupValue(string(k), ev.Labels)
-	return ok
-}
-
 func (k valueKey) Of(v Value) Label {
 	return Label{Name: string(k), Value: v}
 }
@@ -109,22 +64,3 @@
 	}
 	return Value{}, false
 }
-
-// Of creates a new error Label.
-func (k errorKey) Of(err error) Label {
-	return Label{Name: string(k), Value: ValueOf(err)}
-}
-
-func (k errorKey) Matches(ev *Event) bool {
-	_, found := k.Find(ev)
-	return found
-}
-
-func (k errorKey) Find(ev *Event) (error, bool) {
-	for i := len(ev.Labels) - 1; i >= 0; i-- {
-		if ev.Labels[i].Name == string(k) {
-			return ev.Labels[i].Value.Interface().(error), true
-		}
-	}
-	return nil, false
-}
diff --git a/event/common_test.go b/event/common_test.go
index b561ae3..d104024 100644
--- a/event/common_test.go
+++ b/event/common_test.go
@@ -21,47 +21,50 @@
 	const trace = "a trace"
 
 	event.To(ctx).Log(simple)
-	checkFind(t, h, "Log", event.Message, true, simple)
-	checkFind(t, h, "Log", event.Name, false, "")
+	checkMessage(t, h, "Log", simple)
+	checkName(t, h, "Log", "")
 	h.Reset()
 
 	event.To(ctx).Metric(m.Record(3))
-	checkFind(t, h, "Metric", event.Message, false, "")
-	checkFind(t, h, "Metric", event.Name, false, "")
+	checkMessage(t, h, "Metric", "")
+	checkName(t, h, "Metric", "")
 	h.Reset()
 
 	event.To(ctx).Annotate()
-	checkFind(t, h, "Annotate", event.Message, false, "")
-	checkFind(t, h, "Annotate", event.Name, false, "")
+	checkMessage(t, h, "Annotate", "")
+	checkName(t, h, "Annotate", "")
 	h.Reset()
 
 	_, eb := event.To(ctx).Start(trace)
-	checkFind(t, h, "Start", event.Message, false, "")
-	checkFind(t, h, "Start", event.Name, true, trace)
+	checkMessage(t, h, "Start", "")
+	checkName(t, h, "Start", trace)
 	h.Reset()
 
 	eb.End()
-	checkFind(t, h, "End", event.Message, false, "")
-	checkFind(t, h, "End", event.Name, false, "")
+	checkMessage(t, h, "End", "")
+	checkName(t, h, "End", "")
 }
 
 type finder interface {
 	Find(*event.Event) (string, bool)
 }
 
-func checkFind(t *testing.T, h *eventtest.CaptureHandler, method string, key finder, match bool, text string) {
+func checkMessage(t *testing.T, h *eventtest.CaptureHandler, method string, text string) {
 	if len(h.Got) != 1 {
 		t.Errorf("Got %d events, expected 1", len(h.Got))
 		return
 	}
-	m, ok := key.Find(&h.Got[0])
-	if ok && !match {
-		t.Errorf("%s produced an event with a %v", method, key)
+	if h.Got[0].Message != text {
+		t.Errorf("Expected event with Message %q from %s got %q", text, method, h.Got[0].Message)
 	}
-	if !ok && match {
-		t.Errorf("%s did not produce an event with a %v", method, key)
+}
+
+func checkName(t *testing.T, h *eventtest.CaptureHandler, method string, text string) {
+	if len(h.Got) != 1 {
+		t.Errorf("Got %d events, expected 1", len(h.Got))
+		return
 	}
-	if m != text {
-		t.Errorf("Expected event with %v %q from %s got %q", key, text, method, m)
+	if h.Got[0].Name != text {
+		t.Errorf("Expected event with Name %q from %s got %q", text, method, h.Got[0].Name)
 	}
 }
diff --git a/event/event.go b/event/event.go
index 18a737d..369bcc5 100644
--- a/event/event.go
+++ b/event/event.go
@@ -12,9 +12,14 @@
 // Event holds the information about an event that occurred.
 // It combines the event metadata with the user supplied labels.
 type Event struct {
+	TraceID   uint64
 	Parent    uint64    // id of the parent event for this event
 	Namespace string    // namespace of event; if empty, set by exporter to import path
 	At        time.Time // time at which the event is delivered to the exporter.
+	Kind      Kind
+	Message   string
+	Name      string
+	Error     error
 	Labels    []Label
 }
 
diff --git a/event/otel/trace.go b/event/otel/trace.go
index 8942841..14f8533 100644
--- a/event/otel/trace.go
+++ b/event/otel/trace.go
@@ -26,8 +26,7 @@
 func (t *TraceHandler) Metric(ctx context.Context, ev *event.Event)   {}
 func (t *TraceHandler) Start(ctx context.Context, ev *event.Event) context.Context {
 	opts := labelsToSpanOptions(ev.Labels)
-	name, _ := event.Name.Find(ev)
-	octx, span := t.tracer.Start(ctx, name, opts...)
+	octx, span := t.tracer.Start(ctx, ev.Name, opts...)
 	return context.WithValue(octx, spanKey{}, span)
 }