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  }