forked from newrelic/go-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
segments.go
203 lines (177 loc) · 7.02 KB
/
segments.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// Copyright 2020 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package newrelic
import (
"net/http"
)
// SegmentStartTime is created by Transaction.StartSegmentNow and marks the
// beginning of a segment. A segment with a zero-valued SegmentStartTime may
// safely be ended.
type SegmentStartTime struct{ segment }
// Segment is used to instrument functions, methods, and blocks of code. The
// easiest way use Segment is the StartSegment function.
type Segment struct {
StartTime SegmentStartTime
Name string
}
// DatastoreSegment is used to instrument calls to databases and object stores.
type DatastoreSegment struct {
// StartTime should be assigned using StartSegmentNow before each datastore
// call is made.
StartTime SegmentStartTime
// Product, Collection, and Operation are highly recommended as they are
// used for aggregate metrics:
//
// Product is the datastore type. See the constants in
// https://github.com/newrelic/go-agent/blob/master/datastore.go. Product
// is one of the fields primarily responsible for the grouping of Datastore
// metrics.
Product DatastoreProduct
// Collection is the table or group being operated upon in the datastore,
// e.g. "users_table". This becomes the db.collection attribute on Span
// events and Transaction Trace segments. Collection is one of the fields
// primarily responsible for the grouping of Datastore metrics.
Collection string
// Operation is the relevant action, e.g. "SELECT" or "GET". Operation is
// one of the fields primarily responsible for the grouping of Datastore
// metrics.
Operation string
// The following fields are used for extra metrics and added to instance
// data:
//
// ParameterizedQuery may be set to the query being performed. It must
// not contain any raw parameters, only placeholders.
ParameterizedQuery string
// QueryParameters may be used to provide query parameters. Care should
// be taken to only provide parameters which are not sensitive.
// QueryParameters are ignored in high security mode. The keys must contain
// fewer than than 255 bytes. The values must be numbers, strings, or
// booleans.
QueryParameters map[string]interface{}
// Host is the name of the server hosting the datastore.
Host string
// PortPathOrID can represent either the port, path, or id of the
// datastore being connected to.
PortPathOrID string
// DatabaseName is name of database instance where the current query is
// being executed. This becomes the db.instance attribute on Span events
// and Transaction Trace segments.
DatabaseName string
}
// ExternalSegment instruments external calls. StartExternalSegment is the
// recommended way to create ExternalSegments.
type ExternalSegment struct {
StartTime SegmentStartTime
Request *http.Request
Response *http.Response
// URL is an optional field which can be populated in lieu of Request if
// you don't have an http.Request. Either URL or Request must be
// populated. If both are populated then Request information takes
// priority. URL is parsed using url.Parse so it must include the
// protocol scheme (eg. "http://").
URL string
// Host is an optional field that is automatically populated from the
// Request or URL. It is used for external metrics, transaction trace
// segment names, and span event names. Use this field to override the
// host in the URL or Request. This field does not override the host in
// the "http.url" attribute.
Host string
// Procedure is an optional field that can be set to the remote
// procedure being called. If set, this value will be used in metrics,
// transaction trace segment names, and span event names. If unset, the
// request's http method is used.
Procedure string
// Library is an optional field that defaults to "http". It is used for
// external metrics and the "component" span attribute. It should be
// the framework making the external call.
Library string
}
// MessageProducerSegment instruments calls to add messages to a queueing system.
type MessageProducerSegment struct {
StartTime SegmentStartTime
// Library is the name of the library instrumented. eg. "RabbitMQ",
// "JMS"
Library string
// DestinationType is the destination type.
DestinationType MessageDestinationType
// DestinationName is the name of your queue or topic. eg. "UsersQueue".
DestinationName string
// DestinationTemporary must be set to true if destination is temporary
// to improve metric grouping.
DestinationTemporary bool
}
// MessageDestinationType is used for the MessageSegment.DestinationType field.
type MessageDestinationType string
// These message destination type constants are used in for the
// MessageSegment.DestinationType field.
const (
MessageQueue MessageDestinationType = "Queue"
MessageTopic MessageDestinationType = "Topic"
MessageExchange MessageDestinationType = "Exchange"
)
// End finishes the segment.
func (s *Segment) End() error { return endSegment(s) }
// End finishes the datastore segment.
func (s *DatastoreSegment) End() error { return endDatastore(s) }
// End finishes the external segment.
func (s *ExternalSegment) End() error { return endExternal(s) }
// End finishes the message segment.
func (s *MessageProducerSegment) End() error { return endMessage(s) }
// OutboundHeaders returns the headers that should be attached to the external
// request.
func (s *ExternalSegment) OutboundHeaders() http.Header {
return outboundHeaders(s)
}
// StartSegmentNow starts timing a segment. This function is recommended over
// Transaction.StartSegmentNow() because it is nil safe.
func StartSegmentNow(txn Transaction) SegmentStartTime {
if nil != txn {
return txn.StartSegmentNow()
}
return SegmentStartTime{}
}
// StartSegment makes it easy to instrument segments. To time a function, do
// the following:
//
// func timeMe(txn newrelic.Transaction) {
// defer newrelic.StartSegment(txn, "timeMe").End()
// // ... function code here ...
// }
//
// To time a block of code, do the following:
//
// segment := StartSegment(txn, "myBlock")
// // ... code you want to time here ...
// segment.End()
//
func StartSegment(txn Transaction, name string) *Segment {
return &Segment{
StartTime: StartSegmentNow(txn),
Name: name,
}
}
// StartExternalSegment starts the instrumentation of an external call and adds
// distributed tracing headers to the request. If the Transaction parameter is
// nil then StartExternalSegment will look for a Transaction in the request's
// context using FromContext.
//
// Using the same http.Client for all of your external requests? Check out
// NewRoundTripper: You may not need to use StartExternalSegment at all!
//
func StartExternalSegment(txn Transaction, request *http.Request) *ExternalSegment {
if nil == txn {
txn = transactionFromRequestContext(request)
}
s := &ExternalSegment{
StartTime: StartSegmentNow(txn),
Request: request,
}
if request != nil && request.Header != nil {
for key, values := range s.OutboundHeaders() {
for _, value := range values {
request.Header.Add(key, value)
}
}
}
return s
}