mirror of
https://github.com/golang/go
synced 2024-11-18 14:54:40 -07:00
internal/telemetry: unify the event handling to an event package
This is now the only package that is exposed to normal use, and should be the only thing to appear in libraries. Change-Id: I90ee47c6519f30db16ff5d5d2910be86e91e5df2 Reviewed-on: https://go-review.googlesource.com/c/tools/+/222557 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
3dc7fec788
commit
d780ff7bdd
@ -202,7 +202,7 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
|
||||
Version: key.id.Version,
|
||||
}); err != nil {
|
||||
if ctx.Err() == nil {
|
||||
log.Error(ctx, "publishReports: failed to deliver diagnostic", err, telemetry.File.Tag(ctx))
|
||||
log.Error(ctx, "publishReports: failed to deliver diagnostic", err, telemetry.File.From(ctx))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -2,16 +2,13 @@ package telemetry_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
stdlog "log"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
tellog "golang.org/x/tools/internal/telemetry/log"
|
||||
"golang.org/x/tools/internal/telemetry/stats"
|
||||
"golang.org/x/tools/internal/telemetry/tag"
|
||||
teltrace "golang.org/x/tools/internal/telemetry/trace"
|
||||
"golang.org/x/tools/internal/telemetry/unit"
|
||||
)
|
||||
|
||||
@ -37,40 +34,40 @@ var (
|
||||
|
||||
StdLog = Hooks{
|
||||
A: func(ctx context.Context, a *int) (context.Context, func()) {
|
||||
stdlog.Printf("start A where a=%d", *a)
|
||||
log.Printf("start A where a=%d", *a)
|
||||
return ctx, func() {
|
||||
stdlog.Printf("end A where a=%d", *a)
|
||||
log.Printf("end A where a=%d", *a)
|
||||
}
|
||||
},
|
||||
B: func(ctx context.Context, b *string) (context.Context, func()) {
|
||||
stdlog.Printf("start B where b=%q", *b)
|
||||
log.Printf("start B where b=%q", *b)
|
||||
return ctx, func() {
|
||||
stdlog.Printf("end B where b=%q", *b)
|
||||
log.Printf("end B where b=%q", *b)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Log = Hooks{
|
||||
A: func(ctx context.Context, a *int) (context.Context, func()) {
|
||||
tellog.Print(ctx, "start A", tag.Of("a", *a))
|
||||
event.Print(ctx, "start A", event.TagOf("a", *a))
|
||||
return ctx, func() {
|
||||
tellog.Print(ctx, "end A", tag.Of("a", *a))
|
||||
event.Print(ctx, "end A", event.TagOf("a", *a))
|
||||
}
|
||||
},
|
||||
B: func(ctx context.Context, b *string) (context.Context, func()) {
|
||||
tellog.Print(ctx, "start B", tag.Of("b", *b))
|
||||
event.Print(ctx, "start B", event.TagOf("b", *b))
|
||||
return ctx, func() {
|
||||
tellog.Print(ctx, "end B", tag.Of("b", *b))
|
||||
event.Print(ctx, "end B", event.TagOf("b", *b))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Trace = Hooks{
|
||||
A: func(ctx context.Context, a *int) (context.Context, func()) {
|
||||
return teltrace.StartSpan(ctx, "A")
|
||||
return event.StartSpan(ctx, "A")
|
||||
},
|
||||
B: func(ctx context.Context, b *string) (context.Context, func()) {
|
||||
return teltrace.StartSpan(ctx, "B")
|
||||
return event.StartSpan(ctx, "B")
|
||||
},
|
||||
}
|
||||
|
||||
@ -93,12 +90,12 @@ var (
|
||||
func Benchmark(b *testing.B) {
|
||||
b.Run("Baseline", Baseline.runBenchmark)
|
||||
b.Run("StdLog", StdLog.runBenchmark)
|
||||
export.SetExporter(nil)
|
||||
event.SetExporter(nil)
|
||||
b.Run("LogNoExporter", Log.runBenchmark)
|
||||
b.Run("TraceNoExporter", Trace.runBenchmark)
|
||||
b.Run("StatsNoExporter", Stats.runBenchmark)
|
||||
|
||||
export.SetExporter(newExporter())
|
||||
event.SetExporter(newExporter())
|
||||
b.Run("Log", Log.runBenchmark)
|
||||
b.Run("Trace", Trace.runBenchmark)
|
||||
b.Run("Stats", Stats.runBenchmark)
|
||||
@ -136,7 +133,7 @@ func (hooks Hooks) runBenchmark(b *testing.B) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
stdlog.SetOutput(new(noopWriter))
|
||||
log.SetOutput(new(noopWriter))
|
||||
}
|
||||
|
||||
type noopWriter int
|
||||
@ -146,7 +143,7 @@ func (nw *noopWriter) Write(b []byte) (int, error) {
|
||||
}
|
||||
|
||||
type loggingExporter struct {
|
||||
logger export.Exporter
|
||||
logger event.Exporter
|
||||
}
|
||||
|
||||
func newExporter() *loggingExporter {
|
||||
@ -155,11 +152,11 @@ func newExporter() *loggingExporter {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *loggingExporter) ProcessEvent(ctx context.Context, event telemetry.Event) context.Context {
|
||||
export.ContextSpan(ctx, event)
|
||||
return e.logger.ProcessEvent(ctx, event)
|
||||
func (e *loggingExporter) ProcessEvent(ctx context.Context, ev event.Event) context.Context {
|
||||
export.ContextSpan(ctx, ev)
|
||||
return e.logger.ProcessEvent(ctx, ev)
|
||||
}
|
||||
|
||||
func (e *loggingExporter) Metric(ctx context.Context, data telemetry.MetricData) {
|
||||
func (e *loggingExporter) Metric(ctx context.Context, data event.MetricData) {
|
||||
e.logger.Metric(ctx, data)
|
||||
}
|
||||
|
@ -2,14 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package telemetry provides an opinionated set of packages that cover the main
|
||||
// Package telemetry provides a set of packages that cover the main
|
||||
// concepts of telemetry in an implementation agnostic way.
|
||||
// As a library author you should look at
|
||||
// stats (for aggregatable measurements)
|
||||
// trace (for scoped timing spans)
|
||||
// log (for for time based events)
|
||||
// As a binary author you might look at
|
||||
// metric (for methods of aggregating stats)
|
||||
// exporter (for methods of exporting the telemetry to external tools)
|
||||
// debug (for serving internal http pages of some of the telemetry)
|
||||
// The interface for libraries that want to expose telemetry is the event
|
||||
// package.
|
||||
// As a binary author you might look at exporter for methods of exporting the
|
||||
// telemetry to external tools.
|
||||
package telemetry
|
||||
|
@ -4,42 +4,17 @@
|
||||
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
import "golang.org/x/tools/internal/telemetry/event"
|
||||
|
||||
type EventType uint8
|
||||
type Event = event.Event
|
||||
type Tag = event.Tag
|
||||
type TagList = event.TagList
|
||||
type MetricData = event.MetricData
|
||||
|
||||
const (
|
||||
EventLog = EventType(iota)
|
||||
EventStartSpan
|
||||
EventEndSpan
|
||||
EventTag
|
||||
EventDetach
|
||||
EventLog = event.LogType
|
||||
EventStartSpan = event.StartSpanType
|
||||
EventEndSpan = event.EndSpanType
|
||||
EventLabel = event.LabelType
|
||||
EventDetach = event.DetachType
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Type EventType
|
||||
At time.Time
|
||||
Message string
|
||||
Error error
|
||||
Tags TagList
|
||||
}
|
||||
|
||||
func (e Event) Format(f fmt.State, r rune) {
|
||||
if !e.At.IsZero() {
|
||||
fmt.Fprint(f, e.At.Format("2006/01/02 15:04:05 "))
|
||||
}
|
||||
fmt.Fprint(f, e.Message)
|
||||
if e.Error != nil {
|
||||
if f.Flag('+') {
|
||||
fmt.Fprintf(f, ": %+v", e.Error)
|
||||
} else {
|
||||
fmt.Fprintf(f, ": %v", e.Error)
|
||||
}
|
||||
}
|
||||
for _, tag := range e.Tags {
|
||||
fmt.Fprintf(f, "\n\t%v = %v", tag.Key, tag.Value)
|
||||
}
|
||||
}
|
||||
|
52
internal/telemetry/event/event.go
Normal file
52
internal/telemetry/event/event.go
Normal file
@ -0,0 +1,52 @@
|
||||
// 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 event provides support for event based telemetry.
|
||||
package event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type eventType uint8
|
||||
|
||||
const (
|
||||
LogType = eventType(iota)
|
||||
StartSpanType
|
||||
EndSpanType
|
||||
LabelType
|
||||
DetachType
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Type eventType
|
||||
At time.Time
|
||||
Message string
|
||||
Error error
|
||||
Tags TagList
|
||||
}
|
||||
|
||||
func (e Event) IsLog() bool { return e.Type == LogType }
|
||||
func (e Event) IsEndSpan() bool { return e.Type == EndSpanType }
|
||||
func (e Event) IsStartSpan() bool { return e.Type == StartSpanType }
|
||||
func (e Event) IsTag() bool { return e.Type == LabelType }
|
||||
func (e Event) IsDetach() bool { return e.Type == DetachType }
|
||||
|
||||
func (e Event) Format(f fmt.State, r rune) {
|
||||
if !e.At.IsZero() {
|
||||
fmt.Fprint(f, e.At.Format("2006/01/02 15:04:05 "))
|
||||
}
|
||||
fmt.Fprint(f, e.Message)
|
||||
if e.Error != nil {
|
||||
if f.Flag('+') {
|
||||
fmt.Fprintf(f, ": %+v", e.Error)
|
||||
} else {
|
||||
fmt.Fprintf(f, ": %v", e.Error)
|
||||
}
|
||||
}
|
||||
for _, tag := range e.Tags {
|
||||
fmt.Fprintf(f, "\n\t%v = %v", tag.Key, tag.Value)
|
||||
}
|
||||
}
|
55
internal/telemetry/event/export.go
Normal file
55
internal/telemetry/event/export.go
Normal file
@ -0,0 +1,55 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"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
|
||||
|
||||
Metric(context.Context, MetricData)
|
||||
}
|
||||
|
||||
var (
|
||||
exporter unsafe.Pointer
|
||||
)
|
||||
|
||||
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
|
||||
// also a nil pointer
|
||||
p = nil
|
||||
}
|
||||
atomic.StorePointer(&exporter, p)
|
||||
}
|
||||
|
||||
func ProcessEvent(ctx context.Context, event Event) context.Context {
|
||||
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
||||
if exporterPtr == nil {
|
||||
return ctx
|
||||
}
|
||||
// and now also hand the event of to the current exporter
|
||||
return (*exporterPtr).ProcessEvent(ctx, event)
|
||||
}
|
||||
|
||||
func Metric(ctx context.Context, data MetricData) {
|
||||
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
||||
if exporterPtr == nil {
|
||||
return
|
||||
}
|
||||
(*exporterPtr).Metric(ctx, data)
|
||||
}
|
@ -2,13 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package tag provides support for telemetry tagging.
|
||||
package tag
|
||||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
)
|
||||
|
||||
// Key represents the key for a context tag.
|
||||
@ -19,27 +16,24 @@ import (
|
||||
// those values in the context.
|
||||
type Key string
|
||||
|
||||
// Of returns a Tag for a key and value.
|
||||
// TagOf returns a Tag for a key and value.
|
||||
// This is a trivial helper that makes common logging easier to read.
|
||||
func Of(key interface{}, value interface{}) telemetry.Tag {
|
||||
return telemetry.Tag{Key: key, Value: value}
|
||||
func TagOf(key interface{}, value interface{}) Tag {
|
||||
return Tag{Key: key, Value: value}
|
||||
}
|
||||
|
||||
// Of creates a new Tag with this key and the supplied value.
|
||||
// You can use this when building a tag list.
|
||||
func (k Key) Of(v interface{}) telemetry.Tag {
|
||||
return telemetry.Tag{Key: k, Value: v}
|
||||
func (k Key) Of(v interface{}) Tag {
|
||||
return Tag{Key: k, Value: v}
|
||||
}
|
||||
|
||||
// Tag can be used to get a tag for the key from a context.
|
||||
// It makes Key conform to the Tagger interface.
|
||||
func (k Key) Tag(ctx context.Context) telemetry.Tag {
|
||||
return telemetry.Tag{Key: k, Value: ctx.Value(k)}
|
||||
// From can be used to get a tag for the key from a context.
|
||||
func (k Key) From(ctx context.Context) Tag {
|
||||
return Tag{Key: k, Value: ctx.Value(k)}
|
||||
}
|
||||
|
||||
// With applies sets this key to the supplied value on the context and
|
||||
// returns the new context generated.
|
||||
// It uses the With package level function so that observers are also notified.
|
||||
// With is a wrapper over the Label package level function for just this key.
|
||||
func (k Key) With(ctx context.Context, v interface{}) context.Context {
|
||||
return With(ctx, telemetry.Tag{Key: k, Value: v})
|
||||
return Label(ctx, Tag{Key: k, Value: v})
|
||||
}
|
19
internal/telemetry/event/label.go
Normal file
19
internal/telemetry/event/label.go
Normal file
@ -0,0 +1,19 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Label sends a label event to the exporter with the supplied tags.
|
||||
func Label(ctx context.Context, tags ...Tag) context.Context {
|
||||
return ProcessEvent(ctx, Event{
|
||||
Type: LabelType,
|
||||
At: time.Now(),
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
48
internal/telemetry/event/log.go
Normal file
48
internal/telemetry/event/log.go
Normal file
@ -0,0 +1,48 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Log sends a log event with the supplied tag list to the exporter.
|
||||
func Log(ctx context.Context, tags ...Tag) {
|
||||
ProcessEvent(ctx, Event{
|
||||
Type: LogType,
|
||||
At: time.Now(),
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
// Print takes a message and a tag list and combines them into a single event
|
||||
// before delivering them to the exporter.
|
||||
func Print(ctx context.Context, message string, tags ...Tag) {
|
||||
ProcessEvent(ctx, Event{
|
||||
Type: LogType,
|
||||
At: time.Now(),
|
||||
Message: message,
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
// Error takes a message and a tag list and combines them into a single event
|
||||
// before delivering them to the exporter. It captures the error in the
|
||||
// delivered event.
|
||||
func Error(ctx context.Context, message string, err error, tags ...Tag) {
|
||||
if err == nil {
|
||||
err = errors.New(message)
|
||||
message = ""
|
||||
}
|
||||
ProcessEvent(ctx, Event{
|
||||
Type: LogType,
|
||||
At: time.Now(),
|
||||
Message: message,
|
||||
Error: err,
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package telemetry
|
||||
package event
|
||||
|
||||
// MetricData represents a single point in the time series of a metric.
|
||||
// This provides the common interface to all metrics no matter their data
|
@ -2,9 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package telemetry
|
||||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@ -25,6 +26,16 @@ func (t Tag) Format(f fmt.State, r rune) {
|
||||
fmt.Fprintf(f, `%v="%v"`, t.Key, t.Value)
|
||||
}
|
||||
|
||||
// Tags collects a set of values from the context and returns them as a
|
||||
// tag list.
|
||||
func Tags(ctx context.Context, keys ...interface{}) TagList {
|
||||
tags := make(TagList, len(keys))
|
||||
for i, key := range keys {
|
||||
tags[i] = Tag{Key: key, Value: ctx.Value(key)}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// Get will get a single key's value from the list.
|
||||
func (l TagList) Get(k interface{}) interface{} {
|
||||
for _, t := range l {
|
34
internal/telemetry/event/trace.go
Normal file
34
internal/telemetry/event/trace.go
Normal file
@ -0,0 +1,34 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
func StartSpan(ctx context.Context, name string, tags ...Tag) (context.Context, func()) {
|
||||
ctx = ProcessEvent(ctx, Event{
|
||||
Type: StartSpanType,
|
||||
Message: name,
|
||||
At: time.Now(),
|
||||
Tags: tags,
|
||||
})
|
||||
return ctx, func() {
|
||||
ProcessEvent(ctx, Event{
|
||||
Type: EndSpanType,
|
||||
At: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Detach returns a context without an associated span.
|
||||
// This allows the creation of spans that are not children of the current span.
|
||||
func Detach(ctx context.Context) context.Context {
|
||||
return ProcessEvent(ctx, Event{
|
||||
Type: DetachType,
|
||||
At: time.Now(),
|
||||
})
|
||||
}
|
@ -2,58 +2,12 @@
|
||||
// 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.
|
||||
// Package export holds some exporter implementations.
|
||||
// Larger more complex exporters are in sub packages of their own.
|
||||
package export
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
)
|
||||
|
||||
type Exporter interface {
|
||||
// ProcessEvent is a function that handles all events.
|
||||
// Exporters may use information in the context to decide what to do with a
|
||||
// given event.
|
||||
ProcessEvent(context.Context, telemetry.Event) context.Context
|
||||
|
||||
Metric(context.Context, telemetry.MetricData)
|
||||
}
|
||||
import "golang.org/x/tools/internal/telemetry/event"
|
||||
|
||||
var (
|
||||
exporter unsafe.Pointer
|
||||
SetExporter = event.SetExporter
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetExporter(LogWriter(os.Stderr, true))
|
||||
}
|
||||
|
||||
func SetExporter(e Exporter) {
|
||||
p := unsafe.Pointer(&e)
|
||||
if e == nil {
|
||||
p = nil
|
||||
}
|
||||
atomic.StorePointer(&exporter, p)
|
||||
}
|
||||
|
||||
func ProcessEvent(ctx context.Context, event telemetry.Event) context.Context {
|
||||
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
||||
if exporterPtr == nil {
|
||||
return ctx
|
||||
}
|
||||
// and now also hand the event of to the current exporter
|
||||
return (*exporterPtr).ProcessEvent(ctx, event)
|
||||
}
|
||||
|
||||
func Metric(ctx context.Context, data telemetry.MetricData) {
|
||||
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
||||
if exporterPtr == nil {
|
||||
return
|
||||
}
|
||||
(*exporterPtr).Metric(ctx, data)
|
||||
}
|
||||
|
@ -8,15 +8,20 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
)
|
||||
|
||||
// LogWriter returns an observer that logs events to the supplied writer.
|
||||
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) Exporter {
|
||||
func LogWriter(w io.Writer, onlyErrors bool) event.Exporter {
|
||||
return &logWriter{writer: w, onlyErrors: onlyErrors}
|
||||
}
|
||||
|
||||
@ -25,25 +30,26 @@ type logWriter struct {
|
||||
onlyErrors bool
|
||||
}
|
||||
|
||||
func (w *logWriter) ProcessEvent(ctx context.Context, event telemetry.Event) context.Context {
|
||||
switch event.Type {
|
||||
case telemetry.EventLog:
|
||||
if w.onlyErrors && event.Error == nil {
|
||||
func (w *logWriter) ProcessEvent(ctx context.Context, ev event.Event) context.Context {
|
||||
switch {
|
||||
case ev.IsLog():
|
||||
if w.onlyErrors && ev.Error == nil {
|
||||
return ctx
|
||||
}
|
||||
fmt.Fprintf(w.writer, "%v\n", event)
|
||||
case telemetry.EventStartSpan:
|
||||
fmt.Fprintf(w.writer, "%v\n", ev)
|
||||
case ev.IsStartSpan():
|
||||
if span := GetSpan(ctx); span != nil {
|
||||
fmt.Fprintf(w.writer, "start: %v %v", span.Name, span.ID)
|
||||
if span.ParentID.IsValid() {
|
||||
fmt.Fprintf(w.writer, "[%v]", span.ParentID)
|
||||
}
|
||||
}
|
||||
case telemetry.EventEndSpan:
|
||||
case ev.IsEndSpan():
|
||||
if span := GetSpan(ctx); span != nil {
|
||||
fmt.Fprintf(w.writer, "finish: %v %v", span.Name, span.ID)
|
||||
}
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
func (w *logWriter) Metric(context.Context, telemetry.MetricData) {}
|
||||
|
||||
func (w *logWriter) Metric(context.Context, event.MetricData) {}
|
||||
|
@ -8,13 +8,13 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/export/ocagent/wire"
|
||||
"golang.org/x/tools/internal/telemetry/metric"
|
||||
)
|
||||
|
||||
// dataToMetricDescriptor return a *wire.MetricDescriptor based on data.
|
||||
func dataToMetricDescriptor(data telemetry.MetricData) *wire.MetricDescriptor {
|
||||
func dataToMetricDescriptor(data event.MetricData) *wire.MetricDescriptor {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
@ -30,7 +30,7 @@ func dataToMetricDescriptor(data telemetry.MetricData) *wire.MetricDescriptor {
|
||||
}
|
||||
|
||||
// getDescription returns the description of data.
|
||||
func getDescription(data telemetry.MetricData) string {
|
||||
func getDescription(data event.MetricData) string {
|
||||
switch d := data.(type) {
|
||||
case *metric.Int64Data:
|
||||
return d.Info.Description
|
||||
@ -50,7 +50,7 @@ func getDescription(data telemetry.MetricData) string {
|
||||
|
||||
// getLabelKeys returns a slice of *wire.LabelKeys based on the keys
|
||||
// in data.
|
||||
func getLabelKeys(data telemetry.MetricData) []*wire.LabelKey {
|
||||
func getLabelKeys(data event.MetricData) []*wire.LabelKey {
|
||||
switch d := data.(type) {
|
||||
case *metric.Int64Data:
|
||||
return infoKeysToLabelKeys(d.Info.Keys)
|
||||
@ -70,7 +70,7 @@ func getLabelKeys(data telemetry.MetricData) []*wire.LabelKey {
|
||||
|
||||
// dataToMetricDescriptorType returns a wire.MetricDescriptor_Type based on the
|
||||
// underlying type of data.
|
||||
func dataToMetricDescriptorType(data telemetry.MetricData) wire.MetricDescriptor_Type {
|
||||
func dataToMetricDescriptorType(data event.MetricData) wire.MetricDescriptor_Type {
|
||||
switch d := data.(type) {
|
||||
case *metric.Int64Data:
|
||||
if d.IsGauge {
|
||||
@ -96,7 +96,7 @@ func dataToMetricDescriptorType(data telemetry.MetricData) wire.MetricDescriptor
|
||||
|
||||
// dataToTimeseries returns a slice of *wire.TimeSeries based on the
|
||||
// points in data.
|
||||
func dataToTimeseries(data telemetry.MetricData, start time.Time) []*wire.TimeSeries {
|
||||
func dataToTimeseries(data event.MetricData, start time.Time) []*wire.TimeSeries {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
@ -117,7 +117,7 @@ func dataToTimeseries(data telemetry.MetricData, start time.Time) []*wire.TimeSe
|
||||
}
|
||||
|
||||
// numRows returns the number of rows in data.
|
||||
func numRows(data telemetry.MetricData) int {
|
||||
func numRows(data event.MetricData) int {
|
||||
switch d := data.(type) {
|
||||
case *metric.Int64Data:
|
||||
return len(d.Rows)
|
||||
@ -134,7 +134,7 @@ func numRows(data telemetry.MetricData) int {
|
||||
|
||||
// dataToPoints returns an array of *wire.Points based on the point(s)
|
||||
// in data at index i.
|
||||
func dataToPoints(data telemetry.MetricData, i int) []*wire.Point {
|
||||
func dataToPoints(data event.MetricData, i int) []*wire.Point {
|
||||
switch d := data.(type) {
|
||||
case *metric.Int64Data:
|
||||
timestamp := convertTimestamp(*d.EndTime)
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/metric"
|
||||
)
|
||||
|
||||
@ -16,7 +16,7 @@ func TestEncodeMetric(t *testing.T) {
|
||||
const suffix = `]}`
|
||||
tests := []struct {
|
||||
name string
|
||||
data telemetry.MetricData
|
||||
data event.MetricData
|
||||
want string
|
||||
}{
|
||||
{
|
||||
|
@ -18,10 +18,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
"golang.org/x/tools/internal/telemetry/export/ocagent/wire"
|
||||
"golang.org/x/tools/internal/telemetry/tag"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@ -47,7 +46,7 @@ type Exporter struct {
|
||||
mu sync.Mutex
|
||||
config Config
|
||||
spans []*export.Span
|
||||
metrics []telemetry.MetricData
|
||||
metrics []event.MetricData
|
||||
}
|
||||
|
||||
// Connect creates a process specific exporter with the specified
|
||||
@ -85,8 +84,8 @@ func Connect(config *Config) *Exporter {
|
||||
return exporter
|
||||
}
|
||||
|
||||
func (e *Exporter) ProcessEvent(ctx context.Context, event telemetry.Event) context.Context {
|
||||
if event.Type != telemetry.EventEndSpan {
|
||||
func (e *Exporter) ProcessEvent(ctx context.Context, ev event.Event) context.Context {
|
||||
if !ev.IsEndSpan() {
|
||||
return ctx
|
||||
}
|
||||
e.mu.Lock()
|
||||
@ -98,7 +97,7 @@ func (e *Exporter) ProcessEvent(ctx context.Context, event telemetry.Event) cont
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (e *Exporter) Metric(ctx context.Context, data telemetry.MetricData) {
|
||||
func (e *Exporter) Metric(ctx context.Context, data event.MetricData) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
e.metrics = append(e.metrics, data)
|
||||
@ -212,7 +211,7 @@ func convertSpan(span *export.Span) *wire.Span {
|
||||
return result
|
||||
}
|
||||
|
||||
func convertMetric(data telemetry.MetricData, start time.Time) *wire.Metric {
|
||||
func convertMetric(data event.MetricData, start time.Time) *wire.Metric {
|
||||
descriptor := dataToMetricDescriptor(data)
|
||||
timeseries := dataToTimeseries(data, start)
|
||||
|
||||
@ -228,7 +227,7 @@ func convertMetric(data telemetry.MetricData, start time.Time) *wire.Metric {
|
||||
}
|
||||
}
|
||||
|
||||
func convertAttributes(tags telemetry.TagList) *wire.Attributes {
|
||||
func convertAttributes(tags event.TagList) *wire.Attributes {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -274,7 +273,7 @@ func convertAttribute(v interface{}) wire.Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
func convertEvents(events []telemetry.Event) *wire.TimeEvents {
|
||||
func convertEvents(events []event.Event) *wire.TimeEvents {
|
||||
//TODO: MessageEvents?
|
||||
result := make([]wire.TimeEvent, len(events))
|
||||
for i, event := range events {
|
||||
@ -283,22 +282,22 @@ func convertEvents(events []telemetry.Event) *wire.TimeEvents {
|
||||
return &wire.TimeEvents{TimeEvent: result}
|
||||
}
|
||||
|
||||
func convertEvent(event telemetry.Event) wire.TimeEvent {
|
||||
func convertEvent(ev event.Event) wire.TimeEvent {
|
||||
return wire.TimeEvent{
|
||||
Time: convertTimestamp(event.At),
|
||||
Annotation: convertAnnotation(event),
|
||||
Time: convertTimestamp(ev.At),
|
||||
Annotation: convertAnnotation(ev),
|
||||
}
|
||||
}
|
||||
|
||||
func convertAnnotation(event telemetry.Event) *wire.Annotation {
|
||||
description := event.Message
|
||||
if description == "" && event.Error != nil {
|
||||
description = event.Error.Error()
|
||||
event.Error = nil
|
||||
func convertAnnotation(ev event.Event) *wire.Annotation {
|
||||
description := ev.Message
|
||||
if description == "" && ev.Error != nil {
|
||||
description = ev.Error.Error()
|
||||
ev.Error = nil
|
||||
}
|
||||
tags := event.Tags
|
||||
if event.Error != nil {
|
||||
tags = append(tags, tag.Of("error", event.Error))
|
||||
tags := ev.Tags
|
||||
if ev.Error != nil {
|
||||
tags = append(tags, event.TagOf("error", ev.Error))
|
||||
}
|
||||
if description == "" && len(tags) == 0 {
|
||||
return nil
|
||||
|
@ -16,10 +16,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
"golang.org/x/tools/internal/telemetry/export/ocagent"
|
||||
"golang.org/x/tools/internal/telemetry/tag"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -79,13 +78,13 @@ func TestEvents(t *testing.T) {
|
||||
}`
|
||||
tests := []struct {
|
||||
name string
|
||||
event func(ctx context.Context) telemetry.Event
|
||||
event func(ctx context.Context) event.Event
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "no tags",
|
||||
event: func(ctx context.Context) telemetry.Event {
|
||||
return telemetry.Event{
|
||||
event: func(ctx context.Context) event.Event {
|
||||
return event.Event{
|
||||
At: at,
|
||||
}
|
||||
},
|
||||
@ -95,12 +94,12 @@ func TestEvents(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "description no error",
|
||||
event: func(ctx context.Context) telemetry.Event {
|
||||
return telemetry.Event{
|
||||
event: func(ctx context.Context) event.Event {
|
||||
return event.Event{
|
||||
At: at,
|
||||
Message: "cache miss",
|
||||
Tags: telemetry.TagList{
|
||||
tag.Of("db", "godb"),
|
||||
Tags: event.TagList{
|
||||
event.TagOf("db", "godb"),
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -116,13 +115,13 @@ func TestEvents(t *testing.T) {
|
||||
|
||||
{
|
||||
name: "description and error",
|
||||
event: func(ctx context.Context) telemetry.Event {
|
||||
return telemetry.Event{
|
||||
event: func(ctx context.Context) event.Event {
|
||||
return event.Event{
|
||||
At: at,
|
||||
Message: "cache miss",
|
||||
Error: errors.New("no network connectivity"),
|
||||
Tags: telemetry.TagList{
|
||||
tag.Of("db", "godb"), // must come before e
|
||||
Tags: event.TagList{
|
||||
event.TagOf("db", "godb"), // must come before e
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -138,12 +137,12 @@ func TestEvents(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "no description, but error",
|
||||
event: func(ctx context.Context) telemetry.Event {
|
||||
return telemetry.Event{
|
||||
event: func(ctx context.Context) event.Event {
|
||||
return event.Event{
|
||||
At: at,
|
||||
Error: errors.New("no network connectivity"),
|
||||
Tags: telemetry.TagList{
|
||||
tag.Of("db", "godb"),
|
||||
Tags: event.TagList{
|
||||
event.TagOf("db", "godb"),
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -158,31 +157,31 @@ func TestEvents(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "enumerate all attribute types",
|
||||
event: func(ctx context.Context) telemetry.Event {
|
||||
return telemetry.Event{
|
||||
event: func(ctx context.Context) event.Event {
|
||||
return event.Event{
|
||||
At: at,
|
||||
Message: "cache miss",
|
||||
Tags: telemetry.TagList{
|
||||
tag.Of("1_db", "godb"),
|
||||
Tags: event.TagList{
|
||||
event.TagOf("1_db", "godb"),
|
||||
|
||||
tag.Of("2a_age", 0.456), // Constant converted into "float64"
|
||||
tag.Of("2b_ttl", float32(5000)),
|
||||
tag.Of("2c_expiry_ms", float64(1e3)),
|
||||
event.TagOf("2a_age", 0.456), // Constant converted into "float64"
|
||||
event.TagOf("2b_ttl", float32(5000)),
|
||||
event.TagOf("2c_expiry_ms", float64(1e3)),
|
||||
|
||||
tag.Of("3a_retry", false),
|
||||
tag.Of("3b_stale", true),
|
||||
event.TagOf("3a_retry", false),
|
||||
event.TagOf("3b_stale", true),
|
||||
|
||||
tag.Of("4a_max", 0x7fff), // Constant converted into "int"
|
||||
tag.Of("4b_opcode", int8(0x7e)),
|
||||
tag.Of("4c_base", int16(1<<9)),
|
||||
tag.Of("4e_checksum", int32(0x11f7e294)),
|
||||
tag.Of("4f_mode", int64(0644)),
|
||||
event.TagOf("4a_max", 0x7fff), // Constant converted into "int"
|
||||
event.TagOf("4b_opcode", int8(0x7e)),
|
||||
event.TagOf("4c_base", int16(1<<9)),
|
||||
event.TagOf("4e_checksum", int32(0x11f7e294)),
|
||||
event.TagOf("4f_mode", int64(0644)),
|
||||
|
||||
tag.Of("5a_min", uint(1)),
|
||||
tag.Of("5b_mix", uint8(44)),
|
||||
tag.Of("5c_port", uint16(55678)),
|
||||
tag.Of("5d_min_hops", uint32(1<<9)),
|
||||
tag.Of("5e_max_hops", uint64(0xffffff)),
|
||||
event.TagOf("5a_min", uint(1)),
|
||||
event.TagOf("5b_mix", uint8(44)),
|
||||
event.TagOf("5c_port", uint16(55678)),
|
||||
event.TagOf("5d_min_hops", uint32(1<<9)),
|
||||
event.TagOf("5e_max_hops", uint64(0xffffff)),
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -214,19 +213,19 @@ func TestEvents(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
startEvent := telemetry.Event{
|
||||
Type: telemetry.EventStartSpan,
|
||||
startEvent := event.Event{
|
||||
Type: event.StartSpanType,
|
||||
Message: "event span",
|
||||
At: start,
|
||||
}
|
||||
endEvent := telemetry.Event{
|
||||
Type: telemetry.EventEndSpan,
|
||||
endEvent := event.Event{
|
||||
Type: event.EndSpanType,
|
||||
At: end,
|
||||
}
|
||||
ctx := export.ContextSpan(ctx, startEvent)
|
||||
span := export.GetSpan(ctx)
|
||||
span.ID = export.SpanContext{}
|
||||
span.Events = []telemetry.Event{tt.event(ctx)}
|
||||
span.Events = []event.Event{tt.event(ctx)}
|
||||
exporter.ProcessEvent(ctx, startEvent)
|
||||
export.ContextSpan(ctx, endEvent)
|
||||
exporter.ProcessEvent(ctx, endEvent)
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/metric"
|
||||
)
|
||||
|
||||
@ -22,10 +22,10 @@ func New() *Exporter {
|
||||
|
||||
type Exporter struct {
|
||||
mu sync.Mutex
|
||||
metrics []telemetry.MetricData
|
||||
metrics []event.MetricData
|
||||
}
|
||||
|
||||
func (e *Exporter) Metric(ctx context.Context, data telemetry.MetricData) {
|
||||
func (e *Exporter) Metric(ctx context.Context, data event.MetricData) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
name := data.Handle()
|
||||
@ -38,7 +38,7 @@ func (e *Exporter) Metric(ctx context.Context, data telemetry.MetricData) {
|
||||
if index >= len(e.metrics) || e.metrics[index].Handle() != name {
|
||||
// we have a new metric, so we need to make a space for it
|
||||
old := e.metrics
|
||||
e.metrics = make([]telemetry.MetricData, len(old)+1)
|
||||
e.metrics = make([]event.MetricData, len(old)+1)
|
||||
copy(e.metrics, old[:index])
|
||||
copy(e.metrics[index+1:], old[index:])
|
||||
}
|
||||
@ -57,7 +57,7 @@ func (e *Exporter) header(w http.ResponseWriter, name, description string, isGau
|
||||
fmt.Fprintf(w, "# TYPE %s %s\n", name, kind)
|
||||
}
|
||||
|
||||
func (e *Exporter) row(w http.ResponseWriter, name string, group telemetry.TagList, extra string, value interface{}) {
|
||||
func (e *Exporter) row(w http.ResponseWriter, name string, group event.TagList, extra string, value interface{}) {
|
||||
fmt.Fprint(w, name)
|
||||
buf := &bytes.Buffer{}
|
||||
fmt.Fprint(buf, group)
|
||||
|
@ -7,17 +7,16 @@ package export
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
)
|
||||
|
||||
// Tag returns a context updated with tag values from the event.
|
||||
// It ignores events that are not or type EventTag or EventStartSpan.
|
||||
func Tag(ctx context.Context, event telemetry.Event) context.Context {
|
||||
// It ignores events that are not or type IsTag or IsStartSpan.
|
||||
func Tag(ctx context.Context, ev event.Event) context.Context {
|
||||
//TODO: Do we need to do something more efficient than just store tags
|
||||
//TODO: directly on the context?
|
||||
switch event.Type {
|
||||
case telemetry.EventTag, telemetry.EventStartSpan:
|
||||
for _, t := range event.Tags {
|
||||
if ev.IsTag() || ev.IsStartSpan() {
|
||||
for _, t := range ev.Tags {
|
||||
ctx = context.WithValue(ctx, t.Key, t.Value)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
)
|
||||
|
||||
type SpanContext struct {
|
||||
@ -23,8 +23,8 @@ type Span struct {
|
||||
ParentID SpanID
|
||||
Start time.Time
|
||||
Finish time.Time
|
||||
Tags telemetry.TagList
|
||||
Events []telemetry.Event
|
||||
Tags event.TagList
|
||||
Events []event.Event
|
||||
}
|
||||
|
||||
type contextKeyType int
|
||||
@ -46,17 +46,17 @@ func GetSpan(ctx context.Context) *Span {
|
||||
// It creates new spans on EventStartSpan, adds events to the current span on
|
||||
// EventLog or EventTag, and closes the span on EventEndSpan.
|
||||
// The span structure can then be used by other exporters.
|
||||
func ContextSpan(ctx context.Context, event telemetry.Event) context.Context {
|
||||
switch event.Type {
|
||||
case telemetry.EventLog, telemetry.EventTag:
|
||||
func ContextSpan(ctx context.Context, ev event.Event) context.Context {
|
||||
switch {
|
||||
case ev.IsLog(), ev.IsTag():
|
||||
if span := GetSpan(ctx); span != nil {
|
||||
span.Events = append(span.Events, event)
|
||||
span.Events = append(span.Events, ev)
|
||||
}
|
||||
case telemetry.EventStartSpan:
|
||||
case ev.IsStartSpan():
|
||||
span := &Span{
|
||||
Name: event.Message,
|
||||
Start: event.At,
|
||||
Tags: event.Tags,
|
||||
Name: ev.Message,
|
||||
Start: ev.At,
|
||||
Tags: ev.Tags,
|
||||
}
|
||||
if parent := GetSpan(ctx); parent != nil {
|
||||
span.ID.TraceID = parent.ID.TraceID
|
||||
@ -66,11 +66,11 @@ func ContextSpan(ctx context.Context, event telemetry.Event) context.Context {
|
||||
}
|
||||
span.ID.SpanID = newSpanID()
|
||||
ctx = context.WithValue(ctx, spanContextKey, span)
|
||||
case telemetry.EventEndSpan:
|
||||
case ev.IsEndSpan():
|
||||
if span := GetSpan(ctx); span != nil {
|
||||
span.Finish = event.At
|
||||
span.Finish = ev.At
|
||||
}
|
||||
case telemetry.EventDetach:
|
||||
case ev.IsDetach():
|
||||
return context.WithValue(ctx, spanContextKey, nil)
|
||||
}
|
||||
return ctx
|
||||
|
@ -6,54 +6,10 @@
|
||||
// with both the lsp protocol and the other telemetry packages.
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
import "golang.org/x/tools/internal/telemetry/event"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
var (
|
||||
With = event.Log
|
||||
Print = event.Print
|
||||
Error = event.Error
|
||||
)
|
||||
|
||||
type Event telemetry.Event
|
||||
|
||||
// With sends a tag list to the installed loggers.
|
||||
func With(ctx context.Context, tags ...telemetry.Tag) {
|
||||
export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventLog,
|
||||
At: time.Now(),
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
// Print takes a message and a tag list and combines them into a single tag
|
||||
// list before delivering them to the loggers.
|
||||
func Print(ctx context.Context, message string, tags ...telemetry.Tag) {
|
||||
export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventLog,
|
||||
At: time.Now(),
|
||||
Message: message,
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
// Error takes a message and a tag list and combines them into a single tag
|
||||
// list before delivering them to the loggers. It captures the error in the
|
||||
// delivered event.
|
||||
func Error(ctx context.Context, message string, err error, tags ...telemetry.Tag) {
|
||||
if err == nil {
|
||||
err = errorString(message)
|
||||
message = ""
|
||||
}
|
||||
export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventLog,
|
||||
At: time.Now(),
|
||||
Message: message,
|
||||
Error: err,
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
type errorString string
|
||||
|
||||
// Error allows errorString to conform to the error interface.
|
||||
func (err errorString) Error() string { return string(err) }
|
||||
|
@ -10,10 +10,8 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
"golang.org/x/tools/internal/telemetry/stats"
|
||||
"golang.org/x/tools/internal/telemetry/tag"
|
||||
)
|
||||
|
||||
// Scalar represents the construction information for a scalar metric.
|
||||
@ -134,7 +132,7 @@ type Int64Data struct {
|
||||
// End is the last time this metric was updated.
|
||||
EndTime *time.Time
|
||||
|
||||
groups []telemetry.TagList
|
||||
groups []event.TagList
|
||||
}
|
||||
|
||||
// Float64Data is a concrete implementation of Data for float64 scalar metrics.
|
||||
@ -148,7 +146,7 @@ type Float64Data struct {
|
||||
// End is the last time this metric was updated.
|
||||
EndTime *time.Time
|
||||
|
||||
groups []telemetry.TagList
|
||||
groups []event.TagList
|
||||
}
|
||||
|
||||
// HistogramInt64Data is a concrete implementation of Data for int64 histogram metrics.
|
||||
@ -160,7 +158,7 @@ type HistogramInt64Data struct {
|
||||
// End is the last time this metric was updated.
|
||||
EndTime *time.Time
|
||||
|
||||
groups []telemetry.TagList
|
||||
groups []event.TagList
|
||||
}
|
||||
|
||||
// HistogramInt64Row holds the values for a single row of a HistogramInt64Data.
|
||||
@ -186,7 +184,7 @@ type HistogramFloat64Data struct {
|
||||
// End is the last time this metric was updated.
|
||||
EndTime *time.Time
|
||||
|
||||
groups []telemetry.TagList
|
||||
groups []event.TagList
|
||||
}
|
||||
|
||||
// HistogramFloat64Row holds the values for a single row of a HistogramFloat64Data.
|
||||
@ -203,8 +201,8 @@ type HistogramFloat64Row struct {
|
||||
Max float64
|
||||
}
|
||||
|
||||
func getGroup(ctx context.Context, g *[]telemetry.TagList, keys []interface{}) (int, bool) {
|
||||
group := tag.Get(ctx, keys...)
|
||||
func getGroup(ctx context.Context, g *[]event.TagList, keys []interface{}) (int, bool) {
|
||||
group := event.Tags(ctx, keys...)
|
||||
old := *g
|
||||
index := sort.Search(len(old), func(i int) bool {
|
||||
return !old[i].Less(group)
|
||||
@ -213,15 +211,15 @@ func getGroup(ctx context.Context, g *[]telemetry.TagList, keys []interface{}) (
|
||||
// not a new group
|
||||
return index, false
|
||||
}
|
||||
*g = make([]telemetry.TagList, len(old)+1)
|
||||
*g = make([]event.TagList, len(old)+1)
|
||||
copy(*g, old[:index])
|
||||
copy((*g)[index+1:], old[index:])
|
||||
(*g)[index] = group
|
||||
return index, true
|
||||
}
|
||||
|
||||
func (data *Int64Data) Handle() string { return data.Info.Name }
|
||||
func (data *Int64Data) Groups() []telemetry.TagList { return data.groups }
|
||||
func (data *Int64Data) Handle() string { return data.Info.Name }
|
||||
func (data *Int64Data) Groups() []event.TagList { return data.groups }
|
||||
|
||||
func (data *Int64Data) modify(ctx context.Context, at time.Time, f func(v int64) int64) {
|
||||
index, insert := getGroup(ctx, &data.groups, data.Info.Keys)
|
||||
@ -237,7 +235,7 @@ func (data *Int64Data) modify(ctx context.Context, at time.Time, f func(v int64)
|
||||
data.Rows[index] = f(data.Rows[index])
|
||||
data.EndTime = &at
|
||||
frozen := *data
|
||||
export.Metric(ctx, &frozen)
|
||||
event.Metric(ctx, &frozen)
|
||||
}
|
||||
|
||||
func (data *Int64Data) countInt64(ctx context.Context, measure *stats.Int64Measure, value int64, at time.Time) {
|
||||
@ -256,8 +254,8 @@ func (data *Int64Data) latest(ctx context.Context, measure *stats.Int64Measure,
|
||||
data.modify(ctx, at, func(v int64) int64 { return value })
|
||||
}
|
||||
|
||||
func (data *Float64Data) Handle() string { return data.Info.Name }
|
||||
func (data *Float64Data) Groups() []telemetry.TagList { return data.groups }
|
||||
func (data *Float64Data) Handle() string { return data.Info.Name }
|
||||
func (data *Float64Data) Groups() []event.TagList { return data.groups }
|
||||
|
||||
func (data *Float64Data) modify(ctx context.Context, at time.Time, f func(v float64) float64) {
|
||||
index, insert := getGroup(ctx, &data.groups, data.Info.Keys)
|
||||
@ -273,7 +271,7 @@ func (data *Float64Data) modify(ctx context.Context, at time.Time, f func(v floa
|
||||
data.Rows[index] = f(data.Rows[index])
|
||||
data.EndTime = &at
|
||||
frozen := *data
|
||||
export.Metric(ctx, &frozen)
|
||||
event.Metric(ctx, &frozen)
|
||||
}
|
||||
|
||||
func (data *Float64Data) sum(ctx context.Context, measure *stats.Float64Measure, value float64, at time.Time) {
|
||||
@ -284,8 +282,8 @@ func (data *Float64Data) latest(ctx context.Context, measure *stats.Float64Measu
|
||||
data.modify(ctx, at, func(v float64) float64 { return value })
|
||||
}
|
||||
|
||||
func (data *HistogramInt64Data) Handle() string { return data.Info.Name }
|
||||
func (data *HistogramInt64Data) Groups() []telemetry.TagList { return data.groups }
|
||||
func (data *HistogramInt64Data) Handle() string { return data.Info.Name }
|
||||
func (data *HistogramInt64Data) Groups() []event.TagList { return data.groups }
|
||||
|
||||
func (data *HistogramInt64Data) modify(ctx context.Context, at time.Time, f func(v *HistogramInt64Row)) {
|
||||
index, insert := getGroup(ctx, &data.groups, data.Info.Keys)
|
||||
@ -307,7 +305,7 @@ func (data *HistogramInt64Data) modify(ctx context.Context, at time.Time, f func
|
||||
data.Rows[index] = &v
|
||||
data.EndTime = &at
|
||||
frozen := *data
|
||||
export.Metric(ctx, &frozen)
|
||||
event.Metric(ctx, &frozen)
|
||||
}
|
||||
|
||||
func (data *HistogramInt64Data) record(ctx context.Context, measure *stats.Int64Measure, value int64, at time.Time) {
|
||||
@ -328,8 +326,8 @@ func (data *HistogramInt64Data) record(ctx context.Context, measure *stats.Int64
|
||||
})
|
||||
}
|
||||
|
||||
func (data *HistogramFloat64Data) Handle() string { return data.Info.Name }
|
||||
func (data *HistogramFloat64Data) Groups() []telemetry.TagList { return data.groups }
|
||||
func (data *HistogramFloat64Data) Handle() string { return data.Info.Name }
|
||||
func (data *HistogramFloat64Data) Groups() []event.TagList { return data.groups }
|
||||
|
||||
func (data *HistogramFloat64Data) modify(ctx context.Context, at time.Time, f func(v *HistogramFloat64Row)) {
|
||||
index, insert := getGroup(ctx, &data.groups, data.Info.Keys)
|
||||
@ -351,7 +349,7 @@ func (data *HistogramFloat64Data) modify(ctx context.Context, at time.Time, f fu
|
||||
data.Rows[index] = &v
|
||||
data.EndTime = &at
|
||||
frozen := *data
|
||||
export.Metric(ctx, &frozen)
|
||||
event.Metric(ctx, &frozen)
|
||||
}
|
||||
|
||||
func (data *HistogramFloat64Data) record(ctx context.Context, measure *stats.Float64Measure, value float64, at time.Time) {
|
||||
|
@ -8,27 +8,13 @@
|
||||
package tag
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
)
|
||||
|
||||
// With delivers the tag list to the telemetry exporter.
|
||||
func With(ctx context.Context, tags ...telemetry.Tag) context.Context {
|
||||
return export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventTag,
|
||||
At: time.Now(),
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
type Key = event.Key
|
||||
|
||||
// Get collects a set of values from the context and returns them as a tag list.
|
||||
func Get(ctx context.Context, keys ...interface{}) telemetry.TagList {
|
||||
tags := make(telemetry.TagList, len(keys))
|
||||
for i, key := range keys {
|
||||
tags[i] = telemetry.Tag{Key: key, Value: ctx.Value(key)}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
var (
|
||||
With = event.Label
|
||||
Get = event.Tags
|
||||
Of = event.TagOf
|
||||
)
|
||||
|
@ -6,33 +6,10 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/telemetry"
|
||||
"golang.org/x/tools/internal/telemetry/export"
|
||||
"golang.org/x/tools/internal/telemetry/event"
|
||||
)
|
||||
|
||||
func StartSpan(ctx context.Context, name string, tags ...telemetry.Tag) (context.Context, func()) {
|
||||
ctx = export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventStartSpan,
|
||||
Message: name,
|
||||
At: time.Now(),
|
||||
Tags: tags,
|
||||
})
|
||||
return ctx, func() {
|
||||
export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventEndSpan,
|
||||
At: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Detach returns a context without an associated span.
|
||||
// This allows the creation of spans that are not children of the current span.
|
||||
func Detach(ctx context.Context) context.Context {
|
||||
return export.ProcessEvent(ctx, telemetry.Event{
|
||||
Type: telemetry.EventDetach,
|
||||
At: time.Now(),
|
||||
})
|
||||
}
|
||||
var (
|
||||
StartSpan = event.StartSpan
|
||||
Detach = event.Detach
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user