github.com/newrelic/go-agent@v3.26.0+incompatible/internal/span_events_test.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package internal 5 6 import ( 7 "encoding/json" 8 "testing" 9 "time" 10 ) 11 12 func testSpanEventJSON(t *testing.T, e *SpanEvent, expect string) { 13 js, err := json.Marshal(e) 14 if nil != err { 15 t.Error(err) 16 return 17 } 18 expect = CompactJSONString(expect) 19 if string(js) != expect { 20 t.Errorf("\nexpect=%s\nactual=%s\n", expect, string(js)) 21 } 22 } 23 24 var ( 25 sampleSpanEvent = SpanEvent{ 26 TraceID: "trace-id", 27 GUID: "guid", 28 TransactionID: "txn-id", 29 Sampled: true, 30 Priority: 0.5, 31 Timestamp: timeFromUnixMilliseconds(1488393111000), 32 Duration: 2 * time.Second, 33 Name: "myName", 34 Category: spanCategoryGeneric, 35 IsEntrypoint: true, 36 } 37 ) 38 39 func TestSpanEventGenericRootMarshal(t *testing.T) { 40 e := sampleSpanEvent 41 testSpanEventJSON(t, &e, `[ 42 { 43 "type":"Span", 44 "traceId":"trace-id", 45 "guid":"guid", 46 "transactionId":"txn-id", 47 "sampled":true, 48 "priority":0.500000, 49 "timestamp":1488393111000, 50 "duration":2, 51 "name":"myName", 52 "category":"generic", 53 "nr.entryPoint":true 54 }, 55 {}, 56 {}]`) 57 } 58 59 func TestSpanEventDatastoreMarshal(t *testing.T) { 60 e := sampleSpanEvent 61 62 // Alter sample span event for this test case 63 e.IsEntrypoint = false 64 e.ParentID = "parent-id" 65 e.Category = spanCategoryDatastore 66 e.Kind = "client" 67 e.Component = "mySql" 68 e.Attributes.addString(spanAttributeDBStatement, "SELECT * from foo") 69 e.Attributes.addString(spanAttributeDBInstance, "123") 70 e.Attributes.addString(spanAttributePeerAddress, "{host}:{portPathOrId}") 71 e.Attributes.addString(spanAttributePeerHostname, "host") 72 73 expectEvent(t, &e, WantEvent{ 74 Intrinsics: map[string]interface{}{ 75 "type": "Span", 76 "traceId": "trace-id", 77 "guid": "guid", 78 "parentId": "parent-id", 79 "transactionId": "txn-id", 80 "sampled": true, 81 "priority": 0.500000, 82 "timestamp": 1.488393111e+12, 83 "duration": 2, 84 "name": "myName", 85 "category": "datastore", 86 "component": "mySql", 87 "span.kind": "client", 88 }, 89 UserAttributes: map[string]interface{}{}, 90 AgentAttributes: map[string]interface{}{ 91 "db.statement": "SELECT * from foo", 92 "db.instance": "123", 93 "peer.address": "{host}:{portPathOrId}", 94 "peer.hostname": "host", 95 }, 96 }) 97 } 98 99 func TestSpanEventDatastoreWithoutHostMarshal(t *testing.T) { 100 e := sampleSpanEvent 101 102 // Alter sample span event for this test case 103 e.IsEntrypoint = false 104 e.ParentID = "parent-id" 105 e.Category = spanCategoryDatastore 106 e.Kind = "client" 107 e.Component = "mySql" 108 e.Attributes.addString(spanAttributeDBStatement, "SELECT * from foo") 109 e.Attributes.addString(spanAttributeDBInstance, "123") 110 111 // According to CHANGELOG.md, as of version 1.5, if `Host` and 112 // `PortPathOrID` are not provided in a Datastore segment, they 113 // do not appear as `"unknown"` in transaction traces and slow 114 // query traces. To maintain parity with the other offerings of 115 // the Go Agent, neither do Span Events. 116 expectEvent(t, &e, WantEvent{ 117 Intrinsics: map[string]interface{}{ 118 "type": "Span", 119 "traceId": "trace-id", 120 "guid": "guid", 121 "parentId": "parent-id", 122 "transactionId": "txn-id", 123 "sampled": true, 124 "priority": 0.500000, 125 "timestamp": 1.488393111e+12, 126 "duration": 2, 127 "name": "myName", 128 "category": "datastore", 129 "component": "mySql", 130 "span.kind": "client", 131 }, 132 UserAttributes: map[string]interface{}{}, 133 AgentAttributes: map[string]interface{}{ 134 "db.statement": "SELECT * from foo", 135 "db.instance": "123", 136 }, 137 }) 138 } 139 140 func TestSpanEventExternalMarshal(t *testing.T) { 141 e := sampleSpanEvent 142 143 // Alter sample span event for this test case 144 e.ParentID = "parent-id" 145 e.IsEntrypoint = false 146 e.Category = spanCategoryHTTP 147 e.Kind = "client" 148 e.Component = "http" 149 e.Attributes.addString(spanAttributeHTTPURL, "http://url.com") 150 e.Attributes.addString(spanAttributeHTTPMethod, "GET") 151 152 expectEvent(t, &e, WantEvent{ 153 Intrinsics: map[string]interface{}{ 154 "type": "Span", 155 "traceId": "trace-id", 156 "guid": "guid", 157 "parentId": "parent-id", 158 "transactionId": "txn-id", 159 "sampled": true, 160 "priority": 0.500000, 161 "timestamp": 1.488393111e+12, 162 "duration": 2, 163 "name": "myName", 164 "category": "http", 165 "component": "http", 166 "span.kind": "client", 167 }, 168 UserAttributes: map[string]interface{}{}, 169 AgentAttributes: map[string]interface{}{ 170 "http.url": "http://url.com", 171 "http.method": "GET", 172 }, 173 }) 174 } 175 176 func TestSpanEventsEndpointMethod(t *testing.T) { 177 events := &spanEvents{} 178 m := events.EndpointMethod() 179 if m != cmdSpanEvents { 180 t.Error(m) 181 } 182 } 183 184 func TestSpanEventsMergeFromTransaction(t *testing.T) { 185 args := &TxnData{} 186 args.Start = time.Now() 187 args.Duration = 1 * time.Second 188 args.FinalName = "finalName" 189 args.BetterCAT.Sampled = true 190 args.BetterCAT.Priority = 0.7 191 args.BetterCAT.Enabled = true 192 args.BetterCAT.ID = "txn-id" 193 args.BetterCAT.Inbound = &Payload{ 194 ID: "inbound-id", 195 TracedID: "inbound-trace-id", 196 } 197 args.rootSpanID = "root-span-id" 198 199 args.spanEvents = []*SpanEvent{ 200 { 201 GUID: "span-1-id", 202 ParentID: "root-span-id", 203 Timestamp: time.Now(), 204 Duration: 3 * time.Millisecond, 205 Name: "span1", 206 Category: spanCategoryGeneric, 207 IsEntrypoint: false, 208 }, 209 { 210 GUID: "span-2-id", 211 ParentID: "span-1-id", 212 Timestamp: time.Now(), 213 Duration: 3 * time.Millisecond, 214 Name: "span2", 215 Category: spanCategoryGeneric, 216 IsEntrypoint: false, 217 }, 218 } 219 220 spanEvents := newSpanEvents(10) 221 spanEvents.MergeFromTransaction(args) 222 223 ExpectSpanEvents(t, spanEvents, []WantEvent{ 224 { 225 Intrinsics: map[string]interface{}{ 226 "name": "finalName", 227 "sampled": true, 228 "priority": 0.7, 229 "category": spanCategoryGeneric, 230 "parentId": "inbound-id", 231 "nr.entryPoint": true, 232 "guid": "root-span-id", 233 "transactionId": "txn-id", 234 "traceId": "inbound-trace-id", 235 }, 236 }, 237 { 238 Intrinsics: map[string]interface{}{ 239 "name": "span1", 240 "sampled": true, 241 "priority": 0.7, 242 "category": spanCategoryGeneric, 243 "parentId": "root-span-id", 244 "guid": "span-1-id", 245 "transactionId": "txn-id", 246 "traceId": "inbound-trace-id", 247 }, 248 }, 249 { 250 Intrinsics: map[string]interface{}{ 251 "name": "span2", 252 "sampled": true, 253 "priority": 0.7, 254 "category": spanCategoryGeneric, 255 "parentId": "span-1-id", 256 "guid": "span-2-id", 257 "transactionId": "txn-id", 258 "traceId": "inbound-trace-id", 259 }, 260 }, 261 }) 262 }