github.com/newrelic/go-agent@v3.26.0+incompatible/segments.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package newrelic 5 6 import ( 7 "net/http" 8 ) 9 10 // SegmentStartTime is created by Transaction.StartSegmentNow and marks the 11 // beginning of a segment. A segment with a zero-valued SegmentStartTime may 12 // safely be ended. 13 type SegmentStartTime struct{ segment } 14 15 // Segment is used to instrument functions, methods, and blocks of code. The 16 // easiest way use Segment is the StartSegment function. 17 type Segment struct { 18 StartTime SegmentStartTime 19 Name string 20 } 21 22 // DatastoreSegment is used to instrument calls to databases and object stores. 23 type DatastoreSegment struct { 24 // StartTime should be assigned using StartSegmentNow before each datastore 25 // call is made. 26 StartTime SegmentStartTime 27 28 // Product, Collection, and Operation are highly recommended as they are 29 // used for aggregate metrics: 30 // 31 // Product is the datastore type. See the constants in 32 // https://github.com/newrelic/go-agent/blob/master/datastore.go. Product 33 // is one of the fields primarily responsible for the grouping of Datastore 34 // metrics. 35 Product DatastoreProduct 36 // Collection is the table or group being operated upon in the datastore, 37 // e.g. "users_table". This becomes the db.collection attribute on Span 38 // events and Transaction Trace segments. Collection is one of the fields 39 // primarily responsible for the grouping of Datastore metrics. 40 Collection string 41 // Operation is the relevant action, e.g. "SELECT" or "GET". Operation is 42 // one of the fields primarily responsible for the grouping of Datastore 43 // metrics. 44 Operation string 45 46 // The following fields are used for extra metrics and added to instance 47 // data: 48 // 49 // ParameterizedQuery may be set to the query being performed. It must 50 // not contain any raw parameters, only placeholders. 51 ParameterizedQuery string 52 // QueryParameters may be used to provide query parameters. Care should 53 // be taken to only provide parameters which are not sensitive. 54 // QueryParameters are ignored in high security mode. The keys must contain 55 // fewer than than 255 bytes. The values must be numbers, strings, or 56 // booleans. 57 QueryParameters map[string]interface{} 58 // Host is the name of the server hosting the datastore. 59 Host string 60 // PortPathOrID can represent either the port, path, or id of the 61 // datastore being connected to. 62 PortPathOrID string 63 // DatabaseName is name of database instance where the current query is 64 // being executed. This becomes the db.instance attribute on Span events 65 // and Transaction Trace segments. 66 DatabaseName string 67 } 68 69 // ExternalSegment instruments external calls. StartExternalSegment is the 70 // recommended way to create ExternalSegments. 71 type ExternalSegment struct { 72 StartTime SegmentStartTime 73 Request *http.Request 74 Response *http.Response 75 76 // URL is an optional field which can be populated in lieu of Request if 77 // you don't have an http.Request. Either URL or Request must be 78 // populated. If both are populated then Request information takes 79 // priority. URL is parsed using url.Parse so it must include the 80 // protocol scheme (eg. "http://"). 81 URL string 82 // Host is an optional field that is automatically populated from the 83 // Request or URL. It is used for external metrics, transaction trace 84 // segment names, and span event names. Use this field to override the 85 // host in the URL or Request. This field does not override the host in 86 // the "http.url" attribute. 87 Host string 88 // Procedure is an optional field that can be set to the remote 89 // procedure being called. If set, this value will be used in metrics, 90 // transaction trace segment names, and span event names. If unset, the 91 // request's http method is used. 92 Procedure string 93 // Library is an optional field that defaults to "http". It is used for 94 // external metrics and the "component" span attribute. It should be 95 // the framework making the external call. 96 Library string 97 } 98 99 // MessageProducerSegment instruments calls to add messages to a queueing system. 100 type MessageProducerSegment struct { 101 StartTime SegmentStartTime 102 103 // Library is the name of the library instrumented. eg. "RabbitMQ", 104 // "JMS" 105 Library string 106 107 // DestinationType is the destination type. 108 DestinationType MessageDestinationType 109 110 // DestinationName is the name of your queue or topic. eg. "UsersQueue". 111 DestinationName string 112 113 // DestinationTemporary must be set to true if destination is temporary 114 // to improve metric grouping. 115 DestinationTemporary bool 116 } 117 118 // MessageDestinationType is used for the MessageSegment.DestinationType field. 119 type MessageDestinationType string 120 121 // These message destination type constants are used in for the 122 // MessageSegment.DestinationType field. 123 const ( 124 MessageQueue MessageDestinationType = "Queue" 125 MessageTopic MessageDestinationType = "Topic" 126 MessageExchange MessageDestinationType = "Exchange" 127 ) 128 129 // End finishes the segment. 130 func (s *Segment) End() error { return endSegment(s) } 131 132 // End finishes the datastore segment. 133 func (s *DatastoreSegment) End() error { return endDatastore(s) } 134 135 // End finishes the external segment. 136 func (s *ExternalSegment) End() error { return endExternal(s) } 137 138 // End finishes the message segment. 139 func (s *MessageProducerSegment) End() error { return endMessage(s) } 140 141 // OutboundHeaders returns the headers that should be attached to the external 142 // request. 143 func (s *ExternalSegment) OutboundHeaders() http.Header { 144 return outboundHeaders(s) 145 } 146 147 // StartSegmentNow starts timing a segment. This function is recommended over 148 // Transaction.StartSegmentNow() because it is nil safe. 149 func StartSegmentNow(txn Transaction) SegmentStartTime { 150 if nil != txn { 151 return txn.StartSegmentNow() 152 } 153 return SegmentStartTime{} 154 } 155 156 // StartSegment makes it easy to instrument segments. To time a function, do 157 // the following: 158 // 159 // func timeMe(txn newrelic.Transaction) { 160 // defer newrelic.StartSegment(txn, "timeMe").End() 161 // // ... function code here ... 162 // } 163 // 164 // To time a block of code, do the following: 165 // 166 // segment := StartSegment(txn, "myBlock") 167 // // ... code you want to time here ... 168 // segment.End() 169 // 170 func StartSegment(txn Transaction, name string) *Segment { 171 return &Segment{ 172 StartTime: StartSegmentNow(txn), 173 Name: name, 174 } 175 } 176 177 // StartExternalSegment starts the instrumentation of an external call and adds 178 // distributed tracing headers to the request. If the Transaction parameter is 179 // nil then StartExternalSegment will look for a Transaction in the request's 180 // context using FromContext. 181 // 182 // Using the same http.Client for all of your external requests? Check out 183 // NewRoundTripper: You may not need to use StartExternalSegment at all! 184 // 185 func StartExternalSegment(txn Transaction, request *http.Request) *ExternalSegment { 186 if nil == txn { 187 txn = transactionFromRequestContext(request) 188 } 189 s := &ExternalSegment{ 190 StartTime: StartSegmentNow(txn), 191 Request: request, 192 } 193 194 if request != nil && request.Header != nil { 195 for key, values := range s.OutboundHeaders() { 196 for _, value := range values { 197 request.Header.Add(key, value) 198 } 199 } 200 } 201 202 return s 203 }