event: use Source instead of just namespace in event
Also add tests for the Source capture functionality.
Change-Id: I0ba8c3f31c2d30247c60b49baec74a65f5f50739
Reviewed-on: https://go-review.googlesource.com/c/exp/+/329795
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/logfmt/logfmt.go b/event/adapter/logfmt/logfmt.go
index 32eadbe..c3eca4f 100644
--- a/event/adapter/logfmt/logfmt.go
+++ b/event/adapter/logfmt/logfmt.go
@@ -54,8 +54,14 @@
io.WriteString(w, `"`)
}
- if !p.SuppressNamespace && ev.Namespace != "" {
- p.Label(w, event.String("in", ev.Namespace))
+ if !p.SuppressNamespace && ev.Source.Space != "" {
+ p.Label(w, event.String("in", ev.Source.Space))
+ }
+ if ev.Source.Owner != "" {
+ p.Label(w, event.String("owner", ev.Source.Owner))
+ }
+ if ev.Source.Name != "" {
+ p.Label(w, event.String("name", ev.Source.Name))
}
if ev.Parent != 0 {
@@ -70,10 +76,10 @@
p.Label(w, l)
}
- if ev.TraceID != 0 {
+ if ev.ID != 0 {
p.separator(w)
io.WriteString(w, `trace=`)
- w.Write(strconv.AppendUint(p.buf[:0], ev.TraceID, 10))
+ w.Write(strconv.AppendUint(p.buf[:0], ev.ID, 10))
}
if ev.Kind == event.EndKind {
diff --git a/event/adapter/logfmt/logfmt_test.go b/event/adapter/logfmt/logfmt_test.go
index 072caaa..0fdb62b 100644
--- a/event/adapter/logfmt/logfmt_test.go
+++ b/event/adapter/logfmt/logfmt_test.go
@@ -28,7 +28,7 @@
expect: ``,
}, {
name: "span",
- event: event.Event{TraceID: 34},
+ event: event.Event{ID: 34},
expect: `trace=34`,
}, {
name: "parent",
@@ -36,7 +36,7 @@
expect: `parent=14`,
}, {
name: "namespace",
- event: event.Event{Namespace: "golang.org/x/exp/event"},
+ event: event.Event{Source: event.Source{Space: "golang.org/x/exp/event"}},
expect: `in=golang.org/x/exp/event`,
}, {
name: "at",
@@ -174,8 +174,8 @@
name: "suppress namespace",
printer: logfmt.Printer{SuppressNamespace: true},
event: event.Event{
- Namespace: "golang.org/x/exp/event",
- Labels: []event.Label{event.String("msg", "some text")},
+ Source: event.Source{Space: "golang.org/x/exp/event"},
+ Labels: []event.Label{event.String("msg", "some text")},
},
before: `in=golang.org/x/exp/event msg="some text"`,
after: `msg="some text"`,
diff --git a/event/common.go b/event/common.go
index 529a79e..68c0008 100644
--- a/event/common.go
+++ b/event/common.go
@@ -62,9 +62,9 @@
if ev != nil {
ev.Labels = append(ev.Labels, String("name", name))
ev.Labels = append(ev.Labels, labels...)
- ev.TraceID = atomic.AddUint64(&ev.target.exporter.lastEvent, 1)
+ ev.ID = atomic.AddUint64(&ev.target.exporter.lastEvent, 1)
ev.target.exporter.prepare(ev)
- ev.ctx = newContext(ev.ctx, ev.target.exporter, ev.TraceID, ev.At)
+ ev.ctx = newContext(ev.ctx, ev.target.exporter, ev.ID, ev.At)
ctx = ev.Deliver()
}
return ctx
diff --git a/event/event.go b/event/event.go
index 485e706..bfba077 100644
--- a/event/event.go
+++ b/event/event.go
@@ -13,12 +13,12 @@
// 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
- Labels []Label
+ ID uint64
+ Parent uint64 // id of the parent event for this event
+ Source Source // source 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
+ Labels []Label
ctx context.Context
target *target
diff --git a/event/export.go b/event/export.go
index abfe673..9307c44 100644
--- a/event/export.go
+++ b/event/export.go
@@ -101,8 +101,8 @@
if e.opts.Now != nil && ev.At.IsZero() {
ev.At = e.opts.Now()
}
- if e.opts.EnableNamespaces && ev.Namespace == "" {
- ev.Namespace = e.sources.scanStack().Space
+ if e.opts.EnableNamespaces && ev.Source.Space == "" {
+ ev.Source = e.sources.scanStack()
}
}
diff --git a/event/namespace_test.go b/event/namespace_test.go
deleted file mode 100644
index abab523..0000000
--- a/event/namespace_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2021 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 event_test
-
-import (
- "context"
- "runtime"
- "testing"
-
- "golang.org/x/exp/event"
-)
-
-const thisImportPath = "golang.org/x/exp/event_test"
-
-func TestNamespace(t *testing.T) {
- var h nsHandler
- ctx := event.WithExporter(context.Background(), event.NewExporter(&h, &event.ExporterOptions{EnableNamespaces: true}))
- event.Log(ctx, "msg")
- if got, want := h.ns, thisImportPath; got != want {
- t.Errorf("got namespace %q, want, %q", got, want)
- }
-}
-
-type nsHandler struct {
- ns string
-}
-
-func (h *nsHandler) Event(ctx context.Context, ev *event.Event) context.Context {
- h.ns = ev.Namespace
- return ctx
-}
-
-func BenchmarkRuntimeCallers(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var pcs [1]uintptr
- _ = runtime.Callers(2, pcs[:])
- }
-}
-
-func BenchmarkCallersFrames(b *testing.B) {
- var pcs [1]uintptr
- n := runtime.Callers(2, pcs[:])
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- frames := runtime.CallersFrames(pcs[:n])
- frame, _ := frames.Next()
- _ = frame.Function //namespace(frame.Function)
- }
-}
-
-func TestStablePCs(t *testing.T) {
- // The pc is stable regardless of the call stack.
- pc1 := f()
- pc2 := g()
- if pc1 != pc2 {
- t.Fatal("pcs differ")
- }
- // We can recover frame information after the function has returned.
- frames := runtime.CallersFrames([]uintptr{pc1})
- frame, _ := frames.Next()
- want := thisImportPath + ".h"
- if got := frame.Function; got != want {
- t.Errorf("got %q, want %q", got, want)
- }
-}
-
-func f() uintptr {
- return h()
-}
-
-func g() uintptr {
- return h()
-}
-
-func h() uintptr {
- var pcs [1]uintptr
- runtime.Callers(1, pcs[:])
- return pcs[0]
-}
diff --git a/event/source.go b/event/source.go
index 183e336..efe3c5d 100644
--- a/event/source.go
+++ b/event/source.go
@@ -200,8 +200,8 @@
entry.Space = full[:slash+dot]
entry.Name = full[slash+dot+1:]
if dot = strings.LastIndexByte(entry.Name, '.'); dot >= 0 {
- entry.Owner = entry.Name[dot+1:]
- entry.Name = entry.Name[:dot]
+ entry.Owner = entry.Name[:dot]
+ entry.Name = entry.Name[dot+1:]
}
}
return entry
diff --git a/event/source_test.go b/event/source_test.go
new file mode 100644
index 0000000..603f23c
--- /dev/null
+++ b/event/source_test.go
@@ -0,0 +1,86 @@
+// Copyright 2021 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 event_test
+
+import (
+ "context"
+ "testing"
+
+ "golang.org/x/exp/event"
+ "golang.org/x/exp/event/eventtest"
+)
+
+const thisImportPath = "golang.org/x/exp/event_test"
+
+func TestNamespace(t *testing.T) {
+ event.RegisterHelper(testHelperB)
+ event.RegisterHelper(thisImportPath + ".testHelperC")
+ h := &eventtest.CaptureHandler{}
+ opt := eventtest.ExporterOptions()
+ opt.EnableNamespaces = true
+ ctx := event.WithExporter(context.Background(), event.NewExporter(h, opt))
+ for _, test := range []struct {
+ name string
+ do func(context.Context)
+ expect event.Source
+ }{{
+ name: "simple",
+ do: testA,
+ expect: event.Source{Space: thisImportPath, Name: "testA"},
+ }, {
+ name: "pointer helper",
+ do: testB,
+ expect: event.Source{Space: thisImportPath, Name: "testB"},
+ }, {
+ name: "named helper",
+ do: testC,
+ expect: event.Source{Space: thisImportPath, Name: "testC"},
+ }, {
+ name: "method",
+ do: testD,
+ expect: event.Source{Space: thisImportPath, Owner: "tester", Name: "D"},
+ }} {
+ t.Run(test.name, func(t *testing.T) {
+ h.Got = h.Got[:0]
+ test.do(ctx)
+ if len(h.Got) != 1 {
+ t.Fatalf("Expected 1 event, got %v", len(h.Got))
+ }
+ got := h.Got[0].Source
+ if got.Space != test.expect.Space {
+ t.Errorf("got namespace %q, want, %q", got.Space, test.expect.Space)
+ }
+ if got.Owner != test.expect.Owner {
+ t.Errorf("got owner %q, want, %q", got.Owner, test.expect.Owner)
+ }
+ if got.Name != test.expect.Name {
+ t.Errorf("got name %q, want, %q", got.Name, test.expect.Name)
+ }
+ })
+ }
+}
+
+type tester struct{}
+
+//go:noinline
+func testA(ctx context.Context) { event.Log(ctx, "test A") }
+
+//go:noinline
+func testB(ctx context.Context) { testHelperB(ctx) }
+
+//go:noinline
+func testHelperB(ctx context.Context) { event.Log(ctx, "test B") }
+
+//go:noinline
+func testC(ctx context.Context) { testHelperC(ctx) }
+
+//go:noinline
+func testHelperC(ctx context.Context) { event.Log(ctx, "test C") }
+
+//go:noinline
+func testD(ctx context.Context) { tester{}.D(ctx) }
+
+//go:noinline
+func (tester) D(ctx context.Context) { event.Log(ctx, "test D") }