internal/telemetry: change Exporter to be a function type.
Change-Id: Id410da20310baf4da6875de08e4449c7a6fb0250
Reviewed-on: https://go-review.googlesource.com/c/tools/+/224277
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go
index 7835740..11b731a 100644
--- a/internal/lsp/debug/serve.go
+++ b/internal/lsp/debug/serve.go
@@ -36,10 +36,6 @@
"golang.org/x/tools/internal/telemetry/export/prometheus"
)
-type exporter struct {
- stderr io.Writer
-}
-
type instanceKeyType int
const instanceKey = instanceKeyType(0)
@@ -387,9 +383,7 @@
}
func init() {
- event.SetExporter(&exporter{
- stderr: os.Stderr,
- })
+ event.SetExporter(makeExporter(os.Stderr))
}
func GetInstance(ctx context.Context) *Instance {
@@ -545,31 +539,33 @@
return nil
}
-func (e *exporter) ProcessEvent(ctx context.Context, ev event.Event) (context.Context, event.Event) {
- ctx, ev = export.ContextSpan(ctx, ev)
- i := GetInstance(ctx)
- if ev.IsLog() && (ev.Error != nil || i == nil) {
- fmt.Fprintf(e.stderr, "%v\n", ev)
- }
- ctx, ev = protocol.LogEvent(ctx, ev)
- if i == nil {
+func makeExporter(stderr io.Writer) event.Exporter {
+ return func(ctx context.Context, ev event.Event) (context.Context, event.Event) {
+ ctx, ev = export.ContextSpan(ctx, ev)
+ i := GetInstance(ctx)
+ if ev.IsLog() && (ev.Error != nil || i == nil) {
+ fmt.Fprintf(stderr, "%v\n", ev)
+ }
+ ctx, ev = protocol.LogEvent(ctx, ev)
+ if i == nil {
+ return ctx, ev
+ }
+ ctx, ev = export.Tag(ctx, ev)
+ ctx, ev = i.metrics.ProcessEvent(ctx, ev)
+ if i.ocagent != nil {
+ ctx, ev = i.ocagent.ProcessEvent(ctx, ev)
+ }
+ if i.prometheus != nil {
+ ctx, ev = i.prometheus.ProcessEvent(ctx, ev)
+ }
+ if i.rpcs != nil {
+ ctx, ev = i.rpcs.ProcessEvent(ctx, ev)
+ }
+ if i.traces != nil {
+ ctx, ev = i.traces.ProcessEvent(ctx, ev)
+ }
return ctx, ev
}
- ctx, ev = export.Tag(ctx, ev)
- ctx, ev = i.metrics.ProcessEvent(ctx, ev)
- if i.ocagent != nil {
- ctx, ev = i.ocagent.ProcessEvent(ctx, ev)
- }
- if i.prometheus != nil {
- ctx, ev = i.prometheus.ProcessEvent(ctx, ev)
- }
- if i.rpcs != nil {
- ctx, ev = i.rpcs.ProcessEvent(ctx, ev)
- }
- if i.traces != nil {
- ctx, ev = i.traces.ProcessEvent(ctx, ev)
- }
- return ctx, ev
}
type dataFunc func(*http.Request) interface{}
diff --git a/internal/telemetry/bench_test.go b/internal/telemetry/bench_test.go
index 0ebdc2c..2568304 100644
--- a/internal/telemetry/bench_test.go
+++ b/internal/telemetry/bench_test.go
@@ -95,7 +95,7 @@
b.Run("TraceNoExporter", Trace.runBenchmark)
b.Run("StatsNoExporter", Stats.runBenchmark)
- event.SetExporter(newExporter())
+ event.SetExporter(noopExporter)
b.Run("Log", Log.runBenchmark)
b.Run("Trace", Trace.runBenchmark)
b.Run("Stats", Stats.runBenchmark)
@@ -142,17 +142,9 @@
return len(b), nil
}
-type loggingExporter struct {
- logger event.Exporter
-}
+var noopLogger = export.LogWriter(new(noopWriter), false)
-func newExporter() *loggingExporter {
- return &loggingExporter{
- logger: export.LogWriter(new(noopWriter), false),
- }
-}
-
-func (e *loggingExporter) ProcessEvent(ctx context.Context, ev event.Event) (context.Context, event.Event) {
+func noopExporter(ctx context.Context, ev event.Event) (context.Context, event.Event) {
ctx, ev = export.ContextSpan(ctx, ev)
- return e.logger.ProcessEvent(ctx, ev)
+ return noopLogger(ctx, ev)
}
diff --git a/internal/telemetry/event/export.go b/internal/telemetry/event/export.go
index 073ebef..362ba29 100644
--- a/internal/telemetry/event/export.go
+++ b/internal/telemetry/event/export.go
@@ -10,36 +10,35 @@
"unsafe"
)
-type Exporter interface {
- // ProcessEvent is a function that handles all events.
- // This is called with all events that should be delivered to the exporter
- // along with the context in which that event ocurred.
- // This method is called synchronously from the event call site, so it should
- // return quickly so as not to hold up user code.
- ProcessEvent(context.Context, Event) (context.Context, Event)
-}
+// Exporter is a function that handles events.
+// It may return a modified context and event.
+type Exporter func(context.Context, Event) (context.Context, Event)
var (
exporter unsafe.Pointer
)
+// SetExporter sets the global exporter function that handles all events.
+// The exporter is called synchronously from the event call site, so it should
+// return quickly so as not to hold up user code.
func SetExporter(e Exporter) {
p := unsafe.Pointer(&e)
if e == nil {
// &e is always valid, and so p is always valid, but for the early abort
// of ProcessEvent to be efficient it needs to make the nil check on the
- // pointer without having to dereference it, so we make the nil interface
+ // pointer without having to dereference it, so we make the nil function
// also a nil pointer
p = nil
}
atomic.StorePointer(&exporter, p)
}
+// ProcessEvent is called to deliver an event to the global exporter.
func ProcessEvent(ctx context.Context, ev Event) (context.Context, Event) {
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
if exporterPtr == nil {
return ctx, ev
}
// and now also hand the event of to the current exporter
- return (*exporterPtr).ProcessEvent(ctx, ev)
+ return (*exporterPtr)(ctx, ev)
}
diff --git a/internal/telemetry/export/log.go b/internal/telemetry/export/log.go
index bb74805..1f53542 100644
--- a/internal/telemetry/export/log.go
+++ b/internal/telemetry/export/log.go
@@ -8,21 +8,17 @@
"context"
"fmt"
"io"
- "os"
"golang.org/x/tools/internal/telemetry/event"
)
-func init() {
- event.SetExporter(LogWriter(os.Stderr, true))
-}
-
// LogWriter returns an Exporter that logs events to the supplied writer.
// If onlyErrors is true it does not log any event that did not have an
// associated error.
// It ignores all telemetry other than log events.
func LogWriter(w io.Writer, onlyErrors bool) event.Exporter {
- return &logWriter{writer: w, onlyErrors: onlyErrors}
+ lw := &logWriter{writer: w, onlyErrors: onlyErrors}
+ return lw.ProcessEvent
}
type logWriter struct {
diff --git a/internal/telemetry/export/ocagent/ocagent_test.go b/internal/telemetry/export/ocagent/ocagent_test.go
index 329fc6a..ecd2612 100644
--- a/internal/telemetry/export/ocagent/ocagent_test.go
+++ b/internal/telemetry/export/ocagent/ocagent_test.go
@@ -116,11 +116,11 @@
metricBytesIn.Record(&exporter.metrics, bytesIn)
metricRecursiveCalls.SumInt64(&exporter.metrics, recursiveCalls)
- event.SetExporter(exporter)
+ event.SetExporter(exporter.processEvent)
return exporter
}
-func (e *testExporter) ProcessEvent(ctx context.Context, ev event.Event) (context.Context, event.Event) {
+func (e *testExporter) processEvent(ctx context.Context, ev event.Event) (context.Context, event.Event) {
switch {
case ev.IsStartSpan():
ev.At = e.start