forked from remind101/empire
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tx.go
130 lines (112 loc) · 2.9 KB
/
tx.go
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
118
119
120
121
122
123
124
125
126
127
128
129
130
package newrelic
import "golang.org/x/net/context"
// Tx represents a transaction.
type Tx interface {
Start() error
End() error
StartGeneric(name string) error
StartDatastore(table, operation, sql, rollupName string) error
StartExternal(host, name string) error
EndSegment() error
ReportError(exceptionType, errorMessage, stackTrace, stackFrameDelim string) error
}
// tx implements the Tx interface.
type tx struct {
Tracer TxTracer
Reporter TxReporter
id int64
name string
url string
ss *SegmentStack
}
// NewTx returns a new transaction.
func NewTx(name string) *tx {
return &tx{
Tracer: &NRTxTracer{},
Reporter: &NRTxReporter{},
name: name,
ss: NewSegmentStack(),
}
}
// NewRequestTx returns a new transaction with a request url.
func NewRequestTx(name string, url string) *tx {
t := NewTx(name)
t.url = url
return t
}
// Start starts a transaction, setting the id.
func (t *tx) Start() error {
var err error
if t.id != 0 {
return ErrTxAlreadyStarted
}
if t.id, err = t.Tracer.BeginTransaction(); err != nil {
return err
}
if err = t.Tracer.SetTransactionName(t.id, t.name); err != nil {
return err
}
if t.url != "" {
return t.Tracer.SetTransactionRequestURL(t.id, t.url)
}
return nil
}
// End ends a transaction.
func (t *tx) End() error {
for t.ss.Peek() != rootSegment {
t.EndSegment()
}
return t.Tracer.EndTransaction(t.id)
}
// StartGeneric starts a generic segment.
func (t *tx) StartGeneric(name string) error {
id, err := t.Tracer.BeginGenericSegment(t.id, t.ss.Peek(), name)
if err != nil {
return err
}
t.ss.Push(id)
return nil
}
// StartDatastore starts a datastore segment.
func (t *tx) StartDatastore(table, operation, sql, rollupName string) error {
id, err := t.Tracer.BeginDatastoreSegment(t.id, t.ss.Peek(), table, operation, sql, rollupName)
if err != nil {
return err
}
t.ss.Push(id)
return nil
}
// StartExternal starts an external segment.
func (t *tx) StartExternal(host, name string) error {
id, err := t.Tracer.BeginExternalSegment(t.id, t.ss.Peek(), host, name)
if err != nil {
return err
}
t.ss.Push(id)
return nil
}
// EndSegment ends the segment at the top of the stack.
func (t *tx) EndSegment() error {
if id, ok := t.ss.Pop(); ok {
return t.Tracer.EndSegment(t.id, id)
}
return nil
}
// ReportError reports an error that occured during the transaction.
func (t *tx) ReportError(exceptionType, errorMessage, stackTrace, stackFrameDelim string) error {
_, err := t.Reporter.ReportError(t.id, exceptionType, errorMessage, stackTrace, stackFrameDelim)
return err
}
// WithTx inserts a newrelic.Tx into the provided context.
func WithTx(ctx context.Context, t Tx) context.Context {
return context.WithValue(ctx, txKey, t)
}
// FromContext returns a newrelic.Tx from the context.
func FromContext(ctx context.Context) (Tx, bool) {
t, ok := ctx.Value(txKey).(Tx)
return t, ok
}
type key int
const (
txKey key = iota
)