github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/txn_trace_test.go (about) 1 package internal 2 3 import ( 4 "strconv" 5 "testing" 6 "time" 7 8 "github.com/lulzWill/go-agent/internal/cat" 9 ) 10 11 func TestTxnTrace(t *testing.T) { 12 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 13 tr := &TxnData{} 14 tr.TxnTrace.Enabled = true 15 tr.TxnTrace.StackTraceThreshold = 1 * time.Hour 16 tr.TxnTrace.SegmentThreshold = 0 17 18 t1 := StartSegment(tr, start.Add(1*time.Second)) 19 t2 := StartSegment(tr, start.Add(2*time.Second)) 20 EndDatastoreSegment(EndDatastoreParams{ 21 Tracer: tr, 22 Start: t2, 23 Now: start.Add(3 * time.Second), 24 Product: "MySQL", 25 Operation: "SELECT", 26 Collection: "my_table", 27 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 28 QueryParameters: vetQueryParameters(map[string]interface{}{"zip": 1}), 29 Database: "my_db", 30 Host: "db-server-1", 31 PortPathOrID: "3306", 32 }) 33 t3 := StartSegment(tr, start.Add(4*time.Second)) 34 EndExternalSegment(tr, t3, start.Add(5*time.Second), parseURL("http://example.com/zip/zap?secret=shhh"), nil) 35 EndBasicSegment(tr, t1, start.Add(6*time.Second), "t1") 36 t4 := StartSegment(tr, start.Add(7*time.Second)) 37 t5 := StartSegment(tr, start.Add(8*time.Second)) 38 t6 := StartSegment(tr, start.Add(9*time.Second)) 39 EndBasicSegment(tr, t6, start.Add(10*time.Second), "t6") 40 EndBasicSegment(tr, t5, start.Add(11*time.Second), "t5") 41 t7 := StartSegment(tr, start.Add(12*time.Second)) 42 EndDatastoreSegment(EndDatastoreParams{ 43 Tracer: tr, 44 Start: t7, 45 Now: start.Add(13 * time.Second), 46 Product: "MySQL", 47 Operation: "SELECT", 48 // no collection 49 }) 50 t8 := StartSegment(tr, start.Add(14*time.Second)) 51 EndExternalSegment(tr, t8, start.Add(15*time.Second), nil, nil) 52 EndBasicSegment(tr, t4, start.Add(16*time.Second), "t4") 53 54 acfg := CreateAttributeConfig(sampleAttributeConfigInput, true) 55 attr := NewAttributes(acfg) 56 attr.Agent.RequestMethod = "GET" 57 AddUserAttribute(attr, "zap", 123, DestAll) 58 59 ht := newHarvestTraces() 60 ht.regular.addTxnTrace(&HarvestTrace{ 61 TxnEvent: TxnEvent{ 62 Start: start, 63 Duration: 20 * time.Second, 64 FinalName: "WebTransaction/Go/hello", 65 CleanURL: "/url", 66 Attrs: attr, 67 }, 68 Trace: tr.TxnTrace, 69 }) 70 71 expect := `[ 72 1417136460000000, 73 20000, 74 "WebTransaction/Go/hello", 75 "/url", 76 [ 77 0, 78 {}, 79 {}, 80 [ 81 0, 82 20000, 83 "ROOT", 84 {}, 85 [ 86 [ 87 0, 88 20000, 89 "WebTransaction/Go/hello", 90 {}, 91 [ 92 [ 93 1000, 94 6000, 95 "Custom/t1", 96 {}, 97 [ 98 [ 99 2000, 100 3000, 101 "Datastore/statement/MySQL/my_table/SELECT", 102 { 103 "database_name":"my_db", 104 "host":"db-server-1", 105 "port_path_or_id":"3306", 106 "query":"INSERT INTO users (name, age) VALUES ($1, $2)", 107 "query_parameters":{ 108 "zip":1 109 } 110 }, 111 [] 112 ], 113 [ 114 4000, 115 5000, 116 "External/example.com/all", 117 { 118 "uri":"http://example.com/zip/zap" 119 }, 120 [] 121 ] 122 ] 123 ], 124 [ 125 7000, 126 16000, 127 "Custom/t4", 128 {}, 129 [ 130 [ 131 8000, 132 11000, 133 "Custom/t5", 134 {}, 135 [ 136 [ 137 9000, 138 10000, 139 "Custom/t6", 140 {}, 141 [] 142 ] 143 ] 144 ], 145 [ 146 12000, 147 13000, 148 "Datastore/operation/MySQL/SELECT", 149 { 150 "query":"'SELECT' on 'unknown' using 'MySQL'" 151 }, 152 [] 153 ], 154 [ 155 14000, 156 15000, 157 "External/unknown/all", 158 {}, 159 [] 160 ] 161 ] 162 ] 163 ] 164 ] 165 ] 166 ], 167 { 168 "agentAttributes":{ 169 "request.method":"GET" 170 }, 171 "userAttributes":{ 172 "zap":123 173 }, 174 "intrinsics":{} 175 } 176 ], 177 "", 178 null, 179 false, 180 null, 181 "" 182 ]` 183 184 expect = CompactJSONString(expect) 185 js, err := ht.slice()[0].MarshalJSON() 186 if nil != err { 187 t.Fatal(err) 188 } 189 if string(js) != expect { 190 t.Error(string(js), expect) 191 } 192 } 193 194 func TestTxnTraceNoSegmentsNoAttributes(t *testing.T) { 195 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 196 tr := &TxnData{} 197 tr.TxnTrace.Enabled = true 198 tr.TxnTrace.StackTraceThreshold = 1 * time.Hour 199 tr.TxnTrace.SegmentThreshold = 0 200 201 acfg := CreateAttributeConfig(sampleAttributeConfigInput, true) 202 attr := NewAttributes(acfg) 203 204 ht := newHarvestTraces() 205 ht.regular.addTxnTrace(&HarvestTrace{ 206 TxnEvent: TxnEvent{ 207 Start: start, 208 Duration: 20 * time.Second, 209 FinalName: "WebTransaction/Go/hello", 210 CleanURL: "/url", 211 Attrs: attr, 212 }, 213 Trace: tr.TxnTrace, 214 }) 215 216 expect := `[ 217 1417136460000000, 218 20000, 219 "WebTransaction/Go/hello", 220 "/url", 221 [ 222 0, 223 {}, 224 {}, 225 [ 226 0, 227 20000, 228 "ROOT", 229 {}, 230 [ 231 [ 232 0, 233 20000, 234 "WebTransaction/Go/hello", 235 {}, 236 [] 237 ] 238 ] 239 ], 240 { 241 "agentAttributes":{}, 242 "userAttributes":{}, 243 "intrinsics":{} 244 } 245 ], 246 "", 247 null, 248 false, 249 null, 250 "" 251 ]` 252 expect = CompactJSONString(expect) 253 js, err := ht.slice()[0].MarshalJSON() 254 if nil != err { 255 t.Fatal(err) 256 } 257 if string(js) != expect { 258 t.Error(string(js), expect) 259 } 260 } 261 262 func TestTxnTraceSlowestNodesSaved(t *testing.T) { 263 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 264 tr := &TxnData{} 265 tr.TxnTrace.Enabled = true 266 tr.TxnTrace.StackTraceThreshold = 1 * time.Hour 267 tr.TxnTrace.SegmentThreshold = 0 268 tr.TxnTrace.maxNodes = 5 269 270 durations := []int{5, 4, 6, 3, 7, 2, 8, 1, 9} 271 now := start 272 for _, d := range durations { 273 s := StartSegment(tr, now) 274 now = now.Add(time.Duration(d) * time.Second) 275 EndBasicSegment(tr, s, now, strconv.Itoa(d)) 276 } 277 278 acfg := CreateAttributeConfig(sampleAttributeConfigInput, true) 279 attr := NewAttributes(acfg) 280 281 ht := newHarvestTraces() 282 ht.regular.addTxnTrace(&HarvestTrace{ 283 TxnEvent: TxnEvent{ 284 Start: start, 285 Duration: 123 * time.Second, 286 FinalName: "WebTransaction/Go/hello", 287 CleanURL: "/url", 288 Attrs: attr, 289 }, 290 Trace: tr.TxnTrace, 291 }) 292 293 expect := `[ 294 1417136460000000, 295 123000, 296 "WebTransaction/Go/hello", 297 "/url", 298 [ 299 0, 300 {}, 301 {}, 302 [ 303 0, 304 123000, 305 "ROOT", 306 {}, 307 [ 308 [ 309 0, 310 123000, 311 "WebTransaction/Go/hello", 312 {}, 313 [ 314 [ 315 0, 316 5000, 317 "Custom/5", 318 {}, 319 [] 320 ], 321 [ 322 9000, 323 15000, 324 "Custom/6", 325 {}, 326 [] 327 ], 328 [ 329 18000, 330 25000, 331 "Custom/7", 332 {}, 333 [] 334 ], 335 [ 336 27000, 337 35000, 338 "Custom/8", 339 {}, 340 [] 341 ], 342 [ 343 36000, 344 45000, 345 "Custom/9", 346 {}, 347 [] 348 ] 349 ] 350 ] 351 ] 352 ], 353 { 354 "agentAttributes":{}, 355 "userAttributes":{}, 356 "intrinsics":{} 357 } 358 ], 359 "", 360 null, 361 false, 362 null, 363 "" 364 ]` 365 expect = CompactJSONString(expect) 366 js, err := ht.slice()[0].MarshalJSON() 367 if nil != err { 368 t.Fatal(err) 369 } 370 if string(js) != expect { 371 t.Error(string(js), expect) 372 } 373 } 374 375 func TestTxnTraceSegmentThreshold(t *testing.T) { 376 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 377 tr := &TxnData{} 378 tr.TxnTrace.Enabled = true 379 tr.TxnTrace.StackTraceThreshold = 1 * time.Hour 380 tr.TxnTrace.SegmentThreshold = 7 * time.Second 381 tr.TxnTrace.maxNodes = 5 382 383 durations := []int{5, 4, 6, 3, 7, 2, 8, 1, 9} 384 now := start 385 for _, d := range durations { 386 s := StartSegment(tr, now) 387 now = now.Add(time.Duration(d) * time.Second) 388 EndBasicSegment(tr, s, now, strconv.Itoa(d)) 389 } 390 391 acfg := CreateAttributeConfig(sampleAttributeConfigInput, true) 392 attr := NewAttributes(acfg) 393 394 ht := newHarvestTraces() 395 ht.regular.addTxnTrace(&HarvestTrace{ 396 TxnEvent: TxnEvent{ 397 Start: start, 398 Duration: 123 * time.Second, 399 FinalName: "WebTransaction/Go/hello", 400 CleanURL: "/url", 401 Attrs: attr, 402 }, 403 Trace: tr.TxnTrace, 404 }) 405 406 expect := `[ 407 1417136460000000, 408 123000, 409 "WebTransaction/Go/hello", 410 "/url", 411 [ 412 0, 413 {}, 414 {}, 415 [ 416 0, 417 123000, 418 "ROOT", 419 {}, 420 [ 421 [ 422 0, 423 123000, 424 "WebTransaction/Go/hello", 425 {}, 426 [ 427 [ 428 18000, 429 25000, 430 "Custom/7", 431 {}, 432 [] 433 ], 434 [ 435 27000, 436 35000, 437 "Custom/8", 438 {}, 439 [] 440 ], 441 [ 442 36000, 443 45000, 444 "Custom/9", 445 {}, 446 [] 447 ] 448 ] 449 ] 450 ] 451 ], 452 { 453 "agentAttributes":{}, 454 "userAttributes":{}, 455 "intrinsics":{} 456 } 457 ], 458 "", 459 null, 460 false, 461 null, 462 "" 463 ]` 464 expect = CompactJSONString(expect) 465 js, err := ht.slice()[0].MarshalJSON() 466 if nil != err { 467 t.Fatal(err) 468 } 469 if string(js) != expect { 470 t.Error(string(js), expect) 471 } 472 } 473 474 func TestEmptyHarvestTraces(t *testing.T) { 475 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 476 ht := newHarvestTraces() 477 js, err := ht.Data("12345", start) 478 if nil != err || nil != js { 479 t.Error(string(js), err) 480 } 481 } 482 483 func TestLongestTraceSaved(t *testing.T) { 484 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 485 tr := &TxnData{} 486 tr.TxnTrace.Enabled = true 487 488 acfg := CreateAttributeConfig(sampleAttributeConfigInput, true) 489 attr := NewAttributes(acfg) 490 ht := newHarvestTraces() 491 492 ht.Witness(HarvestTrace{ 493 TxnEvent: TxnEvent{ 494 Start: start, 495 Duration: 3 * time.Second, 496 FinalName: "WebTransaction/Go/3", 497 CleanURL: "/url/3", 498 Attrs: attr, 499 }, 500 Trace: tr.TxnTrace, 501 }) 502 ht.Witness(HarvestTrace{ 503 TxnEvent: TxnEvent{ 504 Start: start, 505 Duration: 5 * time.Second, 506 FinalName: "WebTransaction/Go/5", 507 CleanURL: "/url/5", 508 Attrs: attr, 509 }, 510 Trace: tr.TxnTrace, 511 }) 512 ht.Witness(HarvestTrace{ 513 TxnEvent: TxnEvent{ 514 Start: start, 515 Duration: 4 * time.Second, 516 FinalName: "WebTransaction/Go/4", 517 CleanURL: "/url/4", 518 Attrs: attr, 519 }, 520 Trace: tr.TxnTrace, 521 }) 522 523 expect := CompactJSONString(` 524 [ 525 "12345", 526 [ 527 [ 528 1417136460000000,5000,"WebTransaction/Go/5","/url/5", 529 [ 530 0,{},{}, 531 [0,5000,"ROOT",{}, 532 [[0,5000,"WebTransaction/Go/5",{},[]]] 533 ], 534 { 535 "agentAttributes":{}, 536 "userAttributes":{}, 537 "intrinsics":{} 538 } 539 ], 540 "",null,false,null,"" 541 ] 542 ] 543 ]`) 544 js, err := ht.Data("12345", start) 545 if nil != err || string(js) != expect { 546 t.Error(err, string(js), expect) 547 } 548 } 549 550 func TestTxnTraceStackTraceThreshold(t *testing.T) { 551 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 552 tr := &TxnData{} 553 tr.TxnTrace.Enabled = true 554 tr.TxnTrace.StackTraceThreshold = 2 * time.Second 555 tr.TxnTrace.SegmentThreshold = 0 556 tr.TxnTrace.maxNodes = 5 557 558 // below stack trace threshold 559 t1 := StartSegment(tr, start.Add(1*time.Second)) 560 EndBasicSegment(tr, t1, start.Add(2*time.Second), "t1") 561 562 // not above stack trace threshold w/out params 563 t2 := StartSegment(tr, start.Add(2*time.Second)) 564 EndDatastoreSegment(EndDatastoreParams{ 565 Tracer: tr, 566 Start: t2, 567 Now: start.Add(4 * time.Second), 568 Product: "MySQL", 569 Collection: "my_table", 570 Operation: "SELECT", 571 }) 572 573 // node above stack trace threshold w/ params 574 t3 := StartSegment(tr, start.Add(4*time.Second)) 575 EndExternalSegment(tr, t3, start.Add(6*time.Second), parseURL("http://example.com/zip/zap?secret=shhh"), nil) 576 577 p := tr.TxnTrace.nodes[0].params 578 if nil != p { 579 t.Error(p) 580 } 581 p = tr.TxnTrace.nodes[1].params 582 if nil == p || nil == p.StackTrace || "" != p.CleanURL { 583 t.Error(p) 584 } 585 p = tr.TxnTrace.nodes[2].params 586 if nil == p || nil == p.StackTrace || "http://example.com/zip/zap" != p.CleanURL { 587 t.Error(p) 588 } 589 } 590 591 func TestTxnTraceSynthetics(t *testing.T) { 592 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 593 tr := &TxnData{} 594 tr.TxnTrace.Enabled = true 595 596 acfg := CreateAttributeConfig(sampleAttributeConfigInput, true) 597 attr := NewAttributes(acfg) 598 ht := newHarvestTraces() 599 600 ht.Witness(HarvestTrace{ 601 TxnEvent: TxnEvent{ 602 Start: start, 603 Duration: 3 * time.Second, 604 FinalName: "WebTransaction/Go/3", 605 CleanURL: "/url/3", 606 Attrs: attr, 607 CrossProcess: TxnCrossProcess{ 608 Type: txnCrossProcessSynthetics, 609 Synthetics: &cat.SyntheticsHeader{ 610 ResourceID: "resource", 611 }, 612 }, 613 }, 614 Trace: tr.TxnTrace, 615 }) 616 ht.Witness(HarvestTrace{ 617 TxnEvent: TxnEvent{ 618 Start: start, 619 Duration: 5 * time.Second, 620 FinalName: "WebTransaction/Go/5", 621 CleanURL: "/url/5", 622 Attrs: attr, 623 CrossProcess: TxnCrossProcess{ 624 Type: txnCrossProcessSynthetics, 625 Synthetics: &cat.SyntheticsHeader{ 626 ResourceID: "resource", 627 }, 628 }, 629 }, 630 Trace: tr.TxnTrace, 631 }) 632 ht.Witness(HarvestTrace{ 633 TxnEvent: TxnEvent{ 634 Start: start, 635 Duration: 4 * time.Second, 636 FinalName: "WebTransaction/Go/4", 637 CleanURL: "/url/4", 638 Attrs: attr, 639 CrossProcess: TxnCrossProcess{ 640 Type: txnCrossProcessSynthetics, 641 Synthetics: &cat.SyntheticsHeader{ 642 ResourceID: "resource", 643 }, 644 }, 645 }, 646 Trace: tr.TxnTrace, 647 }) 648 649 expect := CompactJSONString(` 650 [ 651 "12345", 652 [ 653 [ 654 1417136460000000,3000,"WebTransaction/Go/3","/url/3", 655 [ 656 0,{},{}, 657 [0,3000,"ROOT",{}, 658 [[0,3000,"WebTransaction/Go/3",{},[]]] 659 ], 660 { 661 "agentAttributes":{}, 662 "userAttributes":{}, 663 "intrinsics":{ 664 "synthetics_resource_id": "resource" 665 } 666 } 667 ], 668 "",null,false,null,"resource" 669 ], 670 [ 671 1417136460000000,5000,"WebTransaction/Go/5","/url/5", 672 [ 673 0,{},{}, 674 [0,5000,"ROOT",{}, 675 [[0,5000,"WebTransaction/Go/5",{},[]]] 676 ], 677 { 678 "agentAttributes":{}, 679 "userAttributes":{}, 680 "intrinsics":{ 681 "synthetics_resource_id": "resource" 682 } 683 } 684 ], 685 "",null,false,null,"resource" 686 ], 687 [ 688 1417136460000000,4000,"WebTransaction/Go/4","/url/4", 689 [ 690 0,{},{}, 691 [0,4000,"ROOT",{}, 692 [[0,4000,"WebTransaction/Go/4",{},[]]] 693 ], 694 { 695 "agentAttributes":{}, 696 "userAttributes":{}, 697 "intrinsics":{ 698 "synthetics_resource_id": "resource" 699 } 700 } 701 ], 702 "",null,false,null,"resource" 703 ] 704 ] 705 ]`) 706 js, err := ht.Data("12345", start) 707 if nil != err || string(js) != expect { 708 t.Errorf("err=%v; actual=%s; expect=%s", err, string(js), expect) 709 } 710 }