|  | // 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. | 
|  |  | 
|  | //go:build !disable_events | 
|  |  | 
|  | package event | 
|  |  | 
|  | import ( | 
|  | "context" | 
|  | "sync" | 
|  | "sync/atomic" | 
|  | "time" | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | // Exporter synchronizes the delivery of events to handlers. | 
|  | type Exporter struct { | 
|  | lastEvent uint64 // accessed using atomic, must be 64 bit aligned | 
|  | opts      ExporterOptions | 
|  |  | 
|  | mu      sync.Mutex | 
|  | handler Handler | 
|  | sources sources | 
|  | } | 
|  |  | 
|  | // target is a bound exporter. | 
|  | // Normally you get a target by looking in the context using To. | 
|  | type target struct { | 
|  | exporter  *Exporter | 
|  | parent    uint64 | 
|  | startTime time.Time // for trace latency | 
|  | } | 
|  |  | 
|  | type ExporterOptions struct { | 
|  | // If non-nil, sets zero Event.At on delivery. | 
|  | Now func() time.Time | 
|  |  | 
|  | // Disable some event types, for better performance. | 
|  | DisableLogging     bool | 
|  | DisableTracing     bool | 
|  | DisableAnnotations bool | 
|  | DisableMetrics     bool | 
|  |  | 
|  | // Enable automatically setting the event Namespace to the calling package's | 
|  | // import path. | 
|  | EnableNamespaces bool | 
|  | } | 
|  |  | 
|  | // contextKeyType is used as the key for storing a contextValue on the context. | 
|  | type contextKeyType struct{} | 
|  |  | 
|  | var contextKey interface{} = contextKeyType{} | 
|  |  | 
|  | var ( | 
|  | defaultTarget unsafe.Pointer | 
|  | ) | 
|  |  | 
|  | // NewExporter creates an Exporter using the supplied handler and options. | 
|  | // Event delivery is serialized to enable safe atomic handling. | 
|  | func NewExporter(handler Handler, opts *ExporterOptions) *Exporter { | 
|  | if handler == nil { | 
|  | panic("handler must not be nil") | 
|  | } | 
|  | e := &Exporter{ | 
|  | handler: handler, | 
|  | sources: newCallers(), | 
|  | } | 
|  | if opts != nil { | 
|  | e.opts = *opts | 
|  | } | 
|  | if e.opts.Now == nil { | 
|  | e.opts.Now = time.Now | 
|  | } | 
|  | return e | 
|  | } | 
|  |  | 
|  | func setDefaultExporter(e *Exporter) { | 
|  | atomic.StorePointer(&defaultTarget, unsafe.Pointer(&target{exporter: e})) | 
|  | } | 
|  |  | 
|  | func getDefaultTarget() *target { | 
|  | return (*target)(atomic.LoadPointer(&defaultTarget)) | 
|  | } | 
|  |  | 
|  | func newContext(ctx context.Context, exporter *Exporter, parent uint64, start time.Time) context.Context { | 
|  | var t *target | 
|  | if exporter != nil { | 
|  | t = &target{exporter: exporter, parent: parent, startTime: start} | 
|  | } | 
|  | return context.WithValue(ctx, contextKey, t) | 
|  | } | 
|  |  | 
|  | // prepare events before delivering to the underlying handler. | 
|  | // it is safe to call this more than once (trace events have to call it early) | 
|  | // If the event does not have a timestamp, and the exporter has a Now function | 
|  | // then the timestamp will be updated. | 
|  | // If automatic namespaces are enabled and the event doesn't have a namespace, | 
|  | // one based on the caller's import path will be provided. | 
|  | func (ev *Event) prepare() { | 
|  | e := ev.target.exporter | 
|  | if ev.ID == 0 { | 
|  | ev.ID = atomic.AddUint64(&e.lastEvent, 1) | 
|  | } | 
|  | if e.opts.Now != nil && ev.At.IsZero() { | 
|  | ev.At = e.opts.Now() | 
|  | } | 
|  | if e.opts.EnableNamespaces && ev.Source.Space == "" { | 
|  | ev.Source = e.sources.scanStack() | 
|  | } | 
|  | } | 
|  |  | 
|  | func (e *Exporter) loggingEnabled() bool     { return !e.opts.DisableLogging } | 
|  | func (e *Exporter) annotationsEnabled() bool { return !e.opts.DisableAnnotations } | 
|  | func (e *Exporter) tracingEnabled() bool     { return !e.opts.DisableTracing } | 
|  | func (e *Exporter) metricsEnabled() bool     { return !e.opts.DisableMetrics } |