mirror of
https://github.com/golang/go
synced 2024-11-05 23:26:18 -07:00
fd4102a86c
This changes span events to return a cheaper end function if there is no exporter and also to deliver the end event to the same exporter that the start even was delivered to rather than which was active when the end event is triggered. Change-Id: I831283da20e8cc991a0cf7490952ae194d125428 Reviewed-on: https://go-review.googlesource.com/c/tools/+/225737 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
69 lines
2.2 KiB
Go
69 lines
2.2 KiB
Go
// 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"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
// Exporter is a function that handles events.
|
|
// It may return a modified context and event.
|
|
type Exporter func(context.Context, Event, TagMap) context.Context
|
|
|
|
var (
|
|
exporter unsafe.Pointer
|
|
)
|
|
|
|
// SetExporter sets the global exporter function that handles all events.
|
|
// The exporter is called synchronously from the event call site, so it should
|
|
// return quickly so as not to hold up user code.
|
|
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 function
|
|
// also a nil pointer
|
|
p = nil
|
|
}
|
|
atomic.StorePointer(&exporter, p)
|
|
}
|
|
|
|
// deliver is called to deliver an event to the supplied exporter.
|
|
// it will fill in the time and generate the basic tag source.
|
|
func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context {
|
|
// add the current time to the event
|
|
ev.At = time.Now()
|
|
// hand the event off to the current exporter
|
|
return exporter(ctx, ev, ev.Map())
|
|
}
|
|
|
|
// dispatch is called to deliver an event to the global exporter if set.
|
|
func dispatch(ctx context.Context, ev Event) context.Context {
|
|
// get the global exporter and abort early if there is not one
|
|
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
|
if exporterPtr == nil {
|
|
return ctx
|
|
}
|
|
return deliver(ctx, *exporterPtr, ev)
|
|
}
|
|
|
|
// dispatchPair is called to deliver a start event to the supplied exporter.
|
|
// It also returns a function that will deliver the end event to the same
|
|
// exporter.
|
|
// it will fill in the time and generate the basic tag source.
|
|
func dispatchPair(ctx context.Context, begin, end Event) (context.Context, func()) {
|
|
// get the global exporter and abort early if there is not one
|
|
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
|
if exporterPtr == nil {
|
|
return ctx, func() {}
|
|
}
|
|
ctx = deliver(ctx, *exporterPtr, begin)
|
|
return ctx, func() { deliver(ctx, *exporterPtr, end) }
|
|
}
|