// 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 holds the definition of the telemetry Exporter interface, // along with some simple implementations. // Larger more complex exporters are in sub packages of their own. package export import ( "context" "os" "sync" "time" "golang.org/x/tools/internal/telemetry" ) type Exporter interface { StartSpan(context.Context, *telemetry.Span) FinishSpan(context.Context, *telemetry.Span) // Log is a function that handles logging events. // Observers may use information in the context to decide what to do with a // given log event. Log(context.Context, telemetry.Event) Metric(context.Context, telemetry.MetricData) Flush() } var ( exporterMu sync.Mutex exporter = LogWriter(os.Stderr, true) ) 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() span.Start = at exporter.StartSpan(ctx, span) } func FinishSpan(ctx context.Context, span *telemetry.Span, at time.Time) { exporterMu.Lock() defer exporterMu.Unlock() span.Finish = at exporter.FinishSpan(ctx, span) } func Tag(ctx context.Context, at time.Time, tags telemetry.TagList) { exporterMu.Lock() defer exporterMu.Unlock() // If context has a span we need to add the tags to it span := telemetry.GetSpan(ctx) if span == nil { return } if span.Start.IsZero() { // span still being created, tag it directly span.Tags = append(span.Tags, tags...) return } // span in progress, add an event to the span span.Events = append(span.Events, telemetry.Event{ At: at, Tags: tags, }) } func Log(ctx context.Context, event telemetry.Event) { exporterMu.Lock() defer exporterMu.Unlock() // If context has a span we need to add the event to it span := telemetry.GetSpan(ctx) if span != nil { span.Events = append(span.Events, event) } // and now also hand the event of to the current observer exporter.Log(ctx, event) } func Metric(ctx context.Context, data telemetry.MetricData) { exporterMu.Lock() defer exporterMu.Unlock() exporter.Metric(ctx, data) } func Flush() { exporterMu.Lock() defer exporterMu.Unlock() exporter.Flush() }