File: export.go

package info (click to toggle)
golang-golang-x-exp 0.0~git20230522.2e198f4-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 6,404 kB
  • sloc: ansic: 1,900; objc: 276; sh: 272; asm: 48; makefile: 26
file content (117 lines) | stat: -rw-r--r-- 3,210 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// 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
// +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 }