github.com/newrelic/go-agent@v3.26.0+incompatible/internal/txn_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 "github.com/newrelic/go-agent/internal/cat" 12 ) 13 14 func testTxnEventJSON(t testing.TB, e *TxnEvent, expect string) { 15 // Type assertion to support early Go versions. 16 if h, ok := t.(interface { 17 Helper() 18 }); ok { 19 h.Helper() 20 } 21 js, err := json.Marshal(e) 22 if nil != err { 23 t.Error(err) 24 return 25 } 26 expect = CompactJSONString(expect) 27 if string(js) != expect { 28 t.Errorf("\nexpect=%s\nactual=%s\n", expect, string(js)) 29 } 30 } 31 32 var ( 33 sampleTxnEvent = TxnEvent{ 34 FinalName: "myName", 35 BetterCAT: BetterCAT{ 36 Enabled: true, 37 ID: "txn-id", 38 Priority: 0.5, 39 }, 40 Start: timeFromUnixMilliseconds(1488393111000), 41 Duration: 2 * time.Second, 42 TotalTime: 3 * time.Second, 43 Zone: ApdexNone, 44 Attrs: nil, 45 } 46 47 sampleTxnEventWithOldCAT = TxnEvent{ 48 FinalName: "myOldName", 49 BetterCAT: BetterCAT{ 50 Enabled: false, 51 }, 52 Start: timeFromUnixMilliseconds(1488393111000), 53 Duration: 2 * time.Second, 54 TotalTime: 3 * time.Second, 55 Zone: ApdexNone, 56 Attrs: nil, 57 } 58 59 sampleTxnEventWithError = TxnEvent{ 60 FinalName: "myName", 61 BetterCAT: BetterCAT{ 62 Enabled: true, 63 ID: "txn-id", 64 Priority: 0.5, 65 }, 66 Start: timeFromUnixMilliseconds(1488393111000), 67 Duration: 2 * time.Second, 68 TotalTime: 3 * time.Second, 69 Zone: ApdexNone, 70 Attrs: nil, 71 HasError: true, 72 } 73 ) 74 75 func TestTxnEventMarshal(t *testing.T) { 76 e := sampleTxnEvent 77 testTxnEventJSON(t, &e, `[ 78 { 79 "type":"Transaction", 80 "name":"myName", 81 "timestamp":1.488393111e+09, 82 "error":false, 83 "duration":2, 84 "totalTime":3, 85 "guid":"txn-id", 86 "traceId":"txn-id", 87 "priority":0.500000, 88 "sampled":false 89 }, 90 {}, 91 {}]`) 92 } 93 94 func TestTxnEventMarshalWithApdex(t *testing.T) { 95 e := sampleTxnEvent 96 e.Zone = ApdexFailing 97 testTxnEventJSON(t, &e, `[ 98 { 99 "type":"Transaction", 100 "name":"myName", 101 "timestamp":1.488393111e+09, 102 "nr.apdexPerfZone":"F", 103 "error":false, 104 "duration":2, 105 "totalTime":3, 106 "guid":"txn-id", 107 "traceId":"txn-id", 108 "priority":0.500000, 109 "sampled":false 110 }, 111 {}, 112 {}]`) 113 } 114 115 func TestTxnEventMarshalWithDatastoreExternal(t *testing.T) { 116 e := sampleTxnEvent 117 e.DatastoreExternalTotals = DatastoreExternalTotals{ 118 externalCallCount: 22, 119 externalDuration: 1122334 * time.Millisecond, 120 datastoreCallCount: 33, 121 datastoreDuration: 5566778 * time.Millisecond, 122 } 123 testTxnEventJSON(t, &e, `[ 124 { 125 "type":"Transaction", 126 "name":"myName", 127 "timestamp":1.488393111e+09, 128 "error":false, 129 "duration":2, 130 "externalCallCount":22, 131 "externalDuration":1122.334, 132 "databaseCallCount":33, 133 "databaseDuration":5566.778, 134 "totalTime":3, 135 "guid":"txn-id", 136 "traceId":"txn-id", 137 "priority":0.500000, 138 "sampled":false 139 }, 140 {}, 141 {}]`) 142 } 143 144 func TestTxnEventMarshalWithInboundCaller(t *testing.T) { 145 e := sampleTxnEvent 146 e.BetterCAT.Inbound = &Payload{ 147 payloadCaller: payloadCaller{ 148 TransportType: "HTTP", 149 Type: "Browser", 150 App: "caller-app", 151 Account: "caller-account", 152 }, 153 ID: "caller-id", 154 TransactionID: "caller-parent-id", 155 TracedID: "trip-id", 156 TransportDuration: 2 * time.Second, 157 } 158 testTxnEventJSON(t, &e, `[ 159 { 160 "type":"Transaction", 161 "name":"myName", 162 "timestamp":1.488393111e+09, 163 "error":false, 164 "duration":2, 165 "totalTime":3, 166 "parent.type": "Browser", 167 "parent.app": "caller-app", 168 "parent.account": "caller-account", 169 "parent.transportType": "HTTP", 170 "parent.transportDuration": 2, 171 "guid":"txn-id", 172 "traceId":"trip-id", 173 "priority":0.500000, 174 "sampled":false, 175 "parentId": "caller-parent-id", 176 "parentSpanId": "caller-id" 177 }, 178 {}, 179 {}]`) 180 } 181 182 func TestTxnEventMarshalWithInboundCallerOldCAT(t *testing.T) { 183 e := sampleTxnEventWithOldCAT 184 e.BetterCAT.Inbound = &Payload{ 185 payloadCaller: payloadCaller{ 186 TransportType: "HTTP", 187 Type: "Browser", 188 App: "caller-app", 189 Account: "caller-account", 190 }, 191 ID: "caller-id", 192 TransactionID: "caller-parent-id", 193 TracedID: "trip-id", 194 TransportDuration: 2 * time.Second, 195 } 196 testTxnEventJSON(t, &e, `[ 197 { 198 "type":"Transaction", 199 "name":"myOldName", 200 "timestamp":1.488393111e+09, 201 "error":false, 202 "duration":2, 203 "totalTime":3 204 }, 205 {}, 206 {}]`) 207 } 208 209 func TestTxnEventMarshalWithAttributes(t *testing.T) { 210 aci := sampleAttributeConfigInput 211 aci.TransactionEvents.Exclude = append(aci.TransactionEvents.Exclude, "zap") 212 aci.TransactionEvents.Exclude = append(aci.TransactionEvents.Exclude, AttributeHostDisplayName.name()) 213 cfg := CreateAttributeConfig(aci, true) 214 attr := NewAttributes(cfg) 215 attr.Agent.Add(AttributeHostDisplayName, "exclude me", nil) 216 attr.Agent.Add(attributeRequestMethod, "GET", nil) 217 AddUserAttribute(attr, "zap", 123, DestAll) 218 AddUserAttribute(attr, "zip", 456, DestAll) 219 e := sampleTxnEvent 220 e.Attrs = attr 221 testTxnEventJSON(t, &e, `[ 222 { 223 "type":"Transaction", 224 "name":"myName", 225 "timestamp":1.488393111e+09, 226 "error":false, 227 "duration":2, 228 "totalTime":3, 229 "guid":"txn-id", 230 "traceId":"txn-id", 231 "priority":0.500000, 232 "sampled":false 233 }, 234 { 235 "zip":456 236 }, 237 { 238 "request.method":"GET" 239 }]`) 240 } 241 242 func TestTxnEventsPayloadsEmpty(t *testing.T) { 243 events := newTxnEvents(10) 244 ps := events.payloads(5) 245 if len(ps) != 1 { 246 t.Error(ps) 247 } 248 if data, err := ps[0].Data("agentRunID", time.Now()); data != nil || err != nil { 249 t.Error(data, err) 250 } 251 } 252 253 func TestTxnEventsPayloadsUnderLimit(t *testing.T) { 254 events := newTxnEvents(10) 255 for i := 0; i < 4; i++ { 256 events.AddTxnEvent(&TxnEvent{}, Priority(float32(i)/10.0)) 257 } 258 ps := events.payloads(5) 259 if len(ps) != 1 { 260 t.Error(ps) 261 } 262 if data, err := ps[0].Data("agentRunID", time.Now()); data == nil || err != nil { 263 t.Error(data, err) 264 } 265 } 266 267 func TestTxnEventsPayloadsOverLimit(t *testing.T) { 268 events := newTxnEvents(10) 269 for i := 0; i < 6; i++ { 270 events.AddTxnEvent(&TxnEvent{}, Priority(float32(i)/10.0)) 271 } 272 ps := events.payloads(5) 273 if len(ps) != 2 { 274 t.Error(ps) 275 } 276 if data, err := ps[0].Data("agentRunID", time.Now()); data == nil || err != nil { 277 t.Error(data, err) 278 } 279 if data, err := ps[1].Data("agentRunID", time.Now()); data == nil || err != nil { 280 t.Error(data, err) 281 } 282 } 283 284 func TestTxnEventsSynthetics(t *testing.T) { 285 events := newTxnEvents(1) 286 287 regular := &TxnEvent{ 288 FinalName: "Regular", 289 Start: time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC), 290 Duration: 2 * time.Second, 291 Zone: ApdexNone, 292 Attrs: nil, 293 } 294 295 synthetics := &TxnEvent{ 296 FinalName: "Synthetics", 297 Start: time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC), 298 Duration: 2 * time.Second, 299 Zone: ApdexNone, 300 Attrs: nil, 301 CrossProcess: TxnCrossProcess{ 302 Type: txnCrossProcessSynthetics, 303 Synthetics: &cat.SyntheticsHeader{ 304 ResourceID: "resource", 305 JobID: "job", 306 MonitorID: "monitor", 307 }, 308 }, 309 } 310 311 events.AddTxnEvent(regular, 1.99999) 312 313 // Check that the event was saved. 314 if saved := events.analyticsEvents.events[0].jsonWriter; saved != regular { 315 t.Errorf("unexpected saved event: expected=%v; got=%v", regular, saved) 316 } 317 318 // The priority sampling algorithm is implemented using isLowerPriority(). In 319 // the case of an event pool with a single event, an incoming event with the 320 // same priority would kick out the event already in the pool. To really test 321 // whether synthetics are given highest deference, add a synthetics event 322 // with a really low priority and affirm it kicks out the event already in the 323 // pool. 324 events.AddTxnEvent(synthetics, 0.0) 325 326 // Check that the event was saved and its priority was appropriately augmented. 327 if saved := events.analyticsEvents.events[0].jsonWriter; saved != synthetics { 328 t.Errorf("unexpected saved event: expected=%v; got=%v", synthetics, saved) 329 } 330 331 if priority := events.analyticsEvents.events[0].priority; priority != 2.0 { 332 t.Errorf("synthetics event has unexpected priority: %f", priority) 333 } 334 } 335 336 func TestTxnEventMarshalWithError(t *testing.T) { 337 e := sampleTxnEventWithError 338 testTxnEventJSON(t, &e, `[ 339 { 340 "type":"Transaction", 341 "name":"myName", 342 "timestamp":1.488393111e+09, 343 "error":true, 344 "duration":2, 345 "totalTime":3, 346 "guid":"txn-id", 347 "traceId":"txn-id", 348 "priority":0.500000, 349 "sampled":false 350 }, 351 {}, 352 {}]`) 353 }