diff --git a/internal/lsp/debug/rpc.go b/internal/lsp/debug/rpc.go index f1b6d9ab93e..39574c10cbe 100644 --- a/internal/lsp/debug/rpc.go +++ b/internal/lsp/debug/rpc.go @@ -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 diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go index 6ff023c0c9b..c1fb38014b3 100644 --- a/internal/lsp/debug/serve.go +++ b/internal/lsp/debug/serve.go @@ -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) { diff --git a/internal/lsp/debug/trace.go b/internal/lsp/debug/trace.go index cdf0ef73261..f71b5a6baa8 100644 --- a/internal/lsp/debug/trace.go +++ b/internal/lsp/debug/trace.go @@ -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 diff --git a/internal/lsp/protocol/context.go b/internal/lsp/protocol/context.go index d024e002d2e..7e9246d89ab 100644 --- a/internal/lsp/protocol/context.go +++ b/internal/lsp/protocol/context.go @@ -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 diff --git a/internal/telemetry/export/export.go b/internal/telemetry/export/export.go index 6ef33020980..dc794588ebf 100644 --- a/internal/telemetry/export/export.go +++ b/internal/telemetry/export/export.go @@ -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() } diff --git a/internal/telemetry/export/multi.go b/internal/telemetry/export/multi.go deleted file mode 100644 index df19f2c33be..00000000000 --- a/internal/telemetry/export/multi.go +++ /dev/null @@ -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() - } -} diff --git a/internal/telemetry/export/null.go b/internal/telemetry/export/null.go deleted file mode 100644 index cc01ba7a238..00000000000 --- a/internal/telemetry/export/null.go +++ /dev/null @@ -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() {} diff --git a/internal/telemetry/export/ocagent/README.md b/internal/telemetry/export/ocagent/README.md index a76f4151589..e1a9dc91fbf 100644 --- a/internal/telemetry/export/ocagent/README.md +++ b/internal/telemetry/export/ocagent/README.md @@ -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") diff --git a/internal/telemetry/export/prometheus/prometheus.go b/internal/telemetry/export/prometheus/prometheus.go index ccbdf96b1b6..ffbb01d5ea5 100644 --- a/internal/telemetry/export/prometheus/prometheus.go +++ b/internal/telemetry/export/prometheus/prometheus.go @@ -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() diff --git a/internal/telemetry/log/bench_test.go b/internal/telemetry/log/bench_test.go index 5eb0b33bca0..16e34766dc6 100644 --- a/internal/telemetry/log/bench_test.go +++ b/internal/telemetry/log/bench_test.go @@ -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++ {