github.com/newrelic/go-agent@v3.26.0+incompatible/internal/txn_trace_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  	"net/http"
     8  	"strconv"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/newrelic/go-agent/internal/cat"
    13  	"github.com/newrelic/go-agent/internal/logger"
    14  )
    15  
    16  func TestTxnTrace(t *testing.T) {
    17  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
    18  	txndata := &TxnData{}
    19  	thread := &Thread{}
    20  	txndata.TxnTrace.Enabled = true
    21  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
    22  	txndata.TxnTrace.SegmentThreshold = 0
    23  
    24  	t1 := StartSegment(txndata, thread, start.Add(1*time.Second))
    25  	t2 := StartSegment(txndata, thread, start.Add(2*time.Second))
    26  	qParams, err := vetQueryParameters(map[string]interface{}{"zip": 1})
    27  	if nil != err {
    28  		t.Error("error creating query params", err)
    29  	}
    30  	EndDatastoreSegment(EndDatastoreParams{
    31  		TxnData:            txndata,
    32  		Thread:             thread,
    33  		Start:              t2,
    34  		Now:                start.Add(3 * time.Second),
    35  		Product:            "MySQL",
    36  		Operation:          "SELECT",
    37  		Collection:         "my_table",
    38  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    39  		QueryParameters:    qParams,
    40  		Database:           "my_db",
    41  		Host:               "db-server-1",
    42  		PortPathOrID:       "3306",
    43  	})
    44  	t3 := StartSegment(txndata, thread, start.Add(4*time.Second))
    45  	EndExternalSegment(EndExternalParams{
    46  		TxnData: txndata,
    47  		Thread:  thread,
    48  		Start:   t3,
    49  		Now:     start.Add(5 * time.Second),
    50  		URL:     parseURL("http://example.com/zip/zap?secret=shhh"),
    51  		Logger:  logger.ShimLogger{},
    52  	})
    53  	EndBasicSegment(txndata, thread, t1, start.Add(6*time.Second), "t1")
    54  	t4 := StartSegment(txndata, thread, start.Add(7*time.Second))
    55  	t5 := StartSegment(txndata, thread, start.Add(8*time.Second))
    56  	t6 := StartSegment(txndata, thread, start.Add(9*time.Second))
    57  	EndBasicSegment(txndata, thread, t6, start.Add(10*time.Second), "t6")
    58  	EndBasicSegment(txndata, thread, t5, start.Add(11*time.Second), "t5")
    59  	t7 := StartSegment(txndata, thread, start.Add(12*time.Second))
    60  	EndDatastoreSegment(EndDatastoreParams{
    61  		TxnData:   txndata,
    62  		Thread:    thread,
    63  		Start:     t7,
    64  		Now:       start.Add(13 * time.Second),
    65  		Product:   "MySQL",
    66  		Operation: "SELECT",
    67  		// no collection
    68  	})
    69  	t8 := StartSegment(txndata, thread, start.Add(14*time.Second))
    70  	EndExternalSegment(EndExternalParams{
    71  		TxnData: txndata,
    72  		Thread:  thread,
    73  		Start:   t8,
    74  		Now:     start.Add(15 * time.Second),
    75  		URL:     nil,
    76  		Logger:  logger.ShimLogger{},
    77  	})
    78  	EndBasicSegment(txndata, thread, t4, start.Add(16*time.Second), "t4")
    79  
    80  	t9 := StartSegment(txndata, thread, start.Add(17*time.Second))
    81  	EndMessageSegment(EndMessageParams{
    82  		TxnData:         txndata,
    83  		Thread:          thread,
    84  		Start:           t9,
    85  		Now:             start.Add(18 * time.Second),
    86  		Logger:          nil,
    87  		DestinationName: "MyTopic",
    88  		Library:         "Kafka",
    89  		DestinationType: "Topic",
    90  	})
    91  
    92  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
    93  	attr := NewAttributes(acfg)
    94  	attr.Agent.Add(attributeRequestURI, "/url", nil)
    95  	AddUserAttribute(attr, "zap", 123, DestAll)
    96  
    97  	ht := newHarvestTraces()
    98  	ht.regular.addTxnTrace(&HarvestTrace{
    99  		TxnEvent: TxnEvent{
   100  			Start:     start,
   101  			Duration:  20 * time.Second,
   102  			TotalTime: 30 * time.Second,
   103  			FinalName: "WebTransaction/Go/hello",
   104  			Attrs:     attr,
   105  			BetterCAT: BetterCAT{
   106  				Enabled:  true,
   107  				ID:       "txn-id",
   108  				Priority: 0.5,
   109  			},
   110  		},
   111  		Trace: txndata.TxnTrace,
   112  	})
   113  
   114  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   115  		MetricName:      "WebTransaction/Go/hello",
   116  		UserAttributes:  map[string]interface{}{"zap": 123},
   117  		AgentAttributes: map[string]interface{}{"request.uri": "/url"},
   118  		Intrinsics: map[string]interface{}{
   119  			"guid":      "txn-id",
   120  			"traceId":   "txn-id",
   121  			"priority":  0.500000,
   122  			"sampled":   false,
   123  			"totalTime": 30,
   124  		},
   125  		Root: WantTraceSegment{
   126  			SegmentName:         "ROOT",
   127  			RelativeStartMillis: 0,
   128  			RelativeStopMillis:  20000,
   129  			Attributes:          map[string]interface{}{},
   130  			Children: []WantTraceSegment{{
   131  				SegmentName:         "WebTransaction/Go/hello",
   132  				RelativeStartMillis: 0,
   133  				RelativeStopMillis:  20000,
   134  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 20000},
   135  				Children: []WantTraceSegment{
   136  					{
   137  						SegmentName:         "Custom/t1",
   138  						RelativeStartMillis: 1000,
   139  						RelativeStopMillis:  6000,
   140  						Attributes:          map[string]interface{}{},
   141  						Children: []WantTraceSegment{
   142  							{
   143  								SegmentName:         "Datastore/statement/MySQL/my_table/SELECT",
   144  								RelativeStartMillis: 2000,
   145  								RelativeStopMillis:  3000,
   146  								Attributes: map[string]interface{}{
   147  									"db.instance":      "my_db",
   148  									"peer.hostname":    "db-server-1",
   149  									"peer.address":     "db-server-1:3306",
   150  									"db.statement":     "INSERT INTO users (name, age) VALUES ($1, $2)",
   151  									"query_parameters": "map[zip:1]",
   152  								},
   153  								Children: []WantTraceSegment{},
   154  							},
   155  							{
   156  								SegmentName:         "External/example.com/http",
   157  								RelativeStartMillis: 4000,
   158  								RelativeStopMillis:  5000,
   159  								Attributes: map[string]interface{}{
   160  									"http.url": "http://example.com/zip/zap",
   161  								},
   162  								Children: []WantTraceSegment{},
   163  							},
   164  						},
   165  					},
   166  					{
   167  						SegmentName:         "Custom/t4",
   168  						RelativeStartMillis: 7000,
   169  						RelativeStopMillis:  16000,
   170  						Attributes:          map[string]interface{}{},
   171  						Children: []WantTraceSegment{
   172  							{
   173  								SegmentName:         "Custom/t5",
   174  								RelativeStartMillis: 8000,
   175  								RelativeStopMillis:  11000,
   176  								Attributes:          map[string]interface{}{},
   177  								Children: []WantTraceSegment{
   178  									{
   179  										SegmentName:         "Custom/t6",
   180  										RelativeStartMillis: 9000,
   181  										RelativeStopMillis:  10000,
   182  										Attributes:          map[string]interface{}{},
   183  										Children:            []WantTraceSegment{},
   184  									},
   185  								},
   186  							},
   187  							{
   188  								SegmentName:         "Datastore/operation/MySQL/SELECT",
   189  								RelativeStartMillis: 12000,
   190  								RelativeStopMillis:  13000,
   191  								Attributes: map[string]interface{}{
   192  									"db.statement": "'SELECT' on 'unknown' using 'MySQL'",
   193  								},
   194  								Children: []WantTraceSegment{},
   195  							},
   196  							{
   197  								SegmentName:         "External/unknown/http",
   198  								RelativeStartMillis: 14000,
   199  								RelativeStopMillis:  15000,
   200  								Attributes:          map[string]interface{}{},
   201  								Children:            []WantTraceSegment{},
   202  							},
   203  						},
   204  					},
   205  					{
   206  						SegmentName:         "MessageBroker/Kafka/Topic/Produce/Named/MyTopic",
   207  						RelativeStartMillis: 17000,
   208  						RelativeStopMillis:  18000,
   209  						Attributes:          map[string]interface{}{},
   210  						Children:            []WantTraceSegment{},
   211  					},
   212  				},
   213  			}},
   214  		},
   215  	}})
   216  }
   217  
   218  func TestTxnTraceNoNodes(t *testing.T) {
   219  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   220  	txndata := &TxnData{}
   221  	txndata.TxnTrace.Enabled = true
   222  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
   223  	txndata.TxnTrace.SegmentThreshold = 0
   224  
   225  	ht := newHarvestTraces()
   226  	ht.regular.addTxnTrace(&HarvestTrace{
   227  		TxnEvent: TxnEvent{
   228  			Start:     start,
   229  			Duration:  20 * time.Second,
   230  			TotalTime: 30 * time.Second,
   231  			FinalName: "WebTransaction/Go/hello",
   232  			Attrs:     nil,
   233  			BetterCAT: BetterCAT{
   234  				Enabled:  true,
   235  				ID:       "txn-id",
   236  				Priority: 0.5,
   237  			},
   238  		},
   239  		Trace: txndata.TxnTrace,
   240  	})
   241  
   242  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   243  		MetricName:      "WebTransaction/Go/hello",
   244  		UserAttributes:  map[string]interface{}{},
   245  		AgentAttributes: map[string]interface{}{},
   246  		Intrinsics: map[string]interface{}{
   247  			"guid":      "txn-id",
   248  			"traceId":   "txn-id",
   249  			"priority":  0.500000,
   250  			"sampled":   false,
   251  			"totalTime": 30,
   252  		},
   253  		Root: WantTraceSegment{
   254  			SegmentName:         "ROOT",
   255  			RelativeStartMillis: 0,
   256  			RelativeStopMillis:  20000,
   257  			Attributes:          map[string]interface{}{},
   258  			Children: []WantTraceSegment{{
   259  				SegmentName:         "WebTransaction/Go/hello",
   260  				RelativeStartMillis: 0,
   261  				RelativeStopMillis:  20000,
   262  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 20000},
   263  				Children:            []WantTraceSegment{},
   264  			}},
   265  		},
   266  	}})
   267  }
   268  
   269  func TestTxnTraceAsync(t *testing.T) {
   270  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   271  	txndata := &TxnData{
   272  		TraceIDGenerator: NewTraceIDGenerator(12345),
   273  	}
   274  	thread1 := &Thread{}
   275  	txndata.TxnTrace.Enabled = true
   276  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
   277  	txndata.TxnTrace.SegmentThreshold = 0
   278  	txndata.BetterCAT.Sampled = true
   279  	txndata.SpanEventsEnabled = true
   280  	txndata.LazilyCalculateSampled = func() bool { return true }
   281  
   282  	t1s1 := StartSegment(txndata, thread1, start.Add(1*time.Second))
   283  	t1s2 := StartSegment(txndata, thread1, start.Add(2*time.Second))
   284  	thread2 := NewThread(txndata)
   285  	t2s1 := StartSegment(txndata, thread2, start.Add(3*time.Second))
   286  	EndBasicSegment(txndata, thread1, t1s2, start.Add(4*time.Second), "thread1.segment2")
   287  	EndBasicSegment(txndata, thread2, t2s1, start.Add(5*time.Second), "thread2.segment1")
   288  	thread3 := NewThread(txndata)
   289  	t3s1 := StartSegment(txndata, thread3, start.Add(6*time.Second))
   290  	t3s2 := StartSegment(txndata, thread3, start.Add(7*time.Second))
   291  	EndBasicSegment(txndata, thread1, t1s1, start.Add(8*time.Second), "thread1.segment1")
   292  	EndBasicSegment(txndata, thread3, t3s2, start.Add(9*time.Second), "thread3.segment2")
   293  	EndBasicSegment(txndata, thread3, t3s1, start.Add(10*time.Second), "thread3.segment1")
   294  
   295  	if tt := thread1.TotalTime(); tt != 7*time.Second {
   296  		t.Error(tt)
   297  	}
   298  	if tt := thread2.TotalTime(); tt != 2*time.Second {
   299  		t.Error(tt)
   300  	}
   301  	if tt := thread3.TotalTime(); tt != 4*time.Second {
   302  		t.Error(tt)
   303  	}
   304  
   305  	if len(txndata.spanEvents) != 5 {
   306  		t.Fatal(txndata.spanEvents)
   307  	}
   308  	for _, e := range txndata.spanEvents {
   309  		if e.GUID == "" || e.ParentID == "" {
   310  			t.Error(e.GUID, e.ParentID)
   311  		}
   312  	}
   313  	spanEventT1S2 := txndata.spanEvents[0]
   314  	spanEventT2S1 := txndata.spanEvents[1]
   315  	spanEventT1S1 := txndata.spanEvents[2]
   316  	spanEventT3S2 := txndata.spanEvents[3]
   317  	spanEventT3S1 := txndata.spanEvents[4]
   318  
   319  	if txndata.rootSpanID == "" {
   320  		t.Error(txndata.rootSpanID)
   321  	}
   322  	if spanEventT1S1.ParentID != txndata.rootSpanID {
   323  		t.Error(spanEventT1S1.ParentID, txndata.rootSpanID)
   324  	}
   325  	if spanEventT1S2.ParentID != spanEventT1S1.GUID {
   326  		t.Error(spanEventT1S2.ParentID, spanEventT1S1.GUID)
   327  	}
   328  	if spanEventT2S1.ParentID != txndata.rootSpanID {
   329  		t.Error(spanEventT2S1.ParentID, txndata.rootSpanID)
   330  	}
   331  	if spanEventT3S1.ParentID != txndata.rootSpanID {
   332  		t.Error(spanEventT3S1.ParentID, txndata.rootSpanID)
   333  	}
   334  	if spanEventT3S2.ParentID != spanEventT3S1.GUID {
   335  		t.Error(spanEventT3S2.ParentID, spanEventT3S1.GUID)
   336  	}
   337  
   338  	ht := newHarvestTraces()
   339  	ht.regular.addTxnTrace(&HarvestTrace{
   340  		TxnEvent: TxnEvent{
   341  			Start:     start,
   342  			Duration:  20 * time.Second,
   343  			TotalTime: 30 * time.Second,
   344  			FinalName: "WebTransaction/Go/hello",
   345  			Attrs:     nil,
   346  			BetterCAT: BetterCAT{
   347  				Enabled:  true,
   348  				ID:       "txn-id",
   349  				Priority: 0.5,
   350  			},
   351  		},
   352  		Trace: txndata.TxnTrace,
   353  	})
   354  
   355  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   356  		MetricName:      "WebTransaction/Go/hello",
   357  		UserAttributes:  map[string]interface{}{},
   358  		AgentAttributes: map[string]interface{}{},
   359  		Intrinsics: map[string]interface{}{
   360  			"totalTime": 30,
   361  			"guid":      "txn-id",
   362  			"traceId":   "txn-id",
   363  			"priority":  0.500000,
   364  			"sampled":   false,
   365  		},
   366  		Root: WantTraceSegment{
   367  			SegmentName:         "ROOT",
   368  			RelativeStartMillis: 0,
   369  			RelativeStopMillis:  20000,
   370  			Attributes:          map[string]interface{}{},
   371  			Children: []WantTraceSegment{{
   372  				SegmentName:         "WebTransaction/Go/hello",
   373  				RelativeStartMillis: 0,
   374  				RelativeStopMillis:  20000,
   375  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 20000},
   376  				Children: []WantTraceSegment{
   377  					{
   378  						SegmentName:         "Custom/thread1.segment1",
   379  						RelativeStartMillis: 1000,
   380  						RelativeStopMillis:  8000,
   381  						Attributes:          map[string]interface{}{},
   382  						Children: []WantTraceSegment{
   383  							{
   384  								SegmentName:         "Custom/thread1.segment2",
   385  								RelativeStartMillis: 2000,
   386  								RelativeStopMillis:  4000,
   387  								Attributes:          map[string]interface{}{},
   388  								Children:            []WantTraceSegment{},
   389  							},
   390  						},
   391  					},
   392  					{
   393  						SegmentName:         "Custom/thread2.segment1",
   394  						RelativeStartMillis: 3000,
   395  						RelativeStopMillis:  5000,
   396  						Attributes:          map[string]interface{}{},
   397  						Children:            []WantTraceSegment{},
   398  					},
   399  					{
   400  						SegmentName:         "Custom/thread3.segment1",
   401  						RelativeStartMillis: 6000,
   402  						RelativeStopMillis:  10000,
   403  						Attributes:          map[string]interface{}{},
   404  						Children: []WantTraceSegment{
   405  							{
   406  								SegmentName:         "Custom/thread3.segment2",
   407  								RelativeStartMillis: 7000,
   408  								RelativeStopMillis:  9000,
   409  								Attributes:          map[string]interface{}{},
   410  								Children:            []WantTraceSegment{},
   411  							},
   412  						},
   413  					},
   414  				},
   415  			}},
   416  		},
   417  	}})
   418  }
   419  
   420  func TestTxnTraceOldCAT(t *testing.T) {
   421  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   422  	txndata := &TxnData{}
   423  	thread := &Thread{}
   424  	txndata.TxnTrace.Enabled = true
   425  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
   426  	txndata.TxnTrace.SegmentThreshold = 0
   427  
   428  	txndata.CrossProcess.Init(true, false, replyAccountOne)
   429  	txndata.CrossProcess.GUID = "0123456789"
   430  	appData, err := txndata.CrossProcess.CreateAppData("WebTransaction/Go/otherService", 2*time.Second, 3*time.Second, 123)
   431  	if nil != err {
   432  		t.Fatal(err)
   433  	}
   434  	resp := &http.Response{
   435  		Header: AppDataToHTTPHeader(appData),
   436  	}
   437  	t3 := StartSegment(txndata, thread, start.Add(4*time.Second))
   438  	EndExternalSegment(EndExternalParams{
   439  		TxnData:  txndata,
   440  		Thread:   thread,
   441  		Start:    t3,
   442  		Now:      start.Add(5 * time.Second),
   443  		URL:      parseURL("http://example.com/zip/zap?secret=shhh"),
   444  		Response: resp,
   445  		Logger:   logger.ShimLogger{},
   446  	})
   447  
   448  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   449  	attr := NewAttributes(acfg)
   450  	attr.Agent.Add(attributeRequestURI, "/url", nil)
   451  	AddUserAttribute(attr, "zap", 123, DestAll)
   452  
   453  	ht := newHarvestTraces()
   454  	ht.regular.addTxnTrace(&HarvestTrace{
   455  		TxnEvent: TxnEvent{
   456  			Start:     start,
   457  			Duration:  20 * time.Second,
   458  			TotalTime: 30 * time.Second,
   459  			FinalName: "WebTransaction/Go/hello",
   460  			Attrs:     attr,
   461  		},
   462  		Trace: txndata.TxnTrace,
   463  	})
   464  
   465  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   466  		MetricName:      "WebTransaction/Go/hello",
   467  		UserAttributes:  map[string]interface{}{"zap": 123},
   468  		AgentAttributes: map[string]interface{}{"request.uri": "/url"},
   469  		Intrinsics:      map[string]interface{}{"totalTime": 30},
   470  		Root: WantTraceSegment{
   471  			SegmentName:         "ROOT",
   472  			RelativeStartMillis: 0,
   473  			RelativeStopMillis:  20000,
   474  			Attributes:          map[string]interface{}{},
   475  			Children: []WantTraceSegment{{
   476  				SegmentName:         "WebTransaction/Go/hello",
   477  				RelativeStartMillis: 0,
   478  				RelativeStopMillis:  20000,
   479  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 20000},
   480  				Children: []WantTraceSegment{
   481  					{
   482  						SegmentName:         "ExternalTransaction/example.com/1#1/WebTransaction/Go/otherService",
   483  						RelativeStartMillis: 4000,
   484  						RelativeStopMillis:  5000,
   485  						Attributes: map[string]interface{}{
   486  							"http.url":         "http://example.com/zip/zap",
   487  							"transaction_guid": "0123456789",
   488  						},
   489  						Children: []WantTraceSegment{},
   490  					},
   491  				},
   492  			}},
   493  		},
   494  	}})
   495  }
   496  
   497  func TestTxnTraceExcludeURI(t *testing.T) {
   498  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   499  	tr := &TxnData{}
   500  	tr.TxnTrace.Enabled = true
   501  	tr.TxnTrace.StackTraceThreshold = 1 * time.Hour
   502  	tr.TxnTrace.SegmentThreshold = 0
   503  
   504  	c := sampleAttributeConfigInput
   505  	c.TransactionTracer.Exclude = []string{"request.uri"}
   506  	acfg := CreateAttributeConfig(c, true)
   507  	attr := NewAttributes(acfg)
   508  	attr.Agent.Add(attributeRequestURI, "/url", nil)
   509  
   510  	ht := newHarvestTraces()
   511  	ht.regular.addTxnTrace(&HarvestTrace{
   512  		TxnEvent: TxnEvent{
   513  			Start:     start,
   514  			Duration:  20 * time.Second,
   515  			FinalName: "WebTransaction/Go/hello",
   516  			Attrs:     attr,
   517  			BetterCAT: BetterCAT{
   518  				Enabled:  true,
   519  				ID:       "txn-id",
   520  				Priority: 0.5,
   521  			},
   522  		},
   523  		Trace: tr.TxnTrace,
   524  	})
   525  
   526  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   527  		MetricName:      "WebTransaction/Go/hello",
   528  		UserAttributes:  map[string]interface{}{},
   529  		AgentAttributes: map[string]interface{}{},
   530  		Intrinsics: map[string]interface{}{
   531  			"totalTime": 0,
   532  			"guid":      "txn-id",
   533  			"traceId":   "txn-id",
   534  			"priority":  0.500000,
   535  			"sampled":   false,
   536  		},
   537  		Root: WantTraceSegment{
   538  			SegmentName:         "ROOT",
   539  			RelativeStartMillis: 0,
   540  			RelativeStopMillis:  20000,
   541  			Attributes:          map[string]interface{}{},
   542  			Children: []WantTraceSegment{{
   543  				SegmentName:         "WebTransaction/Go/hello",
   544  				RelativeStartMillis: 0,
   545  				RelativeStopMillis:  20000,
   546  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 20000},
   547  				Children:            []WantTraceSegment{},
   548  			}},
   549  		},
   550  	}})
   551  }
   552  
   553  func TestTxnTraceNoSegmentsNoAttributes(t *testing.T) {
   554  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   555  	txndata := &TxnData{}
   556  	txndata.TxnTrace.Enabled = true
   557  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
   558  	txndata.TxnTrace.SegmentThreshold = 0
   559  
   560  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   561  	attr := NewAttributes(acfg)
   562  
   563  	ht := newHarvestTraces()
   564  	ht.regular.addTxnTrace(&HarvestTrace{
   565  		TxnEvent: TxnEvent{
   566  			Start:     start,
   567  			Duration:  20 * time.Second,
   568  			TotalTime: 30 * time.Second,
   569  			FinalName: "WebTransaction/Go/hello",
   570  			Attrs:     attr,
   571  			BetterCAT: BetterCAT{
   572  				Enabled:  true,
   573  				ID:       "txn-id",
   574  				Priority: 0.5,
   575  			},
   576  		},
   577  		Trace: txndata.TxnTrace,
   578  	})
   579  
   580  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   581  		MetricName:      "WebTransaction/Go/hello",
   582  		UserAttributes:  map[string]interface{}{},
   583  		AgentAttributes: map[string]interface{}{},
   584  		Intrinsics: map[string]interface{}{
   585  			"totalTime": 30,
   586  			"guid":      "txn-id",
   587  			"traceId":   "txn-id",
   588  			"priority":  0.500000,
   589  			"sampled":   false,
   590  		},
   591  		Root: WantTraceSegment{
   592  			SegmentName:         "ROOT",
   593  			RelativeStartMillis: 0,
   594  			RelativeStopMillis:  20000,
   595  			Attributes:          map[string]interface{}{},
   596  			Children: []WantTraceSegment{{
   597  				SegmentName:         "WebTransaction/Go/hello",
   598  				RelativeStartMillis: 0,
   599  				RelativeStopMillis:  20000,
   600  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 20000},
   601  				Children:            []WantTraceSegment{},
   602  			}},
   603  		},
   604  	}})
   605  }
   606  
   607  func TestTxnTraceSlowestNodesSaved(t *testing.T) {
   608  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   609  	txndata := &TxnData{}
   610  	thread := &Thread{}
   611  	txndata.TxnTrace.Enabled = true
   612  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
   613  	txndata.TxnTrace.SegmentThreshold = 0
   614  	txndata.TxnTrace.maxNodes = 5
   615  
   616  	durations := []int{5, 4, 6, 3, 7, 2, 8, 1, 9}
   617  	now := start
   618  	for _, d := range durations {
   619  		s := StartSegment(txndata, thread, now)
   620  		now = now.Add(time.Duration(d) * time.Second)
   621  		EndBasicSegment(txndata, thread, s, now, strconv.Itoa(d))
   622  	}
   623  
   624  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   625  	attr := NewAttributes(acfg)
   626  	attr.Agent.Add(attributeRequestURI, "/url", nil)
   627  
   628  	ht := newHarvestTraces()
   629  	ht.regular.addTxnTrace(&HarvestTrace{
   630  		TxnEvent: TxnEvent{
   631  			Start:     start,
   632  			Duration:  123 * time.Second,
   633  			TotalTime: 200 * time.Second,
   634  			FinalName: "WebTransaction/Go/hello",
   635  			Attrs:     attr,
   636  			BetterCAT: BetterCAT{
   637  				Enabled:  true,
   638  				ID:       "txn-id",
   639  				Priority: 0.5,
   640  			},
   641  		},
   642  		Trace: txndata.TxnTrace,
   643  	})
   644  
   645  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   646  		MetricName:      "WebTransaction/Go/hello",
   647  		UserAttributes:  map[string]interface{}{},
   648  		AgentAttributes: map[string]interface{}{"request.uri": "/url"},
   649  		Intrinsics: map[string]interface{}{
   650  			"totalTime": 200,
   651  			"guid":      "txn-id",
   652  			"traceId":   "txn-id",
   653  			"priority":  0.500000,
   654  			"sampled":   false,
   655  		},
   656  		Root: WantTraceSegment{
   657  			SegmentName:         "ROOT",
   658  			RelativeStartMillis: 0,
   659  			RelativeStopMillis:  123000,
   660  			Attributes:          map[string]interface{}{},
   661  			Children: []WantTraceSegment{{
   662  				SegmentName:         "WebTransaction/Go/hello",
   663  				RelativeStartMillis: 0,
   664  				RelativeStopMillis:  123000,
   665  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 123000},
   666  				Children: []WantTraceSegment{
   667  					{
   668  						SegmentName:         "Custom/5",
   669  						RelativeStartMillis: 0,
   670  						RelativeStopMillis:  5000,
   671  						Attributes:          map[string]interface{}{},
   672  						Children:            []WantTraceSegment{},
   673  					},
   674  					{
   675  						SegmentName:         "Custom/6",
   676  						RelativeStartMillis: 9000,
   677  						RelativeStopMillis:  15000,
   678  						Attributes:          map[string]interface{}{},
   679  						Children:            []WantTraceSegment{},
   680  					},
   681  					{
   682  						SegmentName:         "Custom/7",
   683  						RelativeStartMillis: 18000,
   684  						RelativeStopMillis:  25000,
   685  						Attributes:          map[string]interface{}{},
   686  						Children:            []WantTraceSegment{},
   687  					},
   688  					{
   689  						SegmentName:         "Custom/8",
   690  						RelativeStartMillis: 27000,
   691  						RelativeStopMillis:  35000,
   692  						Attributes:          map[string]interface{}{},
   693  						Children:            []WantTraceSegment{},
   694  					},
   695  					{
   696  						SegmentName:         "Custom/9",
   697  						RelativeStartMillis: 36000,
   698  						RelativeStopMillis:  45000,
   699  						Attributes:          map[string]interface{}{},
   700  						Children:            []WantTraceSegment{},
   701  					},
   702  				},
   703  			}},
   704  		},
   705  	}})
   706  }
   707  
   708  func TestTxnTraceSegmentThreshold(t *testing.T) {
   709  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   710  	txndata := &TxnData{}
   711  	thread := &Thread{}
   712  	txndata.TxnTrace.Enabled = true
   713  	txndata.TxnTrace.StackTraceThreshold = 1 * time.Hour
   714  	txndata.TxnTrace.SegmentThreshold = 7 * time.Second
   715  	txndata.TxnTrace.maxNodes = 5
   716  
   717  	durations := []int{5, 4, 6, 3, 7, 2, 8, 1, 9}
   718  	now := start
   719  	for _, d := range durations {
   720  		s := StartSegment(txndata, thread, now)
   721  		now = now.Add(time.Duration(d) * time.Second)
   722  		EndBasicSegment(txndata, thread, s, now, strconv.Itoa(d))
   723  	}
   724  
   725  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   726  	attr := NewAttributes(acfg)
   727  	attr.Agent.Add(attributeRequestURI, "/url", nil)
   728  
   729  	ht := newHarvestTraces()
   730  	ht.regular.addTxnTrace(&HarvestTrace{
   731  		TxnEvent: TxnEvent{
   732  			Start:     start,
   733  			Duration:  123 * time.Second,
   734  			TotalTime: 200 * time.Second,
   735  			FinalName: "WebTransaction/Go/hello",
   736  			Attrs:     attr,
   737  			BetterCAT: BetterCAT{
   738  				Enabled:  true,
   739  				ID:       "txn-id",
   740  				Priority: 0.5,
   741  			},
   742  		},
   743  		Trace: txndata.TxnTrace,
   744  	})
   745  
   746  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   747  		MetricName:      "WebTransaction/Go/hello",
   748  		UserAttributes:  map[string]interface{}{},
   749  		AgentAttributes: map[string]interface{}{"request.uri": "/url"},
   750  		Intrinsics: map[string]interface{}{
   751  			"totalTime": 200,
   752  			"guid":      "txn-id",
   753  			"traceId":   "txn-id",
   754  			"priority":  0.500000,
   755  			"sampled":   false,
   756  		},
   757  		Root: WantTraceSegment{
   758  			SegmentName:         "ROOT",
   759  			RelativeStartMillis: 0,
   760  			RelativeStopMillis:  123000,
   761  			Attributes:          map[string]interface{}{},
   762  			Children: []WantTraceSegment{{
   763  				SegmentName:         "WebTransaction/Go/hello",
   764  				RelativeStartMillis: 0,
   765  				RelativeStopMillis:  123000,
   766  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 123000},
   767  				Children: []WantTraceSegment{
   768  					{
   769  						SegmentName:         "Custom/7",
   770  						RelativeStartMillis: 18000,
   771  						RelativeStopMillis:  25000,
   772  						Attributes:          map[string]interface{}{},
   773  						Children:            []WantTraceSegment{},
   774  					},
   775  					{
   776  						SegmentName:         "Custom/8",
   777  						RelativeStartMillis: 27000,
   778  						RelativeStopMillis:  35000,
   779  						Attributes:          map[string]interface{}{},
   780  						Children:            []WantTraceSegment{},
   781  					},
   782  					{
   783  						SegmentName:         "Custom/9",
   784  						RelativeStartMillis: 36000,
   785  						RelativeStopMillis:  45000,
   786  						Attributes:          map[string]interface{}{},
   787  						Children:            []WantTraceSegment{},
   788  					},
   789  				},
   790  			}},
   791  		},
   792  	}})
   793  }
   794  
   795  func TestEmptyHarvestTraces(t *testing.T) {
   796  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   797  	ht := newHarvestTraces()
   798  	js, err := ht.Data("12345", start)
   799  	if nil != err || nil != js {
   800  		t.Error(string(js), err)
   801  	}
   802  }
   803  
   804  func TestLongestTraceSaved(t *testing.T) {
   805  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   806  	txndata := &TxnData{}
   807  	txndata.TxnTrace.Enabled = true
   808  
   809  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   810  	attr := NewAttributes(acfg)
   811  	attr.Agent.Add(attributeRequestURI, "/url", nil)
   812  	ht := newHarvestTraces()
   813  
   814  	ht.Witness(HarvestTrace{
   815  		TxnEvent: TxnEvent{
   816  			Start:     start,
   817  			Duration:  3 * time.Second,
   818  			TotalTime: 4 * time.Second,
   819  			FinalName: "WebTransaction/Go/3",
   820  			Attrs:     attr,
   821  			BetterCAT: BetterCAT{
   822  				Enabled:  true,
   823  				ID:       "txn-id-3",
   824  				Priority: 0.5,
   825  			},
   826  		},
   827  		Trace: txndata.TxnTrace,
   828  	})
   829  	ht.Witness(HarvestTrace{
   830  		TxnEvent: TxnEvent{
   831  			Start:     start,
   832  			Duration:  5 * time.Second,
   833  			TotalTime: 6 * time.Second,
   834  			FinalName: "WebTransaction/Go/5",
   835  			Attrs:     attr,
   836  			BetterCAT: BetterCAT{
   837  				Enabled:  true,
   838  				ID:       "txn-id-5",
   839  				Priority: 0.5,
   840  			},
   841  		},
   842  		Trace: txndata.TxnTrace,
   843  	})
   844  	ht.Witness(HarvestTrace{
   845  		TxnEvent: TxnEvent{
   846  			Start:     start,
   847  			Duration:  4 * time.Second,
   848  			TotalTime: 7 * time.Second,
   849  			FinalName: "WebTransaction/Go/4",
   850  			Attrs:     attr,
   851  			BetterCAT: BetterCAT{
   852  				Enabled:  true,
   853  				ID:       "txn-id-4",
   854  				Priority: 0.5,
   855  			},
   856  		},
   857  		Trace: txndata.TxnTrace,
   858  	})
   859  
   860  	ExpectTxnTraces(t, ht, []WantTxnTrace{{
   861  		MetricName:      "WebTransaction/Go/5",
   862  		UserAttributes:  map[string]interface{}{},
   863  		AgentAttributes: map[string]interface{}{"request.uri": "/url"},
   864  		Intrinsics: map[string]interface{}{
   865  			"totalTime": 6,
   866  			"guid":      "txn-id-5",
   867  			"traceId":   "txn-id-5",
   868  			"priority":  0.500000,
   869  			"sampled":   false,
   870  		},
   871  		Root: WantTraceSegment{
   872  			SegmentName:         "ROOT",
   873  			RelativeStartMillis: 0,
   874  			RelativeStopMillis:  5000,
   875  			Attributes:          map[string]interface{}{},
   876  			Children: []WantTraceSegment{{
   877  				SegmentName:         "WebTransaction/Go/5",
   878  				RelativeStartMillis: 0,
   879  				RelativeStopMillis:  5000,
   880  				Attributes:          map[string]interface{}{"exclusive_duration_millis": 5000},
   881  				Children:            []WantTraceSegment{},
   882  			}},
   883  		},
   884  	}})
   885  }
   886  
   887  func TestTxnTraceStackTraceThreshold(t *testing.T) {
   888  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   889  	txndata := &TxnData{}
   890  	thread := &Thread{}
   891  	txndata.TxnTrace.Enabled = true
   892  	txndata.TxnTrace.StackTraceThreshold = 2 * time.Second
   893  	txndata.TxnTrace.SegmentThreshold = 0
   894  	txndata.TxnTrace.maxNodes = 5
   895  
   896  	// below stack trace threshold
   897  	t1 := StartSegment(txndata, thread, start.Add(1*time.Second))
   898  	EndBasicSegment(txndata, thread, t1, start.Add(2*time.Second), "t1")
   899  
   900  	// not above stack trace threshold w/out params
   901  	t2 := StartSegment(txndata, thread, start.Add(2*time.Second))
   902  	EndBasicSegment(txndata, thread, t2, start.Add(4*time.Second), "t2")
   903  
   904  	// node above stack trace threshold w/ params
   905  	t3 := StartSegment(txndata, thread, start.Add(4*time.Second))
   906  	EndExternalSegment(EndExternalParams{
   907  		TxnData: txndata,
   908  		Thread:  thread,
   909  		Start:   t3,
   910  		Now:     start.Add(6 * time.Second),
   911  		URL:     parseURL("http://example.com/zip/zap?secret=shhh"),
   912  		Logger:  logger.ShimLogger{},
   913  	})
   914  
   915  	ht := newHarvestTraces()
   916  	ht.Witness(HarvestTrace{
   917  		TxnEvent: TxnEvent{
   918  			Start:     start,
   919  			Duration:  3 * time.Second,
   920  			TotalTime: 4 * time.Second,
   921  			FinalName: "WebTransaction/Go/3",
   922  		},
   923  		Trace: txndata.TxnTrace,
   924  	})
   925  
   926  	ExpectTxnTraces(t, ht, []WantTxnTrace{
   927  		{
   928  			MetricName:      "WebTransaction/Go/3",
   929  			UserAttributes:  map[string]interface{}{},
   930  			AgentAttributes: map[string]interface{}{},
   931  			Intrinsics:      map[string]interface{}{"totalTime": 4},
   932  			Root: WantTraceSegment{
   933  				SegmentName:         "ROOT",
   934  				RelativeStartMillis: 0,
   935  				RelativeStopMillis:  3000,
   936  				Attributes:          map[string]interface{}{},
   937  				Children: []WantTraceSegment{{
   938  					SegmentName:         "WebTransaction/Go/3",
   939  					RelativeStartMillis: 0,
   940  					RelativeStopMillis:  3000,
   941  					Attributes:          map[string]interface{}{"exclusive_duration_millis": 3000},
   942  					Children: []WantTraceSegment{
   943  						{
   944  							SegmentName:         "Custom/t1",
   945  							RelativeStartMillis: 1000,
   946  							RelativeStopMillis:  2000,
   947  							Attributes:          map[string]interface{}{},
   948  							Children:            []WantTraceSegment{},
   949  						},
   950  						{
   951  							SegmentName:         "Custom/t2",
   952  							RelativeStartMillis: 2000,
   953  							RelativeStopMillis:  4000,
   954  							Attributes:          map[string]interface{}{"backtrace": MatchAnything},
   955  							Children:            []WantTraceSegment{},
   956  						},
   957  						{
   958  							SegmentName:         "External/example.com/http",
   959  							RelativeStartMillis: 4000,
   960  							RelativeStopMillis:  6000,
   961  							Attributes: map[string]interface{}{
   962  								"backtrace": MatchAnything,
   963  								"http.url":  "http://example.com/zip/zap",
   964  							},
   965  							Children: []WantTraceSegment{},
   966  						},
   967  					},
   968  				}},
   969  			},
   970  		},
   971  	})
   972  }
   973  
   974  func TestTxnTraceSynthetics(t *testing.T) {
   975  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
   976  	txndata := &TxnData{}
   977  	txndata.TxnTrace.Enabled = true
   978  
   979  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   980  	attr := NewAttributes(acfg)
   981  	attr.Agent.Add(attributeRequestURI, "/url", nil)
   982  	ht := newHarvestTraces()
   983  
   984  	ht.Witness(HarvestTrace{
   985  		TxnEvent: TxnEvent{
   986  			Start:     start,
   987  			Duration:  3 * time.Second,
   988  			TotalTime: 4 * time.Second,
   989  			FinalName: "WebTransaction/Go/3",
   990  			Attrs:     attr,
   991  			CrossProcess: TxnCrossProcess{
   992  				Type: txnCrossProcessSynthetics,
   993  				Synthetics: &cat.SyntheticsHeader{
   994  					ResourceID: "resource",
   995  				},
   996  			},
   997  		},
   998  		Trace: txndata.TxnTrace,
   999  	})
  1000  	ht.Witness(HarvestTrace{
  1001  		TxnEvent: TxnEvent{
  1002  			Start:     start,
  1003  			Duration:  5 * time.Second,
  1004  			TotalTime: 6 * time.Second,
  1005  			FinalName: "WebTransaction/Go/5",
  1006  			Attrs:     attr,
  1007  			CrossProcess: TxnCrossProcess{
  1008  				Type: txnCrossProcessSynthetics,
  1009  				Synthetics: &cat.SyntheticsHeader{
  1010  					ResourceID: "resource",
  1011  				},
  1012  			},
  1013  		},
  1014  		Trace: txndata.TxnTrace,
  1015  	})
  1016  	ht.Witness(HarvestTrace{
  1017  		TxnEvent: TxnEvent{
  1018  			Start:     start,
  1019  			Duration:  4 * time.Second,
  1020  			TotalTime: 5 * time.Second,
  1021  			FinalName: "WebTransaction/Go/4",
  1022  			Attrs:     attr,
  1023  			CrossProcess: TxnCrossProcess{
  1024  				Type: txnCrossProcessSynthetics,
  1025  				Synthetics: &cat.SyntheticsHeader{
  1026  					ResourceID: "resource",
  1027  				},
  1028  			},
  1029  		},
  1030  		Trace: txndata.TxnTrace,
  1031  	})
  1032  
  1033  	ExpectTxnTraces(t, ht, []WantTxnTrace{
  1034  		{
  1035  			MetricName:      "WebTransaction/Go/3",
  1036  			UserAttributes:  map[string]interface{}{},
  1037  			AgentAttributes: map[string]interface{}{"request.uri": "/url"},
  1038  			Intrinsics: map[string]interface{}{
  1039  				"totalTime":              4,
  1040  				"synthetics_resource_id": "resource",
  1041  			},
  1042  			Root: WantTraceSegment{
  1043  				SegmentName:         "ROOT",
  1044  				RelativeStartMillis: 0,
  1045  				RelativeStopMillis:  3000,
  1046  				Attributes:          map[string]interface{}{},
  1047  				Children: []WantTraceSegment{{
  1048  					SegmentName:         "WebTransaction/Go/3",
  1049  					RelativeStartMillis: 0,
  1050  					RelativeStopMillis:  3000,
  1051  					Attributes:          map[string]interface{}{"exclusive_duration_millis": 3000},
  1052  					Children:            []WantTraceSegment{},
  1053  				}},
  1054  			},
  1055  		},
  1056  		{
  1057  			MetricName:      "WebTransaction/Go/5",
  1058  			UserAttributes:  map[string]interface{}{},
  1059  			AgentAttributes: map[string]interface{}{"request.uri": "/url"},
  1060  			Intrinsics: map[string]interface{}{
  1061  				"totalTime":              6,
  1062  				"synthetics_resource_id": "resource",
  1063  			},
  1064  			Root: WantTraceSegment{
  1065  				SegmentName:         "ROOT",
  1066  				RelativeStartMillis: 0,
  1067  				RelativeStopMillis:  5000,
  1068  				Attributes:          map[string]interface{}{},
  1069  				Children: []WantTraceSegment{{
  1070  					SegmentName:         "WebTransaction/Go/5",
  1071  					RelativeStartMillis: 0,
  1072  					RelativeStopMillis:  5000,
  1073  					Attributes:          map[string]interface{}{"exclusive_duration_millis": 5000},
  1074  					Children:            []WantTraceSegment{},
  1075  				}},
  1076  			},
  1077  		},
  1078  		{
  1079  			MetricName:      "WebTransaction/Go/4",
  1080  			UserAttributes:  map[string]interface{}{},
  1081  			AgentAttributes: map[string]interface{}{"request.uri": "/url"},
  1082  			Intrinsics: map[string]interface{}{
  1083  				"totalTime":              5,
  1084  				"synthetics_resource_id": "resource",
  1085  			},
  1086  			Root: WantTraceSegment{
  1087  				SegmentName:         "ROOT",
  1088  				RelativeStartMillis: 0,
  1089  				RelativeStopMillis:  4000,
  1090  				Attributes:          map[string]interface{}{},
  1091  				Children: []WantTraceSegment{{
  1092  					SegmentName:         "WebTransaction/Go/4",
  1093  					RelativeStartMillis: 0,
  1094  					RelativeStopMillis:  4000,
  1095  					Attributes:          map[string]interface{}{"exclusive_duration_millis": 4000},
  1096  					Children:            []WantTraceSegment{},
  1097  				}},
  1098  			},
  1099  		},
  1100  	})
  1101  }
  1102  
  1103  func TestTraceJSON(t *testing.T) {
  1104  	// Have one test compare exact JSON to ensure that all misc fields (such
  1105  	// as the trailing `null,false,null,""`) are what we expect.
  1106  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
  1107  	txndata := &TxnData{}
  1108  	txndata.TxnTrace.Enabled = true
  1109  	ht := newHarvestTraces()
  1110  	ht.Witness(HarvestTrace{
  1111  		TxnEvent: TxnEvent{
  1112  			Start:     start,
  1113  			Duration:  3 * time.Second,
  1114  			TotalTime: 4 * time.Second,
  1115  			FinalName: "WebTransaction/Go/trace",
  1116  			Attrs:     nil,
  1117  		},
  1118  		Trace: txndata.TxnTrace,
  1119  	})
  1120  
  1121  	expect := `[
  1122     "12345",
  1123     [
  1124        [
  1125           1417136460000000,
  1126           3000,
  1127           "WebTransaction/Go/trace",
  1128           null,
  1129           [0,{},{},
  1130              [
  1131                 0,
  1132                 3000,
  1133                 "ROOT",
  1134                 {},
  1135                 [[0,3000,"WebTransaction/Go/trace",{"exclusive_duration_millis":3000},[]]]
  1136              ],
  1137              {
  1138                 "agentAttributes":{},
  1139                 "userAttributes":{},
  1140                 "intrinsics":{"totalTime":4}
  1141              }
  1142           ],"",null,false,null,""
  1143        ]
  1144     ]
  1145  ]`
  1146  
  1147  	js, err := ht.Data("12345", start)
  1148  	if nil != err {
  1149  		t.Fatal(err)
  1150  	}
  1151  	testExpectedJSON(t, expect, string(js))
  1152  }
  1153  
  1154  func TestTraceCatGUID(t *testing.T) {
  1155  	// Test catGUID is properly set in outbound json when CAT is enabled
  1156  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
  1157  	txndata := &TxnData{}
  1158  	txndata.TxnTrace.Enabled = true
  1159  	ht := newHarvestTraces()
  1160  	ht.Witness(HarvestTrace{
  1161  		TxnEvent: TxnEvent{
  1162  			Start:     start,
  1163  			Duration:  3 * time.Second,
  1164  			TotalTime: 4 * time.Second,
  1165  			FinalName: "WebTransaction/Go/trace",
  1166  			Attrs:     nil,
  1167  			CrossProcess: TxnCrossProcess{
  1168  				Type: 1,
  1169  				GUID: "this is guid",
  1170  			},
  1171  		},
  1172  		Trace: txndata.TxnTrace,
  1173  	})
  1174  
  1175  	expect := `[
  1176     "12345",
  1177     [
  1178        [
  1179           1417136460000000,
  1180           3000,
  1181           "WebTransaction/Go/trace",
  1182           null,
  1183           [0,{},{},
  1184              [
  1185                 0,
  1186                 3000,
  1187                 "ROOT",
  1188                 {},
  1189                 [[0,3000,"WebTransaction/Go/trace",{"exclusive_duration_millis":3000},[]]]
  1190              ],
  1191              {
  1192                 "agentAttributes":{},
  1193                 "userAttributes":{},
  1194                 "intrinsics":{"totalTime":4}
  1195              }
  1196           ],"this is guid",null,false,null,""
  1197        ]
  1198     ]
  1199  ]`
  1200  
  1201  	js, err := ht.Data("12345", start)
  1202  	if nil != err {
  1203  		t.Fatal(err)
  1204  	}
  1205  	testExpectedJSON(t, expect, string(js))
  1206  }
  1207  
  1208  func TestTraceDistributedTracingGUID(t *testing.T) {
  1209  	// Test catGUID is properly set in outbound json when DT is enabled
  1210  	start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC)
  1211  	txndata := &TxnData{}
  1212  	txndata.TxnTrace.Enabled = true
  1213  	ht := newHarvestTraces()
  1214  	ht.Witness(HarvestTrace{
  1215  		TxnEvent: TxnEvent{
  1216  			Start:     start,
  1217  			Duration:  3 * time.Second,
  1218  			TotalTime: 4 * time.Second,
  1219  			FinalName: "WebTransaction/Go/trace",
  1220  			Attrs:     nil,
  1221  			BetterCAT: BetterCAT{
  1222  				Enabled: true,
  1223  				ID:      "this is guid",
  1224  			},
  1225  		},
  1226  		Trace: txndata.TxnTrace,
  1227  	})
  1228  
  1229  	expect := `[
  1230     "12345",
  1231     [
  1232        [
  1233           1417136460000000,
  1234           3000,
  1235           "WebTransaction/Go/trace",
  1236           null,
  1237           [0,{},{},
  1238              [
  1239                 0,
  1240                 3000,
  1241                 "ROOT",
  1242                 {},
  1243                 [[0,3000,"WebTransaction/Go/trace",{"exclusive_duration_millis":3000},[]]]
  1244              ],
  1245              {
  1246                 "agentAttributes":{},
  1247                 "userAttributes":{},
  1248                 "intrinsics":{
  1249  				   "totalTime":4,
  1250  				   "guid":"this is guid",
  1251  				   "traceId":"this is guid",
  1252  				   "priority":0.000000,
  1253  				   "sampled":false
  1254  			   }
  1255              }
  1256           ],"this is guid",null,false,null,""
  1257        ]
  1258     ]
  1259  ]`
  1260  
  1261  	js, err := ht.Data("12345", start)
  1262  	if nil != err {
  1263  		t.Fatal(err)
  1264  	}
  1265  	testExpectedJSON(t, expect, string(js))
  1266  }
  1267  
  1268  func BenchmarkWitnessNode(b *testing.B) {
  1269  	trace := &TxnTrace{
  1270  		Enabled:             true,
  1271  		SegmentThreshold:    0,             // save all segments
  1272  		StackTraceThreshold: 1 * time.Hour, // no stack traces
  1273  		maxNodes:            100 * 1000,
  1274  	}
  1275  
  1276  	b.ResetTimer()
  1277  	b.ReportAllocs()
  1278  
  1279  	for i := 0; i < b.N; i++ {
  1280  		end := segmentEnd{
  1281  			duration:  time.Duration(RandUint32()) * time.Millisecond,
  1282  			exclusive: 0,
  1283  		}
  1284  		trace.witnessNode(end, "myNode", nil, "")
  1285  	}
  1286  }