From f0ebba1556c2a85f5ad5bbdeb55a69ef6b6295e5 Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Mon, 13 Apr 2020 12:11:54 -0400 Subject: [PATCH] internal/telemetry: add support for using telemetry in tests For now this just logs to the testing.TB, it should be possible to also use it to log metrics and timings in the future. Also adds event.Debugf as a temporary debugging print to the telemetry system, which is very helpful when debugging tests. Change-Id: Ib2e919998919491e227885e2ee6eeea9e2fdc996 Reviewed-on: https://go-review.googlesource.com/c/tools/+/228717 Run-TryBot: Ian Cottrell TryBot-Result: Gobot Gobot Reviewed-by: Emmanuel Odeke Reviewed-by: Robert Findley --- internal/telemetry/event/log.go | 9 +++ .../telemetry/export/eventtest/eventtest.go | 62 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 internal/telemetry/export/eventtest/eventtest.go diff --git a/internal/telemetry/event/log.go b/internal/telemetry/event/log.go index 568aa1b923..8d0a046e78 100644 --- a/internal/telemetry/event/log.go +++ b/internal/telemetry/event/log.go @@ -7,6 +7,7 @@ package event import ( "context" "errors" + "fmt" ) // Log sends a log event with the supplied tag list to the exporter. @@ -57,3 +58,11 @@ func Error(ctx context.Context, message string, err error, tags ...Tag) { } dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message), Err.Of(err)}, tags)) } + +// Debugf sends a log event with the supplied message to the exporter. +// This is intended only for temporary debugging lines, and usage should not +// normally be checked in, preffering structured log events for things +// that have to be used in production. +func Debugf(ctx context.Context, message string, args ...interface{}) { + dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(fmt.Sprintf(message, args...))}, nil)) +} diff --git a/internal/telemetry/export/eventtest/eventtest.go b/internal/telemetry/export/eventtest/eventtest.go new file mode 100644 index 0000000000..ae92166d7a --- /dev/null +++ b/internal/telemetry/export/eventtest/eventtest.go @@ -0,0 +1,62 @@ +// Copyright 2020 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 eventtest supports logging events to a test. +// You can use NewContext to create a context that knows how to deliver +// telemetry events back to the test. +// You must use this context or a derived one anywhere you want telemetry to be +// correctly routed back to the test it was constructed with. +// Any events delivered to a background context will be dropped. +// +// Importing this package will cause it to register a new global telemetry +// exporter that understands the special contexts returned by NewContext. +// This means you should not import this package if you are not going to call +// NewContext. +package eventtest + +import ( + "bytes" + "context" + "sync" + "testing" + + "golang.org/x/tools/internal/telemetry/event" + "golang.org/x/tools/internal/telemetry/export" +) + +func init() { + e := &testExporter{buffer: &bytes.Buffer{}} + e.logger = export.LogWriter(e.buffer, false) + + event.SetExporter(export.Spans(e.processEvent)) +} + +type testingKeyType int + +const testingKey = testingKeyType(0) + +// NewContext returns a context you should use for the active test. +func NewContext(ctx context.Context, t testing.TB) context.Context { + return context.WithValue(ctx, testingKey, t) +} + +type testExporter struct { + mu sync.Mutex + buffer *bytes.Buffer + logger event.Exporter +} + +func (w *testExporter) processEvent(ctx context.Context, ev event.Event, tagMap event.TagMap) context.Context { + w.mu.Lock() + defer w.mu.Unlock() + // build our log message in buffer + result := w.logger(ctx, ev, tagMap) + v := ctx.Value(testingKey) + // get the testing.TB + if w.buffer.Len() > 0 && v != nil { + v.(testing.TB).Log(w.buffer) + } + w.buffer.Truncate(0) + return result +}