1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:14:46 -07:00

internal/telemetry: removing the concept of exporter lists

Instead we only have a single exporter, and it must delegate behaviour
to any other exporters it wants to include.
This removes a whole collection of suprises caused by init functions adding
new exporters to a list, as well as generally making things faster, at the small
expense of needing to implement a custom exporter if you want to combine the
features of a few other exporters.

This is essentially the opposite of https://go-review.googlesource.com/c/tools/+/212243
which will now be abandoned in favor of this approach.

Change-Id: Icacb4c1f0f40f99ddd1d82c73d4f25a3486e56ce
Reviewed-on: https://go-review.googlesource.com/c/tools/+/220857
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Ian Cottrell 2020-02-05 18:30:35 +00:00
parent eb7c56241b
commit 2e887e3d13
10 changed files with 75 additions and 119 deletions

View File

@ -90,11 +90,6 @@ type rpcCodeBucket struct {
Count int64
}
func (r *rpcs) StartSpan(ctx context.Context, span *telemetry.Span) {}
func (r *rpcs) FinishSpan(ctx context.Context, span *telemetry.Span) {}
func (r *rpcs) Log(ctx context.Context, event telemetry.Event) {}
func (r *rpcs) Flush() {}
func (r *rpcs) Metric(ctx context.Context, data telemetry.MetricData) {
for i, group := range data.Groups() {
set := &r.Inbound

View File

@ -27,7 +27,9 @@ import (
"sync"
"time"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry"
"golang.org/x/tools/internal/telemetry/export"
"golang.org/x/tools/internal/telemetry/export/ocagent"
"golang.org/x/tools/internal/telemetry/export/prometheus"
@ -368,7 +370,7 @@ func NewInstance(workdir, agent string) *Instance {
i.rpcs = &rpcs{}
i.traces = &traces{}
i.State = &State{}
export.AddExporters(i.ocagent, i.prometheus, i.rpcs, i.traces)
export.SetExporter(i)
return i
}
@ -493,6 +495,57 @@ func (i *Instance) writeMemoryDebug(threshold uint64) error {
return nil
}
func (i *Instance) StartSpan(ctx context.Context, spn *telemetry.Span) {
if i.ocagent != nil {
i.ocagent.StartSpan(ctx, spn)
}
if i.traces != nil {
i.traces.StartSpan(ctx, spn)
}
}
func (i *Instance) FinishSpan(ctx context.Context, spn *telemetry.Span) {
if i.ocagent != nil {
i.ocagent.FinishSpan(ctx, spn)
}
if i.traces != nil {
i.traces.FinishSpan(ctx, spn)
}
}
//TODO: remove this hack
// capture stderr at startup because it gets modified in a way that this
// logger should not respect
var stderr = os.Stderr
func (i *Instance) Log(ctx context.Context, event telemetry.Event) {
if event.Error != nil {
fmt.Fprintf(stderr, "%v\n", event)
}
protocol.LogEvent(ctx, event)
if i.ocagent != nil {
i.ocagent.Log(ctx, event)
}
}
func (i *Instance) Metric(ctx context.Context, data telemetry.MetricData) {
if i.ocagent != nil {
i.ocagent.Metric(ctx, data)
}
if i.traces != nil {
i.prometheus.Metric(ctx, data)
}
if i.rpcs != nil {
i.rpcs.Metric(ctx, data)
}
}
func (i *Instance) Flush() {
if i.ocagent != nil {
i.ocagent.Flush()
}
}
type dataFunc func(*http.Request) interface{}
func render(tmpl *template.Template, fun dataFunc) func(http.ResponseWriter, *http.Request) {

View File

@ -130,12 +130,6 @@ func (t *traces) FinishSpan(ctx context.Context, span *telemetry.Span) {
}
}
func (t *traces) Log(ctx context.Context, event telemetry.Event) {}
func (t *traces) Metric(ctx context.Context, data telemetry.MetricData) {}
func (t *traces) Flush() {}
func (t *traces) getData(req *http.Request) interface{} {
if len(t.sets) == 0 {
return nil

View File

@ -5,14 +5,9 @@ import (
"fmt"
"golang.org/x/tools/internal/telemetry"
"golang.org/x/tools/internal/telemetry/export"
"golang.org/x/tools/internal/xcontext"
)
func init() {
export.AddExporters(logExporter{})
}
type contextKey int
const (
@ -23,16 +18,7 @@ func WithClient(ctx context.Context, client Client) context.Context {
return context.WithValue(ctx, clientKey, client)
}
// logExporter sends the log event back to the client if there is one stored on the
// context.
type logExporter struct{}
func (logExporter) StartSpan(context.Context, *telemetry.Span) {}
func (logExporter) FinishSpan(context.Context, *telemetry.Span) {}
func (logExporter) Metric(context.Context, telemetry.MetricData) {}
func (logExporter) Flush() {}
func (logExporter) Log(ctx context.Context, event telemetry.Event) {
func LogEvent(ctx context.Context, event telemetry.Event) {
client, ok := ctx.Value(clientKey).(Client)
if !ok {
return

View File

@ -41,15 +41,12 @@ func SetExporter(e Exporter) {
exporter = e
}
func AddExporters(e ...Exporter) {
exporterMu.Lock()
defer exporterMu.Unlock()
exporter = Multi(append([]Exporter{exporter}, e...)...)
}
func StartSpan(ctx context.Context, span *telemetry.Span, at time.Time) {
exporterMu.Lock()
defer exporterMu.Unlock()
if exporter == nil {
return
}
span.Start = at
exporter.StartSpan(ctx, span)
}
@ -57,6 +54,9 @@ func StartSpan(ctx context.Context, span *telemetry.Span, at time.Time) {
func FinishSpan(ctx context.Context, span *telemetry.Span, at time.Time) {
exporterMu.Lock()
defer exporterMu.Unlock()
if exporter == nil {
return
}
span.Finish = at
exporter.FinishSpan(ctx, span)
}
@ -64,6 +64,9 @@ func FinishSpan(ctx context.Context, span *telemetry.Span, at time.Time) {
func Tag(ctx context.Context, at time.Time, tags telemetry.TagList) {
exporterMu.Lock()
defer exporterMu.Unlock()
if exporter == nil {
return
}
// If context has a span we need to add the tags to it
span := telemetry.GetSpan(ctx)
if span == nil {
@ -84,6 +87,9 @@ func Tag(ctx context.Context, at time.Time, tags telemetry.TagList) {
func Log(ctx context.Context, event telemetry.Event) {
exporterMu.Lock()
defer exporterMu.Unlock()
if exporter == nil {
return
}
// If context has a span we need to add the event to it
span := telemetry.GetSpan(ctx)
if span != nil {
@ -96,11 +102,17 @@ func Log(ctx context.Context, event telemetry.Event) {
func Metric(ctx context.Context, data telemetry.MetricData) {
exporterMu.Lock()
defer exporterMu.Unlock()
if exporter == nil {
return
}
exporter.Metric(ctx, data)
}
func Flush() {
exporterMu.Lock()
defer exporterMu.Unlock()
if exporter == nil {
return
}
exporter.Flush()
}

View File

@ -1,55 +0,0 @@
// Copyright 2019 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 export
import (
"context"
"golang.org/x/tools/internal/telemetry"
)
// Multi returns an exporter that invokes all the exporters given to it in order.
func Multi(e ...Exporter) Exporter {
a := make(multi, 0, len(e))
for _, i := range e {
if i == nil {
continue
}
if i, ok := i.(multi); ok {
a = append(a, i...)
continue
}
a = append(a, i)
}
return a
}
type multi []Exporter
func (m multi) StartSpan(ctx context.Context, span *telemetry.Span) {
for _, o := range m {
o.StartSpan(ctx, span)
}
}
func (m multi) FinishSpan(ctx context.Context, span *telemetry.Span) {
for _, o := range m {
o.FinishSpan(ctx, span)
}
}
func (m multi) Log(ctx context.Context, event telemetry.Event) {
for _, o := range m {
o.Log(ctx, event)
}
}
func (m multi) Metric(ctx context.Context, data telemetry.MetricData) {
for _, o := range m {
o.Metric(ctx, data)
}
}
func (m multi) Flush() {
for _, o := range m {
o.Flush()
}
}

View File

@ -1,24 +0,0 @@
// Copyright 2019 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 export
import (
"context"
"golang.org/x/tools/internal/telemetry"
)
// Null returns an observer that does nothing.
func Null() Exporter {
return null{}
}
type null struct{}
func (null) StartSpan(context.Context, *telemetry.Span) {}
func (null) FinishSpan(context.Context, *telemetry.Span) {}
func (null) Log(context.Context, telemetry.Event) {}
func (null) Metric(context.Context, telemetry.MetricData) {}
func (null) Flush() {}

View File

@ -79,7 +79,7 @@ func main() {
Rate: 5 * time.Second,
Client: &http.Client{},
})
export.AddExporters(exporter)
export.SetExporter(exporter)
ctx := context.TODO()
mLatency := stats.Float64("latency", "the latency in milliseconds", "ms")

View File

@ -25,11 +25,6 @@ type Exporter struct {
metrics []telemetry.MetricData
}
func (e *Exporter) StartSpan(ctx context.Context, span *telemetry.Span) {}
func (e *Exporter) FinishSpan(ctx context.Context, span *telemetry.Span) {}
func (e *Exporter) Log(ctx context.Context, event telemetry.Event) {}
func (e *Exporter) Flush() {}
func (e *Exporter) Metric(ctx context.Context, data telemetry.MetricData) {
e.mu.Lock()
defer e.mu.Unlock()

View File

@ -91,7 +91,7 @@ func BenchmarkBaseline(b *testing.B) {
func BenchmarkLoggingNoExporter(b *testing.B) {
ctx := context.Background()
export.SetExporter(export.Null())
export.SetExporter(nil)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {