event: merge the handlers but not the methods
Change-Id: I7ff8c97f7d9b9111c2333fc8241d37105416b4b3
Reviewed-on: https://go-review.googlesource.com/c/exp/+/324650
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/eventtest/eventtest.go b/event/adapter/eventtest/eventtest.go
index 915160a..4ed96fc 100644
--- a/event/adapter/eventtest/eventtest.go
+++ b/event/adapter/eventtest/eventtest.go
@@ -31,30 +31,30 @@
}
func (h *testHandler) Log(ctx context.Context, ev *event.Event) {
- h.event(ctx, "log", ev)
+ h.event(ctx, ev)
}
func (h *testHandler) Metric(ctx context.Context, ev *event.Event) {
- h.event(ctx, "metric", ev)
+ h.event(ctx, ev)
}
func (h *testHandler) Annotate(ctx context.Context, ev *event.Event) {
- h.event(ctx, "annotate", ev)
+ h.event(ctx, ev)
}
func (h *testHandler) Start(ctx context.Context, ev *event.Event) context.Context {
- h.event(ctx, "start", ev)
+ h.event(ctx, ev)
return ctx
}
func (h *testHandler) End(ctx context.Context, ev *event.Event) {
- h.event(ctx, "end", ev)
+ h.event(ctx, ev)
}
-func (h *testHandler) event(ctx context.Context, kind string, ev *event.Event) {
+func (h *testHandler) event(ctx context.Context, ev *event.Event) {
//TODO: choose between stdout and stderr based on the event
//TODO: decide if we should be calling h.tb.Fail()
- h.printer.Event(os.Stdout, kind, ev)
+ h.printer.Event(os.Stdout, ev)
}
// FixedNow updates the exporter in the context to use a time function returned
diff --git a/event/adapter/logfmt/logfmt.go b/event/adapter/logfmt/logfmt.go
index a663c40..71aaa49 100644
--- a/event/adapter/logfmt/logfmt.go
+++ b/event/adapter/logfmt/logfmt.go
@@ -33,44 +33,37 @@
}
func (h *Handler) Log(ctx context.Context, ev *event.Event) {
- h.printer.Event(h.to, "log", ev)
+ h.printer.Event(h.to, ev)
}
func (h *Handler) Metric(ctx context.Context, ev *event.Event) {
- h.printer.Event(h.to, "metric", ev)
+ h.printer.Event(h.to, ev)
}
func (h *Handler) Annotate(ctx context.Context, ev *event.Event) {
- h.printer.Event(h.to, "annotate", ev)
+ h.printer.Event(h.to, ev)
}
func (h *Handler) Start(ctx context.Context, ev *event.Event) context.Context {
- h.printer.Event(h.to, "start", ev)
+ h.printer.Event(h.to, ev)
return ctx
}
func (h *Handler) End(ctx context.Context, ev *event.Event) {
- h.printer.Event(h.to, "end", ev)
+ h.printer.Event(h.to, ev)
}
-func (p *Printer) Event(w io.Writer, kind string, ev *event.Event) {
+func (p *Printer) Event(w io.Writer, ev *event.Event) {
const timeFormat = "2006-01-02T15:04:05"
p.needSep = false
if !ev.At.IsZero() {
p.label(w, "time", event.BytesOf(ev.At.AppendFormat(p.buf[:0], timeFormat)))
}
- if ev.ID != 0 {
- p.label(w, "trace", event.BytesOf(strconv.AppendUint(p.buf[:0], ev.ID, 10)))
- }
if ev.Parent != 0 {
p.label(w, "parent", event.BytesOf(strconv.AppendUint(p.buf[:0], ev.Parent, 10)))
}
- if kind != "log" && kind != "start" {
- p.label(w, "kind", event.StringOf(kind))
- }
-
for _, l := range ev.Labels {
if l.Name == "" {
continue
diff --git a/event/bench/event_test.go b/event/bench/event_test.go
index 9b733d7..4f34b07 100644
--- a/event/bench/event_test.go
+++ b/event/bench/event_test.go
@@ -126,7 +126,7 @@
type noopHandler struct{}
-func (noopHandler) Log_(ctx context.Context, ev *event.Event) {}
+func (noopHandler) Log(ctx context.Context, ev *event.Event) {}
func (noopHandler) Metric(ctx context.Context, ev *event.Event) {}
func (noopHandler) Annotate(ctx context.Context, ev *event.Event) {}
func (noopHandler) End(ctx context.Context, ev *event.Event) {}
diff --git a/event/builder.go b/event/builder.go
index d5037e3..cdceb06 100644
--- a/event/builder.go
+++ b/event/builder.go
@@ -101,7 +101,7 @@
if b.data == nil {
return
}
- if b.data.exporter.log != nil {
+ if b.data.exporter.handler != nil {
b.log(message)
}
b.done()
@@ -113,7 +113,7 @@
if b.data == nil {
return
}
- if b.data.exporter.log != nil {
+ if b.data.exporter.loggingEnabled() {
b.log(fmt.Sprintf(template, args...))
}
b.done()
@@ -124,7 +124,7 @@
defer b.data.exporter.mu.Unlock()
b.data.Event.Labels = append(b.data.Event.Labels, Message.Of(message))
b.data.exporter.prepare(&b.data.Event)
- b.data.exporter.log.Log(b.ctx, &b.data.Event)
+ b.data.exporter.handler.Log(b.ctx, &b.data.Event)
}
// Metric is a helper that calls Deliver with MetricKind.
@@ -132,11 +132,12 @@
if b.data == nil {
return
}
- if b.data.exporter.metric != nil {
+ if b.data.exporter.metricsEnabled() {
b.data.exporter.mu.Lock()
defer b.data.exporter.mu.Unlock()
+ b.data.Event.Labels = append(b.data.Event.Labels, Metric.Value())
b.data.exporter.prepare(&b.data.Event)
- b.data.exporter.metric.Metric(b.ctx, &b.data.Event)
+ b.data.exporter.handler.Metric(b.ctx, &b.data.Event)
}
b.done()
}
@@ -146,11 +147,11 @@
if b.data == nil {
return
}
- if b.data.exporter.annotate != nil {
+ if b.data.exporter.annotationsEnabled() {
b.data.exporter.mu.Lock()
defer b.data.exporter.mu.Unlock()
b.data.exporter.prepare(&b.data.Event)
- b.data.exporter.annotate.Annotate(b.ctx, &b.data.Event)
+ b.data.exporter.handler.Annotate(b.ctx, &b.data.Event)
}
b.done()
}
@@ -160,11 +161,12 @@
if b.data == nil {
return
}
- if b.data.exporter.trace != nil {
+ if b.data.exporter.tracingEnabled() {
b.data.exporter.mu.Lock()
defer b.data.exporter.mu.Unlock()
+ b.data.Event.Labels = append(b.data.Event.Labels, End.Value())
b.data.exporter.prepare(&b.data.Event)
- b.data.exporter.trace.End(b.ctx, &b.data.Event)
+ b.data.exporter.handler.End(b.ctx, &b.data.Event)
}
b.done()
}
@@ -195,21 +197,22 @@
}
ctx := b.ctx
end := func() {}
- if b.data.exporter.trace != nil {
+ if b.data.exporter.tracingEnabled() {
b.data.exporter.mu.Lock()
defer b.data.exporter.mu.Unlock()
b.data.exporter.lastEvent++
- b.data.Event.ID = b.data.exporter.lastEvent
+ traceID := b.data.exporter.lastEvent
+ b.data.Event.Labels = append(b.data.Event.Labels, Trace.Of(traceID))
b.data.exporter.prepare(&b.data.Event)
// create the end builder
eb := Builder{}
eb.data = builderPool.Get().(*builder)
eb.data.exporter = b.data.exporter
- eb.data.Event.Parent = b.data.Event.ID
+ eb.data.Event.Parent = traceID
// and now deliver the start event
- b.data.Event.Labels = append(b.data.Event.Labels, Trace.Of(name))
- ctx = newContext(ctx, b.data.exporter, b.data.Event.ID)
- ctx = b.data.exporter.trace.Start(ctx, &b.data.Event)
+ b.data.Event.Labels = append(b.data.Event.Labels, Name.Of(name))
+ ctx = newContext(ctx, b.data.exporter, traceID)
+ ctx = b.data.exporter.handler.Start(ctx, &b.data.Event)
eb.ctx = ctx
end = eb.End
}
diff --git a/event/builder_test.go b/event/builder_test.go
index a9b23e4..65d429a 100644
--- a/event/builder_test.go
+++ b/event/builder_test.go
@@ -78,6 +78,10 @@
t *testing.T
}
+func (*testTraceHandler) Log(ctx context.Context, _ *event.Event) {}
+func (*testTraceHandler) Annotate(ctx context.Context, _ *event.Event) {}
+func (*testTraceHandler) Metric(ctx context.Context, _ *event.Event) {}
+
func (*testTraceHandler) Start(ctx context.Context, _ *event.Event) context.Context {
return context.WithValue(ctx, "x", 1)
}
diff --git a/event/common.go b/event/common.go
index 08c95a7..e3fbe16 100644
--- a/event/common.go
+++ b/event/common.go
@@ -5,15 +5,25 @@
package event
const Message = stringKey("msg")
-const Trace = stringKey("name")
+const Name = stringKey("name")
+const Trace = traceKey("trace")
+const End = tagKey("end")
+const Metric = tagKey("metric")
type stringKey string
+type traceKey string
+type tagKey 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) {
@@ -22,3 +32,36 @@
}
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) {
+ for i := len(ev.Labels) - 1; i >= 0; i-- {
+ if ev.Labels[i].Name == string(k) {
+ return ev.Labels[i].Value.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 {
+ for i := len(ev.Labels) - 1; i >= 0; i-- {
+ if ev.Labels[i].Name == string(k) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/event/common_test.go b/event/common_test.go
index 892287b..b86f9aa 100644
--- a/event/common_test.go
+++ b/event/common_test.go
@@ -22,23 +22,23 @@
event.To(ctx).Log(simple)
checkFind(t, h, "Log", event.Message, true, simple)
- checkFind(t, h, "Log", event.Trace, false, "")
+ checkFind(t, h, "Log", event.Name, false, "")
event.To(ctx).Metric()
checkFind(t, h, "Metric", event.Message, false, "")
- checkFind(t, h, "Metric", event.Trace, false, "")
+ checkFind(t, h, "Metric", event.Name, false, "")
event.To(ctx).Annotate()
checkFind(t, h, "Annotate", event.Message, false, "")
- checkFind(t, h, "Annotate", event.Trace, false, "")
+ checkFind(t, h, "Annotate", event.Name, false, "")
_, end := event.To(ctx).Start(trace)
checkFind(t, h, "Start", event.Message, false, "")
- checkFind(t, h, "Start", event.Trace, true, trace)
+ checkFind(t, h, "Start", event.Name, true, trace)
end()
checkFind(t, h, "End", event.Message, false, "")
- checkFind(t, h, "End", event.Trace, false, "")
+ checkFind(t, h, "End", event.Name, false, "")
}
type finder interface {
diff --git a/event/event.go b/event/event.go
index 5e29773..a055ef8 100644
--- a/event/event.go
+++ b/event/event.go
@@ -12,41 +12,31 @@
// Event holds the information about an event that occurred.
// It combines the event metadata with the user supplied labels.
type Event struct {
- ID uint64 // only set for trace events, a unique id per exporter for the trace.
Parent uint64 // id of the parent event for this event
At time.Time // time at which the event is delivered to the exporter.
Labels []Label
}
-// LogHandler is a the type for something that handles log events as they occur.
-type LogHandler interface {
+// Handler is a the type for something that handles events as they occur.
+type Handler interface {
// Log indicates a logging event.
Log(context.Context, *Event)
-}
-
-// MetricHandler is a the type for something that handles metric events as they
-// occur.
-type MetricHandler interface {
// Metric indicates a metric record event.
Metric(context.Context, *Event)
-}
-
-// AnnotateHandler is a the type for something that handles annotate events as
-// they occur.
-type AnnotateHandler interface {
// Annotate reports label values at a point in time.
Annotate(context.Context, *Event)
-}
-
-// TraceHandler is a the type for something that handles start and end events as
-// they occur.
-type TraceHandler interface {
// Start indicates a trace start event.
Start(context.Context, *Event) context.Context
// End indicates a trace end event.
End(context.Context, *Event)
}
+// Matcher is the interface to something that can check if an event matches
+// a condition.
+type Matcher interface {
+ Matches(ev *Event) bool
+}
+
// WithExporter returns a context with the exporter attached.
// The exporter is called synchronously from the event call site, so it should
// return quickly so as not to hold up user code.
@@ -59,3 +49,12 @@
func SetDefaultExporter(e *Exporter) {
setDefaultExporter(e)
}
+
+// Is uses the matcher to check if the event is a match.
+// This is a simple helper to convert code like
+// event.End.Matches(ev)
+// to the more readable
+// ev.Is(event.End)
+func (ev *Event) Is(m Matcher) bool {
+ return m.Matches(ev)
+}
diff --git a/event/event_test.go b/event/event_test.go
index b62957c..3f64305 100644
--- a/event/event_test.go
+++ b/event/event_test.go
@@ -54,7 +54,7 @@
},
expect: `
time=2020-03-05T14:27:48 trace=1 name=span
-time=2020-03-05T14:27:49 parent=1 kind=end
+time=2020-03-05T14:27:49 parent=1 end
`}, {
name: "span nested",
events: func(ctx context.Context) {
@@ -66,26 +66,26 @@
},
expect: `
time=2020-03-05T14:27:48 trace=1 name=parent
-time=2020-03-05T14:27:49 trace=2 parent=1 name=child
+time=2020-03-05T14:27:49 parent=1 trace=2 name=child
time=2020-03-05T14:27:50 parent=2 msg=message
-time=2020-03-05T14:27:51 parent=2 kind=end
-time=2020-03-05T14:27:52 parent=1 kind=end
+time=2020-03-05T14:27:51 parent=2 end
+time=2020-03-05T14:27:52 parent=1 end
`}, {
name: "metric",
events: func(ctx context.Context) { event.To(ctx).With(l1).Metric() },
- expect: `time=2020-03-05T14:27:48 kind=metric l1=1`,
+ expect: `time=2020-03-05T14:27:48 l1=1 metric`,
}, {
name: "metric 2",
events: func(ctx context.Context) { event.To(ctx).With(l1).With(l2).Metric() },
- expect: `time=2020-03-05T14:27:48 kind=metric l1=1 l2=2`,
+ expect: `time=2020-03-05T14:27:48 l1=1 l2=2 metric`,
}, {
name: "annotate",
events: func(ctx context.Context) { event.To(ctx).With(l1).Annotate() },
- expect: `time=2020-03-05T14:27:48 kind=annotate l1=1`,
+ expect: `time=2020-03-05T14:27:48 l1=1`,
}, {
name: "annotate 2",
events: func(ctx context.Context) { event.To(ctx).With(l1).With(l2).Annotate() },
- expect: `time=2020-03-05T14:27:48 kind=annotate l1=1 l2=2`,
+ expect: `time=2020-03-05T14:27:48 l1=1 l2=2`,
}, {
name: "multiple events",
events: func(ctx context.Context) {
diff --git a/event/export.go b/event/export.go
index f9ef7e2..84c6521 100644
--- a/event/export.go
+++ b/event/export.go
@@ -19,10 +19,7 @@
Now func() time.Time
mu sync.Mutex
- log LogHandler
- metric MetricHandler
- annotate AnnotateHandler
- trace TraceHandler
+ handler Handler
lastEvent uint64
}
@@ -44,13 +41,8 @@
// NewExporter creates an Exporter using the supplied handler.
// Event delivery is serialized to enable safe atomic handling.
-func NewExporter(handler interface{}) *Exporter {
- e := &Exporter{Now: time.Now}
- e.log, _ = handler.(LogHandler)
- e.metric, _ = handler.(MetricHandler)
- e.annotate, _ = handler.(AnnotateHandler)
- e.trace, _ = handler.(TraceHandler)
- return e
+func NewExporter(handler Handler) *Exporter {
+ return &Exporter{Now: time.Now, handler: handler}
}
func setDefaultExporter(e *Exporter) {
@@ -83,3 +75,10 @@
ev.At = e.Now()
}
}
+
+//TODO: decide how to control the enable/disable behaviour
+
+func (e *Exporter) loggingEnabled() bool { return true }
+func (e *Exporter) annotationsEnabled() bool { return true }
+func (e *Exporter) tracingEnabled() bool { return true }
+func (e *Exporter) metricsEnabled() bool { return true }
diff --git a/event/logging/internal/internal.go b/event/logging/internal/internal.go
index e971215..c7b56aa 100644
--- a/event/logging/internal/internal.go
+++ b/event/logging/internal/internal.go
@@ -25,6 +25,11 @@
copy(h.Got.Labels, ev.Labels)
}
+func (h *TestHandler) Annotate(_ context.Context, _ *event.Event) {}
+func (h *TestHandler) Metric(_ context.Context, _ *event.Event) {}
+func (h *TestHandler) Start(ctx context.Context, _ *event.Event) context.Context { return ctx }
+func (h *TestHandler) End(_ context.Context, _ *event.Event) {}
+
var TestAt = time.Now()
func NewTestExporter() (*event.Exporter, *TestHandler) {
diff --git a/event/otel/trace.go b/event/otel/trace.go
index 2cc56a4..8942841 100644
--- a/event/otel/trace.go
+++ b/event/otel/trace.go
@@ -15,17 +15,18 @@
tracer trace.Tracer
}
-var _ event.TraceHandler = (*TraceHandler)(nil)
-
func NewTraceHandler(t trace.Tracer) *TraceHandler {
return &TraceHandler{tracer: t}
}
type spanKey struct{}
-func (t *TraceHandler) Start(ctx context.Context, e *event.Event) context.Context {
- opts := labelsToSpanOptions(e.Labels)
- name, _ := event.Trace.Find(e)
+func (t *TraceHandler) Log(ctx context.Context, ev *event.Event) {}
+func (t *TraceHandler) Annotate(ctx context.Context, ev *event.Event) {}
+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...)
return context.WithValue(octx, spanKey{}, span)
}