github.com/newrelic/go-agent@v3.26.0+incompatible/internal/span_events_test.go (about)

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