From 9475d65aacd408501feff31f3fe412388a936412 Mon Sep 17 00:00:00 2001 From: Jesse Rittner Date: Thu, 6 Jan 2022 23:55:43 -0500 Subject: [PATCH 01/30] do not include distributed trace headers in AWS SDK requests --- v3/integrations/nrawssdk-v1/nrawssdk.go | 11 +---- v3/integrations/nrawssdk-v1/nrawssdk_test.go | 44 +++++++++++++++----- v3/internal/awssupport/awssupport.go | 20 ++++++--- 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/v3/integrations/nrawssdk-v1/nrawssdk.go b/v3/integrations/nrawssdk-v1/nrawssdk.go index 658f5f33b..4d020fb58 100644 --- a/v3/integrations/nrawssdk-v1/nrawssdk.go +++ b/v3/integrations/nrawssdk-v1/nrawssdk.go @@ -5,8 +5,6 @@ package nrawssdk import ( - "net/http" - "github.com/aws/aws-sdk-go/aws/request" "github.com/newrelic/go-agent/v3/internal" "github.com/newrelic/go-agent/v3/internal/awssupport" @@ -26,14 +24,7 @@ func startSegment(req *request.Request) { } func endSegment(req *request.Request) { - ctx := req.HTTPRequest.Context() - - hdr := http.Header{} - if req.HTTPRequest != nil { - hdr = req.HTTPRequest.Header - } - - awssupport.EndSegment(ctx, hdr) + awssupport.EndSegment(req.HTTPRequest.Context(), req.HTTPResponse) } // InstrumentHandlers will add instrumentation to the given *request.Handlers. diff --git a/v3/integrations/nrawssdk-v1/nrawssdk_test.go b/v3/integrations/nrawssdk-v1/nrawssdk_test.go index 16025f24f..79d20d9b0 100644 --- a/v3/integrations/nrawssdk-v1/nrawssdk_test.go +++ b/v3/integrations/nrawssdk-v1/nrawssdk_test.go @@ -93,11 +93,12 @@ var ( }, UserAttributes: map[string]interface{}{}, AgentAttributes: map[string]interface{}{ - "aws.operation": "Invoke", - "aws.region": "us-west-2", - "aws.requestId": requestID, - "http.method": "POST", - "http.url": "https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/non-existent-function/invocations", + "aws.operation": "Invoke", + "aws.region": "us-west-2", + "aws.requestId": requestID, + "http.method": "POST", + "http.url": "https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/non-existent-function/invocations", + "http.statusCode": 200, }, } externalSpanNoRequestID = internal.WantEvent{ @@ -115,10 +116,33 @@ var ( }, UserAttributes: map[string]interface{}{}, AgentAttributes: map[string]interface{}{ - "aws.operation": "Invoke", - "aws.region": "us-west-2", - "http.method": "POST", - "http.url": "https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/non-existent-function/invocations", + "aws.operation": "Invoke", + "aws.region": "us-west-2", + "http.method": "POST", + "http.url": "https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/non-existent-function/invocations", + "http.statusCode": 200, + }, + } + externalSpanSendFailure = internal.WantEvent{ + Intrinsics: map[string]interface{}{ + "name": "External/lambda.us-west-2.amazonaws.com/http/POST", + "sampled": true, + "category": "http", + "priority": internal.MatchAnything, + "guid": internal.MatchAnything, + "transactionId": internal.MatchAnything, + "traceId": internal.MatchAnything, + "parentId": internal.MatchAnything, + "component": "http", + "span.kind": "client", + }, + UserAttributes: map[string]interface{}{}, + AgentAttributes: map[string]interface{}{ + "aws.operation": "Invoke", + "aws.region": "us-west-2", + "http.method": "POST", + "http.url": "https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/non-existent-function/invocations", + "http.statusCode": 0, }, } datastoreSpan = internal.WantEvent{ @@ -493,7 +517,7 @@ func TestRetrySend(t *testing.T) { app.ExpectMetrics(t, externalMetrics) app.ExpectSpanEvents(t, []internal.WantEvent{ - externalSpanNoRequestID, externalSpan, genericSpan}) + externalSpanSendFailure, externalSpan, genericSpan}) } func TestRequestSentTwice(t *testing.T) { diff --git a/v3/internal/awssupport/awssupport.go b/v3/internal/awssupport/awssupport.go index ce8d5751e..f0a4cb868 100644 --- a/v3/internal/awssupport/awssupport.go +++ b/v3/internal/awssupport/awssupport.go @@ -83,7 +83,12 @@ func StartSegment(input StartSegmentInputs) *http.Request { StartTime: txn.StartSegmentNow(), } } else { - segment = newrelic.StartExternalSegment(txn, input.HTTPRequest) + // Do NOT set any distributed trace headers. + // Doing so can cause the AWS SDK's request signature to be invalid on retries. + segment = &newrelic.ExternalSegment{ + Request: input.HTTPRequest, + StartTime: txn.StartSegmentNow(), + } } integrationsupport.AddAgentSpanAttribute(txn, newrelic.SpanAttributeAWSOperation, input.Operation) @@ -94,11 +99,16 @@ func StartSegment(input StartSegmentInputs) *http.Request { } // EndSegment will end any segment found in the given context. -func EndSegment(ctx context.Context, hdr http.Header) { +func EndSegment(ctx context.Context, resp *http.Response) { if segment, ok := ctx.Value(segmentContextKey).(endable); ok { - if id := GetRequestID(hdr); "" != id { - txn := newrelic.FromContext(ctx) - integrationsupport.AddAgentSpanAttribute(txn, newrelic.SpanAttributeAWSRequestID, id) + if resp != nil { + if extSegment, ok := segment.(*newrelic.ExternalSegment); ok { + extSegment.Response = resp + } + if requestID := GetRequestID(resp.Header); requestID != "" { + txn := newrelic.FromContext(ctx) + integrationsupport.AddAgentSpanAttribute(txn, newrelic.SpanAttributeAWSRequestID, requestID) + } } segment.End() } From 7e3666b7030c7328a39ac9c2d96ebbebd54c0689 Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Wed, 26 Jan 2022 09:39:30 -0500 Subject: [PATCH 02/30] Support Wrapping newrelic.Error Ensure that if an error contains attributes, that they are safely coppied into the new error created in the wrap function. --- .../nrpkgerrors/nrkpgerrors_test.go | 30 +++++++++++++++++-- v3/integrations/nrpkgerrors/nrpkgerrors.go | 15 ++++++++-- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/v3/integrations/nrpkgerrors/nrkpgerrors_test.go b/v3/integrations/nrpkgerrors/nrkpgerrors_test.go index 270239318..06fd58aaa 100644 --- a/v3/integrations/nrpkgerrors/nrkpgerrors_test.go +++ b/v3/integrations/nrpkgerrors/nrkpgerrors_test.go @@ -31,10 +31,21 @@ func gamma(e error) error { return errors.WithStack(e) } func theta(e error) error { return errors.WithMessage(e, "theta") } +func withAttributes(e error) newrelic.Error { + return newrelic.Error{ + Message: e.Error(), + Attributes: map[string]interface{}{ + "testAttribute": 1, + "foo": 2, + }, + } +} + func TestWrappedStackTrace(t *testing.T) { testcases := []struct { - Error error - ExpectTopFrame string + Error error + ExpectTopFrame string + ExpectAttributes map[string]interface{} }{ {Error: basicError{}, ExpectTopFrame: ""}, {Error: alpha(basicError{}), ExpectTopFrame: "alpha"}, @@ -43,6 +54,7 @@ func TestWrappedStackTrace(t *testing.T) { {Error: alpha(theta(beta(basicError{}))), ExpectTopFrame: "beta"}, {Error: alpha(theta(beta(theta(basicError{})))), ExpectTopFrame: "beta"}, {Error: theta(basicError{}), ExpectTopFrame: ""}, + {Error: withAttributes(basicError{}), ExpectTopFrame: "", ExpectAttributes: map[string]interface{}{"testAttribute": 1, "foo": 2}}, } for idx, tc := range testcases { @@ -53,6 +65,20 @@ func TestWrappedStackTrace(t *testing.T) { t.Errorf("testcase %d: expected %s got %s", idx, tc.ExpectTopFrame, fn) } + // check that error attributes are equal if they are expected + if tc.ExpectAttributes != nil { + errorAttributes := e.(newrelic.Error).ErrorAttributes() + if len(tc.ExpectAttributes) != len(errorAttributes) { + t.Errorf("testcase %d: error attribute size expected %d got %d", + idx, len(tc.ExpectAttributes), len(errorAttributes)) + } + for k, v := range errorAttributes { + if tc.ExpectAttributes[k] != v { + t.Errorf("testcase %d: expected attribute %s:%v got %s:%v", + idx, k, tc.ExpectAttributes[k], k, v) + } + } + } } } diff --git a/v3/integrations/nrpkgerrors/nrpkgerrors.go b/v3/integrations/nrpkgerrors/nrpkgerrors.go index 8de6d46d3..dcbb66ff2 100644 --- a/v3/integrations/nrpkgerrors/nrpkgerrors.go +++ b/v3/integrations/nrpkgerrors/nrpkgerrors.go @@ -80,9 +80,18 @@ func errorClass(e error) string { // newrelic.Transaction.NoticeError it gives an improved stacktrace and class // type. func Wrap(e error) error { + attributes := make(map[string]interface{}) + switch error := e.(type) { + case newrelic.Error: + // if e is type newrelic.Error, copy attributes into wrapped errror + for key, value := range error.ErrorAttributes() { + attributes[key] = value + } + } return newrelic.Error{ - Message: e.Error(), - Class: errorClass(e), - Stack: stackTrace(e), + Message: e.Error(), + Class: errorClass(e), + Stack: stackTrace(e), + Attributes: attributes, } } From 707f866c9bd921a1084f5c79431666b491032787 Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Wed, 26 Jan 2022 14:06:22 -0500 Subject: [PATCH 03/30] correct nrpkgerror comment spelling and add empty newrelic.Error test --- v3/integrations/nrpkgerrors/nrkpgerrors_test.go | 2 ++ v3/integrations/nrpkgerrors/nrpkgerrors.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/v3/integrations/nrpkgerrors/nrkpgerrors_test.go b/v3/integrations/nrpkgerrors/nrkpgerrors_test.go index 06fd58aaa..17d1d62c0 100644 --- a/v3/integrations/nrpkgerrors/nrkpgerrors_test.go +++ b/v3/integrations/nrpkgerrors/nrkpgerrors_test.go @@ -31,6 +31,7 @@ func gamma(e error) error { return errors.WithStack(e) } func theta(e error) error { return errors.WithMessage(e, "theta") } +func basicNRError(e error) newrelic.Error { return newrelic.Error{Message: e.Error()} } func withAttributes(e error) newrelic.Error { return newrelic.Error{ Message: e.Error(), @@ -54,6 +55,7 @@ func TestWrappedStackTrace(t *testing.T) { {Error: alpha(theta(beta(basicError{}))), ExpectTopFrame: "beta"}, {Error: alpha(theta(beta(theta(basicError{})))), ExpectTopFrame: "beta"}, {Error: theta(basicError{}), ExpectTopFrame: ""}, + {Error: basicNRError(basicError{}), ExpectTopFrame: ""}, {Error: withAttributes(basicError{}), ExpectTopFrame: "", ExpectAttributes: map[string]interface{}{"testAttribute": 1, "foo": 2}}, } diff --git a/v3/integrations/nrpkgerrors/nrpkgerrors.go b/v3/integrations/nrpkgerrors/nrpkgerrors.go index dcbb66ff2..65af40e4b 100644 --- a/v3/integrations/nrpkgerrors/nrpkgerrors.go +++ b/v3/integrations/nrpkgerrors/nrpkgerrors.go @@ -83,7 +83,7 @@ func Wrap(e error) error { attributes := make(map[string]interface{}) switch error := e.(type) { case newrelic.Error: - // if e is type newrelic.Error, copy attributes into wrapped errror + // if e is type newrelic.Error, copy attributes into wrapped error for key, value := range error.ErrorAttributes() { attributes[key] = value } From 7451f0b64dcd9044b145e8c2ae5a5db119d51538 Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Thu, 27 Jan 2022 10:57:17 -0500 Subject: [PATCH 04/30] extend wait time for span in TestTrObsOKSendBackoffNo to cut down on testing flakes --- v3/newrelic/trace_observer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v3/newrelic/trace_observer_test.go b/v3/newrelic/trace_observer_test.go index 71d75a84d..f746416c8 100644 --- a/v3/newrelic/trace_observer_test.go +++ b/v3/newrelic/trace_observer_test.go @@ -902,7 +902,7 @@ func TestTrObsOKSendBackoffNo(t *testing.T) { } // If the default backoff of 15 seconds is used, the second span will not // be received in time. - if !s.DidSpansArrive(t, 2, 4*time.Second) { + if !s.DidSpansArrive(t, 2, 8*time.Second) { t.Error("server did not receive 2 spans") } } From ae2c2ae5032780789c6e85b0532ad1d11c51fd5c Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Fri, 28 Jan 2022 15:06:26 -0500 Subject: [PATCH 05/30] Pin net/http2 verison in go 1.13 and 1.14 The net library is no longer compatible when built from "tip" in go versions below 1.15, and is not supported in go versions below 1.16. This pins it to a known working version. --- build-script.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build-script.sh b/build-script.sh index 5f8035c41..009e47a67 100755 --- a/build-script.sh +++ b/build-script.sh @@ -44,9 +44,11 @@ for dir in $DIRS; do V1_10="1.10" V1_11="1.11" V1_12="1.12" + V1_13="1.13" + V1_14="1.14" if [[ "$VERSION" =~ .*"$V1_7".* || "$VERSION" =~ .*"$V1_8".* ]]; then echo "Not installing GRPC for old versions" - elif [[ "$VERSION" =~ .*"$V1_9" || "$VERSION" =~ .*"$V1_10" || "$VERSION" =~ .*"$V1_11" || "$VERSION" =~ .*"$V1_12" ]]; then + elif [[ "$VERSION" =~ .*"$V1_9" || "$VERSION" =~ .*"$V1_10" || "$VERSION" =~ .*"$V1_11" || "$VERSION" =~ .*"$V1_12" || "$VERSION" =~ .*"$V1_13" || "$VERSION" =~ .*"$V1_14" ]]; then # install v3 dependencies that support this go version set +e go get -u google.golang.org/grpc # this go get will fail to build From 72402e45b4a28cbab6f220f6a2d28dd6250694f8 Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Tue, 1 Feb 2022 10:49:10 -0500 Subject: [PATCH 06/30] Create functional way to pin Go dependency Creates a bash function that pins golang repos to a specific version or commit using the go mod syntax: @. This can be set in the github actions by declaring a matrix variable "pin". --- .github/workflows/ci.yaml | 3 ++- build-script.sh | 34 +++++++++++++++++++++------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4c559b834..942e3a925 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -231,6 +231,7 @@ jobs: env: DIRS: ${{ matrix.dirs }} EXTRATESTING: ${{ matrix.extratesting }} + PIN: ${{ matrix.pin }} go-agent-arm64: # Run all unit tests on aarch64 emulator to ensure compatibility with AWS @@ -271,7 +272,7 @@ jobs: go version cd v3/newrelic go mod download github.com/golang/protobuf - go get + go get -t echo ==== v3/newrelic tests ==== go test ./... cd ../internal diff --git a/build-script.sh b/build-script.sh index 009e47a67..0f7c91910 100755 --- a/build-script.sh +++ b/build-script.sh @@ -19,6 +19,22 @@ fi pwd=$(pwd) +# inputs +# 1: repo pin; example: github.com/rewrelic/go-agent@v1.9.0 +pin_go_dependency() { + echo "Pinning: $1" + if [[ ! -z "$1" ]]; then + repo=$(echo "$1" | cut -d '@' -f1) + pinTo=$(echo "$1" | cut -d '@' -f2) + set +e + go get -u "$repo" # this go get will fail to build + set -e + cd $GOPATH/src/"$repo" + git checkout "$pinTo" + cd - + fi +} + IFS="," for dir in $DIRS; do cd "$pwd/$dir" @@ -27,6 +43,8 @@ for dir in $DIRS; do go mod edit -replace github.com/newrelic/go-agent/v3=$pwd/v3 fi + pin_go_dependency "$PIN" + # go get is necessary for testing v2 integrations since they do not have # a go.mod file. if [[ $dir =~ "_integrations" ]]; then @@ -50,20 +68,10 @@ for dir in $DIRS; do echo "Not installing GRPC for old versions" elif [[ "$VERSION" =~ .*"$V1_9" || "$VERSION" =~ .*"$V1_10" || "$VERSION" =~ .*"$V1_11" || "$VERSION" =~ .*"$V1_12" || "$VERSION" =~ .*"$V1_13" || "$VERSION" =~ .*"$V1_14" ]]; then # install v3 dependencies that support this go version - set +e - go get -u google.golang.org/grpc # this go get will fail to build - set -e - cd $GOPATH/src/google.golang.org/grpc - git checkout v1.31.0 - cd - - - set +e - go get -u golang.org/x/net/http2 # this go get will fail to build - set -e - cd $GOPATH/src/golang.org/x/net/http2 - git checkout 7fd8e65b642006927f6cec5cb4241df7f98a2210 - cd - + pin_go_dependency "google.golang.org/grpc@v1.31.0" + pin_go_dependency "golang.org/x/net/http2@7fd8e65b642006927f6cec5cb4241df7f98a2210" + # install protobuff once dependencies are resolved go get -u github.com/golang/protobuf/protoc-gen-go else go get -u github.com/golang/protobuf/protoc-gen-go From 02830287a40ce5ca4cac4df478c3b0f5b7bcd17e Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Wed, 2 Feb 2022 16:02:40 -0500 Subject: [PATCH 07/30] move go get -t after pinning --- build-script.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/build-script.sh b/build-script.sh index 0f7c91910..05c0ae334 100755 --- a/build-script.sh +++ b/build-script.sh @@ -22,14 +22,14 @@ pwd=$(pwd) # inputs # 1: repo pin; example: github.com/rewrelic/go-agent@v1.9.0 pin_go_dependency() { - echo "Pinning: $1" if [[ ! -z "$1" ]]; then + echo "Pinning: $1" repo=$(echo "$1" | cut -d '@' -f1) pinTo=$(echo "$1" | cut -d '@' -f2) set +e go get -u "$repo" # this go get will fail to build set -e - cd $GOPATH/src/"$repo" + cd "$GOPATH"/src/"$repo" git checkout "$pinTo" cd - fi @@ -40,18 +40,13 @@ for dir in $DIRS; do cd "$pwd/$dir" if [ -f "go.mod" ]; then - go mod edit -replace github.com/newrelic/go-agent/v3=$pwd/v3 + go mod edit -replace github.com/newrelic/go-agent/v3="$pwd"/v3 fi pin_go_dependency "$PIN" - # go get is necessary for testing v2 integrations since they do not have - # a go.mod file. - if [[ $dir =~ "_integrations" ]]; then - go get -t ./... - fi # avoid testing v3 code when testing v2 newrelic package - if [ $dir == "." ]; then + if [ "$dir" == "." ]; then rm -rf v3/ else # Only v3 code version 1.9+ needs GRPC dependencies @@ -79,6 +74,12 @@ for dir in $DIRS; do fi fi + # go get is necessary for testing v2 integrations since they do not have + # a go.mod file. + if [[ $dir =~ "_integrations" ]]; then + go get -t ./... + fi + go test -race -benchtime=1ms -bench=. ./... go vet ./... From 6f8d511a15dddcbef8c8a1a066ac90cfa9d5818b Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Wed, 2 Feb 2022 16:13:24 -0500 Subject: [PATCH 08/30] pin _integrations/echo to version compatible with go 1.13 --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 942e3a925..492753687 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -48,6 +48,7 @@ jobs: dirs: _integrations/nrawssdk - go-version: 1.13.x dirs: _integrations/nrecho + pin: github.com/labstack/echo@v3.3.10 - go-version: 1.13.x dirs: _integrations/nrgin/v1 - go-version: 1.13.x From fd4141ca907337f704d2ba57b9f3b182627dccff Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Thu, 3 Feb 2022 15:09:19 -0500 Subject: [PATCH 09/30] pin _integrations/nrawssdk to compatible version --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 492753687..e74a51f5e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,6 +45,8 @@ jobs: # v2 integrations - go-version: 1.13.x + # only versions up to 0.24.0 of awssdkv2 are supported by this code + pin: github.com/aws/aws-sdk-go-v2@v0.24.0 dirs: _integrations/nrawssdk - go-version: 1.13.x dirs: _integrations/nrecho From ff69021b5a42336674ea50874d585861fcc504b4 Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Fri, 4 Feb 2022 16:33:44 -0500 Subject: [PATCH 10/30] clarify validateStringFields expected vs actual Updates the error message of the comparison method to clearly state which value is expected and actual, and fixes the usage of this function to follow this convention consistently. --- v3/newrelic/expect_implementation.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/v3/newrelic/expect_implementation.go b/v3/newrelic/expect_implementation.go index c582405bb..6ecf594e6 100644 --- a/v3/newrelic/expect_implementation.go +++ b/v3/newrelic/expect_implementation.go @@ -11,9 +11,9 @@ import ( "github.com/newrelic/go-agent/v3/internal" ) -func validateStringField(v internal.Validator, fieldName, v1, v2 string) { - if v1 != v2 { - v.Error(fieldName, v1, v2) +func validateStringField(v internal.Validator, fieldName, expect, actual string) { + if expect != actual { + v.Error(fieldName, "incorrect: Expected:", expect, " Got:", actual) } } @@ -442,13 +442,13 @@ func expectSlowQuery(t internal.Validator, slowQuery *slowQuery, want internal.W t.Error("wrong Count field", slowQuery.Count, want.Count) } uri, _ := slowQuery.txnEvent.Attrs.GetAgentValue(AttributeRequestURI, destTxnTrace) - validateStringField(t, "MetricName", slowQuery.DatastoreMetric, want.MetricName) - validateStringField(t, "Query", slowQuery.ParameterizedQuery, want.Query) - validateStringField(t, "TxnEvent.FinalName", slowQuery.txnEvent.FinalName, want.TxnName) - validateStringField(t, "request.uri", uri, want.TxnURL) - validateStringField(t, "DatabaseName", slowQuery.DatabaseName, want.DatabaseName) - validateStringField(t, "Host", slowQuery.Host, want.Host) - validateStringField(t, "PortPathOrID", slowQuery.PortPathOrID, want.PortPathOrID) + validateStringField(t, "MetricName", want.MetricName, slowQuery.DatastoreMetric) + validateStringField(t, "Query", want.Query, slowQuery.ParameterizedQuery) + validateStringField(t, "TxnEvent.FinalName", want.TxnName, slowQuery.txnEvent.FinalName) + validateStringField(t, "request.uri", want.TxnURL, uri) + validateStringField(t, "DatabaseName", want.DatabaseName, slowQuery.DatabaseName) + validateStringField(t, "Host", want.Host, slowQuery.Host) + validateStringField(t, "PortPathOrID", want.PortPathOrID, slowQuery.PortPathOrID) expectAttributes(t, map[string]interface{}(slowQuery.QueryParameters), want.Params) } From 8d914523ba9584560f59218557a06a6a16f5a95b Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Fri, 4 Feb 2022 16:47:08 -0500 Subject: [PATCH 11/30] Remove nrgraphgophers_test error type expectation The latest version of graphql for golang returns errors of type "errorString" rather than "queryError" causing the test to fail. The error type is not an important part of validating that an error was captured, so we will simply not check it. --- v3/integrations/nrgraphgophers/nrgraphgophers_test.go | 1 - v3/newrelic/expect_implementation.go | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/v3/integrations/nrgraphgophers/nrgraphgophers_test.go b/v3/integrations/nrgraphgophers/nrgraphgophers_test.go index 763f30437..287e80e04 100644 --- a/v3/integrations/nrgraphgophers/nrgraphgophers_test.go +++ b/v3/integrations/nrgraphgophers/nrgraphgophers_test.go @@ -244,7 +244,6 @@ func TestQueryRequestError(t *testing.T) { app.ExpectErrors(t, []internal.WantError{{ TxnName: "WebTransaction/Go/POST /", Msg: "graphql: something went wrong", - Klass: "*errors.QueryError", }}) } diff --git a/v3/newrelic/expect_implementation.go b/v3/newrelic/expect_implementation.go index 6ecf594e6..82a9607b1 100644 --- a/v3/newrelic/expect_implementation.go +++ b/v3/newrelic/expect_implementation.go @@ -12,6 +12,10 @@ import ( ) func validateStringField(v internal.Validator, fieldName, expect, actual string) { + // If an expected value is not set, we assume the user does not want to validate it + if expect == "" { + return + } if expect != actual { v.Error(fieldName, "incorrect: Expected:", expect, " Got:", actual) } From f23a215f1f8c8a1998a00c84425024b57ee97918 Mon Sep 17 00:00:00 2001 From: Rich Vanderwal Date: Fri, 11 Feb 2022 19:20:25 +0000 Subject: [PATCH 12/30] Removing unneeded utility from agent --- internal/tools/utilization/Dockerfile | 22 ----------------- internal/tools/utilization/main.go | 31 ------------------------ v3/internal/tools/utilization/Dockerfile | 22 ----------------- v3/internal/tools/utilization/main.go | 31 ------------------------ 4 files changed, 106 deletions(-) delete mode 100644 internal/tools/utilization/Dockerfile delete mode 100644 internal/tools/utilization/main.go delete mode 100644 v3/internal/tools/utilization/Dockerfile delete mode 100644 v3/internal/tools/utilization/main.go diff --git a/internal/tools/utilization/Dockerfile b/internal/tools/utilization/Dockerfile deleted file mode 100644 index 975fdc840..000000000 --- a/internal/tools/utilization/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2020 New Relic Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -# This Dockerfile builds a docker image which prints utilization information. -# It is designed to be build from the top level (go-agent directory). -# -# To build: -# docker build -t utilization -f internal/tools/utilization/Dockerfile . -# -# Then to run: -# docker run utilization -# - -FROM golang:1.7 - -ENV GOPATH /tmp/gopath - -RUN mkdir -p $GOPATH/src/github.com/newrelic/go-agent/ - -COPY . $GOPATH/src/github.com/newrelic/go-agent/ - -CMD go run ${GOPATH}/src/github.com/newrelic/go-agent/internal/tools/utilization/main.go diff --git a/internal/tools/utilization/main.go b/internal/tools/utilization/main.go deleted file mode 100644 index 66d83b5d1..000000000 --- a/internal/tools/utilization/main.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 New Relic Corporation. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package main - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/newrelic/go-agent" - "github.com/newrelic/go-agent/internal/utilization" -) - -func main() { - util := utilization.Gather(utilization.Config{ - DetectAWS: true, - DetectAzure: true, - DetectDocker: true, - DetectPCF: true, - DetectGCP: true, - DetectKubernetes: true, - }, newrelic.NewDebugLogger(os.Stdout)) - - js, err := json.MarshalIndent(util, "", "\t") - if err != nil { - fmt.Printf("%s\n", err) - } else { - fmt.Printf("%s\n", js) - } -} diff --git a/v3/internal/tools/utilization/Dockerfile b/v3/internal/tools/utilization/Dockerfile deleted file mode 100644 index 90e0a1af3..000000000 --- a/v3/internal/tools/utilization/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2020 New Relic Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -# This Dockerfile builds a docker image which prints utilization information. -# It is designed to be build from the top level (go-agent directory). -# -# To build: -# docker build -t utilization -f internal/tools/utilization/Dockerfile . -# -# Then to run: -# docker run utilization -# - -FROM golang:1 - -ENV GOPATH /tmp/gopath - -RUN mkdir -p $GOPATH/src/github.com/newrelic/go-agent/ - -COPY . $GOPATH/src/github.com/newrelic/go-agent/ - -CMD go run ${GOPATH}/src/github.com/newrelic/go-agent/internal/tools/utilization/main.go diff --git a/v3/internal/tools/utilization/main.go b/v3/internal/tools/utilization/main.go deleted file mode 100644 index 707005b5a..000000000 --- a/v3/internal/tools/utilization/main.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 New Relic Corporation. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package main - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/newrelic/go-agent/v3/internal/utilization" - newrelic "github.com/newrelic/go-agent/v3/newrelic" -) - -func main() { - util := utilization.Gather(utilization.Config{ - DetectAWS: true, - DetectAzure: true, - DetectDocker: true, - DetectPCF: true, - DetectGCP: true, - DetectKubernetes: true, - }, newrelic.NewDebugLogger(os.Stdout)) - - js, err := json.MarshalIndent(util, "", "\t") - if err != nil { - fmt.Printf("%s\n", err) - } else { - fmt.Printf("%s\n", js) - } -} From 0e5a9d4161998cdd280921a441e721b790df3c10 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Fri, 11 Feb 2022 16:14:47 -0700 Subject: [PATCH 13/30] add memtotal bits for openbsd --- internal/sysinfo/memtotal_openbsd_amd64.go | 35 +++++++++++++ internal/sysinfo/memtotal_openbsd_test.go | 49 +++++++++++++++++++ v3/internal/sysinfo/memtotal_openbsd_amd64.go | 35 +++++++++++++ v3/internal/sysinfo/memtotal_openbsd_test.go | 49 +++++++++++++++++++ 4 files changed, 168 insertions(+) create mode 100644 internal/sysinfo/memtotal_openbsd_amd64.go create mode 100644 internal/sysinfo/memtotal_openbsd_test.go create mode 100644 v3/internal/sysinfo/memtotal_openbsd_amd64.go create mode 100644 v3/internal/sysinfo/memtotal_openbsd_test.go diff --git a/internal/sysinfo/memtotal_openbsd_amd64.go b/internal/sysinfo/memtotal_openbsd_amd64.go new file mode 100644 index 000000000..2dc20960d --- /dev/null +++ b/internal/sysinfo/memtotal_openbsd_amd64.go @@ -0,0 +1,35 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "syscall" + "unsafe" +) + +// PhysicalMemoryBytes returns the total amount of host memory. +func PhysicalMemoryBytes() (uint64, error) { + mib := []int32{6 /* CTL_HW */, 19 /* HW_PHYSMEM64 */} + + buf := make([]byte, 8) + bufLen := uintptr(8) + + _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), + uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&bufLen)), + uintptr(0), uintptr(0)) + + if e1 != 0 { + return 0, e1 + } + + switch bufLen { + case 4: + return uint64(*(*uint32)(unsafe.Pointer(&buf[0]))), nil + case 8: + return *(*uint64)(unsafe.Pointer(&buf[0])), nil + default: + return 0, syscall.EIO + } +} diff --git a/internal/sysinfo/memtotal_openbsd_test.go b/internal/sysinfo/memtotal_openbsd_test.go new file mode 100644 index 000000000..e12140848 --- /dev/null +++ b/internal/sysinfo/memtotal_openbsd_test.go @@ -0,0 +1,49 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "errors" + "os/exec" + "regexp" + "strconv" + "testing" +) + +var re = regexp.MustCompile(`hw\.physmem=(\d+)`) + +func openbsdSysctlMemoryBytes() (uint64, error) { + out, err := exec.Command("/sbin/sysctl", "hw.physmem").Output() + if err != nil { + return 0, err + } + + match := re.FindSubmatch(out) + if match == nil { + return 0, errors.New("memory size not found in sysctl output") + } + + bts, err := strconv.ParseUint(string(match[1]), 10, 64) + if err != nil { + return 0, err + } + + return bts, nil +} + +func TestPhysicalMemoryBytes(t *testing.T) { + mem, err := PhysicalMemoryBytes() + if err != nil { + t.Fatal(err) + } + + mem2, err := openbsdSysctlMemoryBytes() + if nil != err { + t.Fatal(err) + } + + if mem != mem2 { + t.Errorf("Expected %d, got %d\n", mem2, mem) + } +} diff --git a/v3/internal/sysinfo/memtotal_openbsd_amd64.go b/v3/internal/sysinfo/memtotal_openbsd_amd64.go new file mode 100644 index 000000000..2dc20960d --- /dev/null +++ b/v3/internal/sysinfo/memtotal_openbsd_amd64.go @@ -0,0 +1,35 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "syscall" + "unsafe" +) + +// PhysicalMemoryBytes returns the total amount of host memory. +func PhysicalMemoryBytes() (uint64, error) { + mib := []int32{6 /* CTL_HW */, 19 /* HW_PHYSMEM64 */} + + buf := make([]byte, 8) + bufLen := uintptr(8) + + _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), + uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&bufLen)), + uintptr(0), uintptr(0)) + + if e1 != 0 { + return 0, e1 + } + + switch bufLen { + case 4: + return uint64(*(*uint32)(unsafe.Pointer(&buf[0]))), nil + case 8: + return *(*uint64)(unsafe.Pointer(&buf[0])), nil + default: + return 0, syscall.EIO + } +} diff --git a/v3/internal/sysinfo/memtotal_openbsd_test.go b/v3/internal/sysinfo/memtotal_openbsd_test.go new file mode 100644 index 000000000..e12140848 --- /dev/null +++ b/v3/internal/sysinfo/memtotal_openbsd_test.go @@ -0,0 +1,49 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "errors" + "os/exec" + "regexp" + "strconv" + "testing" +) + +var re = regexp.MustCompile(`hw\.physmem=(\d+)`) + +func openbsdSysctlMemoryBytes() (uint64, error) { + out, err := exec.Command("/sbin/sysctl", "hw.physmem").Output() + if err != nil { + return 0, err + } + + match := re.FindSubmatch(out) + if match == nil { + return 0, errors.New("memory size not found in sysctl output") + } + + bts, err := strconv.ParseUint(string(match[1]), 10, 64) + if err != nil { + return 0, err + } + + return bts, nil +} + +func TestPhysicalMemoryBytes(t *testing.T) { + mem, err := PhysicalMemoryBytes() + if err != nil { + t.Fatal(err) + } + + mem2, err := openbsdSysctlMemoryBytes() + if nil != err { + t.Fatal(err) + } + + if mem != mem2 { + t.Errorf("Expected %d, got %d\n", mem2, mem) + } +} From 6da91bf6630ffd1717acde96f1978cfca75499fb Mon Sep 17 00:00:00 2001 From: Rich Vanderwal Date: Tue, 15 Feb 2022 13:48:35 -0800 Subject: [PATCH 14/30] update version of nats-streaming-server --- CHANGELOG.md | 6 ++++++ v3/integrations/nrstan/test/go.mod | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4c9887e..b0a3f7d11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ # ChangeLog + +## Unreleased + +### Changed +* Updated version of `nats-streaming-server` in the nrstan integration to patch vulnerability mentioned in [this Dependabot alert](https://github.com/newrelic/go-agent/security/dependabot/3). + ## 3.15.2 ### Added * Strings logged via the Go Agent's built-in logger will have strings of the form `license_key=`*hex-string* changed to `license_key=[redacted]` before they are output, regardless of severity level, where *hex-string* means a sequence of upper- or lower-case hexadecimal digits and dots ('.'). This incorporates [PR #415](https://github.com/newrelic/go-agent/pull/415). diff --git a/v3/integrations/nrstan/test/go.mod b/v3/integrations/nrstan/test/go.mod index 7113f5303..ccb0ba0a9 100644 --- a/v3/integrations/nrstan/test/go.mod +++ b/v3/integrations/nrstan/test/go.mod @@ -6,8 +6,8 @@ module github.com/newrelic/go-agent/v3/integrations/nrstan/test go 1.13 require ( - github.com/nats-io/nats-streaming-server v0.16.2 - github.com/nats-io/stan.go v0.5.0 + github.com/nats-io/nats-streaming-server v0.24.1 + github.com/nats-io/stan.go v0.10.2 github.com/newrelic/go-agent/v3 v3.4.0 github.com/newrelic/go-agent/v3/integrations/nrstan v0.0.0 ) From 9b73d1ddcbe572ef878e0d1703c31e0660c6afed Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Wed, 16 Feb 2022 11:59:17 -0500 Subject: [PATCH 15/30] clarify validateStringField in internal/expect.go --- internal/expect.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/expect.go b/internal/expect.go index 6cab9a7e0..d97016fc4 100644 --- a/internal/expect.go +++ b/internal/expect.go @@ -24,9 +24,13 @@ type Validator interface { Error(...interface{}) } -func validateStringField(v Validator, fieldName, v1, v2 string) { - if v1 != v2 { - v.Error(fieldName, v1, v2) +func validateStringField(v Validator, fieldName, expect, actual string) { + // If an expected value is not set, we assume the user does not want to validate it + if expect == "" { + return + } + if expect != actual { + v.Error(fieldName, "incorrect: Expected:", expect, " Got:", actual) } } From 3e2bd9a0ef937e7a72d1a2d065e7415b41458920 Mon Sep 17 00:00:00 2001 From: Emilio Garcia Date: Wed, 16 Feb 2022 12:11:21 -0500 Subject: [PATCH 16/30] protobuf typo in build-script.sh --- build-script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-script.sh b/build-script.sh index 05c0ae334..364678bd5 100755 --- a/build-script.sh +++ b/build-script.sh @@ -66,7 +66,7 @@ for dir in $DIRS; do pin_go_dependency "google.golang.org/grpc@v1.31.0" pin_go_dependency "golang.org/x/net/http2@7fd8e65b642006927f6cec5cb4241df7f98a2210" - # install protobuff once dependencies are resolved + # install protobuf once dependencies are resolved go get -u github.com/golang/protobuf/protoc-gen-go else go get -u github.com/golang/protobuf/protoc-gen-go From 0e5b79df57af0dd367536cd7c6a063bddc4b6e08 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Fri, 18 Feb 2022 09:40:28 -0800 Subject: [PATCH 17/30] wip on dt test cases --- v3/newrelic/app_run_test.go | 4 ++-- v3/newrelic/config.go | 6 ++++-- v3/newrelic/config_options.go | 7 +++++++ v3/newrelic/config_test.go | 8 ++++---- v3/newrelic/internal_17_test.go | 6 +++--- v3/newrelic/internal_attributes_test.go | 23 +++++++++++++++++++---- v3/newrelic/internal_context_test.go | 4 ++-- v3/newrelic/internal_test.go | 13 +++++++++++++ v3/newrelic/limits.go | 1 + 9 files changed, 55 insertions(+), 17 deletions(-) diff --git a/v3/newrelic/app_run_test.go b/v3/newrelic/app_run_test.go index 9f969f0b8..7ed1067a8 100644 --- a/v3/newrelic/app_run_test.go +++ b/v3/newrelic/app_run_test.go @@ -46,10 +46,10 @@ func TestResponseCodeIsError(t *testing.T) { } func TestCrossAppTracingEnabled(t *testing.T) { - // CAT should be enabled by default. + // CAT should NOT be enabled by default. cfg := config{Config: defaultConfig()} run := newAppRun(cfg, internal.ConnectReplyDefaults()) - if enabled := run.Config.CrossApplicationTracer.Enabled; !enabled { + if enabled := run.Config.CrossApplicationTracer.Enabled; enabled { t.Error(enabled) } diff --git a/v3/newrelic/config.go b/v3/newrelic/config.go index a5c9be1e8..3ae6baa08 100644 --- a/v3/newrelic/config.go +++ b/v3/newrelic/config.go @@ -235,6 +235,7 @@ type Config struct { // Disabling the New Relic header here does not prevent the agent from // accepting *inbound* New Relic headers. ExcludeNewRelicHeader bool + ReservoirLimit int } // SpanEvents controls behavior relating to Span Events. Span Events @@ -413,8 +414,9 @@ func defaultConfig() Config { // browser monitoring attributes are disabled by default c.BrowserMonitoring.Attributes.Enabled = false - c.CrossApplicationTracer.Enabled = true - c.DistributedTracer.Enabled = false + c.CrossApplicationTracer.Enabled = false + c.DistributedTracer.Enabled = true + c.DistributedTracer.ReservoirLimit = 2000 c.SpanEvents.Enabled = true c.SpanEvents.Attributes.Enabled = true diff --git a/v3/newrelic/config_options.go b/v3/newrelic/config_options.go index 60524f08b..4b935ebb7 100644 --- a/v3/newrelic/config_options.go +++ b/v3/newrelic/config_options.go @@ -36,6 +36,13 @@ func ConfigDistributedTracerEnabled(enabled bool) ConfigOption { return func(cfg *Config) { cfg.DistributedTracer.Enabled = enabled } } +// ConfigDistributedTracerReservoirLimit alters the sample reservoir size to be +// used for distributed tracing instead of using the built-in default. +// Alters the DistributedTracer.ReservoirLimit setting. +func ConfigDistributedTracerReservoirLimit(limit int) ConfigOption { + return func(cfg *Config) { cfg.DistributedTracer.ReservoirLimit = limit } +} + // ConfigLogger populates the Config's Logger. func ConfigLogger(l Logger) ConfigOption { return func(cfg *Config) { cfg.Logger = l } diff --git a/v3/newrelic/config_test.go b/v3/newrelic/config_test.go index 118a46677..4ee6dc8c1 100644 --- a/v3/newrelic/config_test.go +++ b/v3/newrelic/config_test.go @@ -134,7 +134,7 @@ func TestCopyConfigReferenceFieldsPresent(t *testing.T) { "Attributes":{"Enabled":false,"Exclude":["10"],"Include":["9"]}, "Enabled":true }, - "CrossApplicationTracer":{"Enabled":true}, + "CrossApplicationTracer":{"Enabled":false}, "CustomInsightsEvents":{"Enabled":true}, "DatastoreTracer":{ "DatabaseNameReporting":{"Enabled":true}, @@ -145,7 +145,7 @@ func TestCopyConfigReferenceFieldsPresent(t *testing.T) { "Threshold":10000000 } }, - "DistributedTracer":{"Enabled":false,"ExcludeNewRelicHeader":false}, + "DistributedTracer":{"Enabled":true,"ExcludeNewRelicHeader":false,"ReservoirLimit":2000}, "Enabled":true, "Error":null, "ErrorCollector":{ @@ -310,7 +310,7 @@ func TestCopyConfigReferenceFieldsAbsent(t *testing.T) { }, "Enabled":true }, - "CrossApplicationTracer":{"Enabled":true}, + "CrossApplicationTracer":{"Enabled":false}, "CustomInsightsEvents":{"Enabled":true}, "DatastoreTracer":{ "DatabaseNameReporting":{"Enabled":true}, @@ -321,7 +321,7 @@ func TestCopyConfigReferenceFieldsAbsent(t *testing.T) { "Threshold":10000000 } }, - "DistributedTracer":{"Enabled":false,"ExcludeNewRelicHeader":false}, + "DistributedTracer":{"Enabled":true,"ExcludeNewRelicHeader":false,"ReservoirLimit":2000}, "Enabled":true, "Error":null, "ErrorCollector":{ diff --git a/v3/newrelic/internal_17_test.go b/v3/newrelic/internal_17_test.go index b7c7820ab..84dfff87c 100644 --- a/v3/newrelic/internal_17_test.go +++ b/v3/newrelic/internal_17_test.go @@ -19,7 +19,7 @@ func myErrorHandler(w http.ResponseWriter, req *http.Request) { } func TestWrapHandleFunc(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) mux := http.NewServeMux() mux.HandleFunc(WrapHandleFunc(app.Application, helloPath, myErrorHandler)) w := newCompatibleResponseRecorder() @@ -61,7 +61,7 @@ func TestWrapHandleFunc(t *testing.T) { } func TestWrapHandle(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) mux := http.NewServeMux() mux.Handle(WrapHandle(app.Application, helloPath, http.HandlerFunc(myErrorHandler))) w := newCompatibleResponseRecorder() @@ -193,7 +193,7 @@ func TestRoundTripper(t *testing.T) { } func TestRoundTripperOldCAT(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") url := "http://example.com/" req, err := http.NewRequest("GET", url, nil) diff --git a/v3/newrelic/internal_attributes_test.go b/v3/newrelic/internal_attributes_test.go index 136301623..c27e6aaba 100644 --- a/v3/newrelic/internal_attributes_test.go +++ b/v3/newrelic/internal_attributes_test.go @@ -16,6 +16,7 @@ import ( func TestAddAttributeHighSecurity(t *testing.T) { cfgfn := func(cfg *Config) { cfg.HighSecurity = true + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -39,7 +40,7 @@ func TestAddAttributeSecurityPolicyDisablesParameters(t *testing.T) { replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.CustomParameters.SetEnabled(false) } - app := testApp(replyfn, nil, t) + app := testApp(replyfn, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.AddAttribute(`key`, 1) @@ -62,6 +63,7 @@ func TestAddAttributeSecurityPolicyDisablesInclude(t *testing.T) { reply.SecurityPolicies.AttributesInclude.SetEnabled(false) } cfgfn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false cfg.TransactionEvents.Attributes.Include = append(cfg.TransactionEvents.Attributes.Include, AttributeRequestUserAgent) } @@ -98,6 +100,7 @@ func TestUserAttributeBasics(t *testing.T) { cfgfn := func(cfg *Config) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -157,6 +160,7 @@ func TestUserAttributeBasics(t *testing.T) { func TestUserAttributeConfiguration(t *testing.T) { cfgfn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false cfg.TransactionEvents.Attributes.Exclude = []string{"only_errors", "only_txn_traces"} cfg.ErrorCollector.Attributes.Exclude = []string{"only_txn_events", "only_txn_traces"} cfg.TransactionTracer.Attributes.Exclude = []string{"only_txn_events", "only_errors"} @@ -242,6 +246,7 @@ func agentAttributeTestcase(t testing.TB, cfgfn func(cfg *Config), e AttributeEx cfg.HostDisplayName = `my\host\display\name` cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 + cfg.DistributedTracer.Enabled = false if nil != cfgfn { cfgfn(cfg) } @@ -318,6 +323,7 @@ func TestAgentAttributes(t *testing.T) { func TestAttributesDisabled(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.Attributes.Enabled = false + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: map[string]interface{}{}, @@ -332,7 +338,7 @@ func TestAttributesDisabled(t *testing.T) { } func TestDefaultResponseCode(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) w := newCompatibleResponseRecorder() txn := app.StartTransaction("hello") rw := txn.SetWebResponse(w) @@ -354,7 +360,7 @@ func TestDefaultResponseCode(t *testing.T) { } func TestNoResponseCode(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) w := newCompatibleResponseRecorder() txn := app.StartTransaction("hello") txn.SetWebResponse(w) @@ -374,6 +380,7 @@ func TestNoResponseCode(t *testing.T) { func TestTxnEventAttributesDisabled(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.TransactionEvents.Attributes.Enabled = false + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: map[string]interface{}{}, @@ -390,6 +397,7 @@ func TestTxnEventAttributesDisabled(t *testing.T) { func TestErrorAttributesDisabled(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.ErrorCollector.Attributes.Enabled = false + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: agent1, @@ -406,6 +414,7 @@ func TestErrorAttributesDisabled(t *testing.T) { func TestTxnTraceAttributesDisabled(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.TransactionTracer.Attributes.Enabled = false + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: agent1, @@ -441,6 +450,7 @@ var ( func TestAgentAttributesExcluded(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.Attributes.Exclude = allAgentAttributeNames + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: map[string]interface{}{}, @@ -457,6 +467,7 @@ func TestAgentAttributesExcluded(t *testing.T) { func TestAgentAttributesExcludedFromErrors(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.ErrorCollector.Attributes.Exclude = allAgentAttributeNames + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: agent1, @@ -473,6 +484,7 @@ func TestAgentAttributesExcludedFromErrors(t *testing.T) { func TestAgentAttributesExcludedFromTxnEvents(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.TransactionEvents.Attributes.Exclude = allAgentAttributeNames + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: map[string]interface{}{}, @@ -489,6 +501,7 @@ func TestAgentAttributesExcludedFromTxnEvents(t *testing.T) { func TestAgentAttributesExcludedFromTxnTraces(t *testing.T) { agentAttributeTestcase(t, func(cfg *Config) { cfg.TransactionTracer.Attributes.Exclude = allAgentAttributeNames + cfg.DistributedTracer.Enabled = false }, AttributeExpect{ TxnEvent: UserAgent{ Agent: agent1, @@ -506,6 +519,7 @@ func TestRequestURIPresent(t *testing.T) { cfgfn := func(cfg *Config) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -556,6 +570,7 @@ func TestRequestURIExcluded(t *testing.T) { cfgfn := func(cfg *Config) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 + cfg.DistributedTracer.Enabled = false cfg.Attributes.Exclude = append(cfg.Attributes.Exclude, AttributeRequestURI) } app := testApp(nil, cfgfn, t) @@ -606,7 +621,7 @@ func TestRequestURIExcluded(t *testing.T) { func TestMessageAttributes(t *testing.T) { // test that adding message attributes as agent attributes filters them, // but as user attributes does not filter them. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello1") txn.Private.(internal.AddAgentAttributer).AddAgentAttribute(AttributeMessageRoutingKey, "myRoutingKey", nil) diff --git a/v3/newrelic/internal_context_test.go b/v3/newrelic/internal_context_test.go index dfaee698d..1e15e61cd 100644 --- a/v3/newrelic/internal_context_test.go +++ b/v3/newrelic/internal_context_test.go @@ -14,7 +14,7 @@ func TestWrapHandlerContext(t *testing.T) { // Test that WrapHandleFunc adds the transaction to the request's // context, and that it is accessible through FromContext. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) _, h := WrapHandleFunc(app.Application, "myTxn", func(rw http.ResponseWriter, r *http.Request) { txn := FromContext(r.Context()) segment := txn.StartSegment("mySegment") @@ -41,7 +41,7 @@ func TestStartExternalSegmentNilTransaction(t *testing.T) { // Test that StartExternalSegment pulls the transaction from the // request's context if it is not explicitly provided. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("myTxn") req, _ := http.NewRequest("GET", "http://example.com", nil) diff --git a/v3/newrelic/internal_test.go b/v3/newrelic/internal_test.go index dc3d042c2..9860b6b4b 100644 --- a/v3/newrelic/internal_test.go +++ b/v3/newrelic/internal_test.go @@ -257,6 +257,19 @@ func (ea expectApp) ExpectSpanEvents(t internal.Validator, want []internal.WantE ea.Application.Private.(internal.Expect).ExpectSpanEvents(t, want) } +func testAppMultiConfig(opts ...func(*Config)) func(*Config) { + return func(c *Config) { + for _, fn := range opts { + if fn != nil { + fn(c) + if c.Error != nil { + return + } + } + } + } +} + func testApp(replyfn func(*internal.ConnectReply), cfgfn func(*Config), t testing.TB) expectApp { lg := &errorSaverLogger{} app, err := NewApplication( diff --git a/v3/newrelic/limits.go b/v3/newrelic/limits.go index 44e38bab2..67ee68648 100644 --- a/v3/newrelic/limits.go +++ b/v3/newrelic/limits.go @@ -38,6 +38,7 @@ const ( maxHarvestSlowSQLs = 10 // maxSpanEvents is the maximum number of Span Events that can be captured // per 60-second harvest cycle + // XXX DEPRECATED: replaced with DistributedTracer.ReservoirLimit configuration value maxSpanEvents = 1000 // attributes From c6b4c2dede2d05e55f1b50adbb8cef6a77318995 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Fri, 25 Feb 2022 12:47:06 -0800 Subject: [PATCH 18/30] DT by default passing all unit tests --- v3/newrelic/internal_17_test.go | 7 +- v3/newrelic/internal_cross_process_test.go | 42 ++++-- v3/newrelic/internal_errors_13_test.go | 2 +- v3/newrelic/internal_errors_test.go | 60 ++++++--- .../internal_segment_attributes_test.go | 6 + v3/newrelic/internal_serverless_test.go | 13 +- v3/newrelic/internal_set_web_response_test.go | 6 +- v3/newrelic/internal_slow_queries_test.go | 22 +++ v3/newrelic/internal_synthetics_test.go | 6 +- v3/newrelic/internal_test.go | 127 ++++++++++-------- v3/newrelic/sql_driver_test.go | 14 +- 11 files changed, 200 insertions(+), 105 deletions(-) diff --git a/v3/newrelic/internal_17_test.go b/v3/newrelic/internal_17_test.go index 84dfff87c..82d1dc8f1 100644 --- a/v3/newrelic/internal_17_test.go +++ b/v3/newrelic/internal_17_test.go @@ -193,7 +193,12 @@ func TestRoundTripper(t *testing.T) { } func TestRoundTripperOldCAT(t *testing.T) { - app := testApp(nil, ConfigDistributedTracerEnabled(false), t) + cfgfn := func(c *Config) { + c.DistributedTracer.Enabled = false + c.CrossApplicationTracer.Enabled = true + } + + app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") url := "http://example.com/" req, err := http.NewRequest("GET", url, nil) diff --git a/v3/newrelic/internal_cross_process_test.go b/v3/newrelic/internal_cross_process_test.go index 8a356bd3c..9b1ff2bf6 100644 --- a/v3/newrelic/internal_cross_process_test.go +++ b/v3/newrelic/internal_cross_process_test.go @@ -34,25 +34,31 @@ var ( ) func inboundCrossProcessRequestFactory() *http.Request { - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.CrossApplicationTracer.Enabled = true + cfg.DistributedTracer.Enabled = false + } app := testApp(crossProcessReplyFn, cfgFn, nil) clientTxn := app.StartTransaction("client") req, err := http.NewRequest("GET", "newrelic.com", nil) StartExternalSegment(clientTxn, req) - if "" == req.Header.Get(cat.NewRelicIDName) { + if req.Header.Get(cat.NewRelicIDName) == "" { panic("missing cat header NewRelicIDName: " + req.Header.Get(cat.NewRelicIDName)) } - if "" == req.Header.Get(cat.NewRelicTxnName) { + if req.Header.Get(cat.NewRelicTxnName) == "" { panic("missing cat header NewRelicTxnName: " + req.Header.Get(cat.NewRelicTxnName)) } - if nil != err { + if err != nil { panic(err) } return req } func outboundCrossProcessResponse() http.Header { - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.CrossApplicationTracer.Enabled = true + cfg.DistributedTracer.Enabled = false + } app := testApp(crossProcessReplyFn, cfgFn, nil) w := httptest.NewRecorder() txn := app.StartTransaction("txn") @@ -65,7 +71,10 @@ func outboundCrossProcessResponse() http.Header { func TestCrossProcessWriteHeaderSuccess(t *testing.T) { // Test that the CAT response header is present when the consumer uses // txn.SetWebResponse().WriteHeader. - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false + cfg.CrossApplicationTracer.Enabled = true + } app := testApp(crossProcessReplyFn, cfgFn, t) w := httptest.NewRecorder() txn := app.StartTransaction("hello") @@ -74,7 +83,7 @@ func TestCrossProcessWriteHeaderSuccess(t *testing.T) { rw.WriteHeader(200) txn.End() - if "" == w.Header().Get(cat.NewRelicAppDataName) { + if w.Header().Get(cat.NewRelicAppDataName) == "" { t.Error(w.Header().Get(cat.NewRelicAppDataName)) } @@ -94,7 +103,10 @@ func TestCrossProcessWriteHeaderSuccess(t *testing.T) { func TestCrossProcessWriteSuccess(t *testing.T) { // Test that the CAT response header is present when the consumer uses // txn.Write. - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.CrossApplicationTracer.Enabled = true + cfg.DistributedTracer.Enabled = false + } app := testApp(crossProcessReplyFn, cfgFn, t) w := httptest.NewRecorder() txn := app.StartTransaction("hello") @@ -120,7 +132,10 @@ func TestCrossProcessWriteSuccess(t *testing.T) { func TestCrossProcessLocallyDisabled(t *testing.T) { // Test that the CAT can be disabled by local configuration. - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = false } + cfgFn := func(cfg *Config) { + cfg.CrossApplicationTracer.Enabled = false + cfg.DistributedTracer.Enabled = false + } app := testApp(crossProcessReplyFn, cfgFn, t) w := httptest.NewRecorder() txn := app.StartTransaction("hello") @@ -148,7 +163,9 @@ func TestCrossProcessLocallyDisabled(t *testing.T) { func TestCrossProcessDisabledByServerSideConfig(t *testing.T) { // Test that the CAT can be disabled by server-side-config. - cfgFn := func(cfg *Config) {} + cfgFn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false + } replyfn := func(reply *internal.ConnectReply) { crossProcessReplyFn(reply) json.Unmarshal([]byte(`{"agent_config":{"cross_application_tracer.enabled":false}}`), reply) @@ -180,7 +197,10 @@ func TestCrossProcessDisabledByServerSideConfig(t *testing.T) { func TestCrossProcessEnabledByServerSideConfig(t *testing.T) { // Test that the CAT can be enabled by server-side-config. - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = false } + cfgFn := func(cfg *Config) { + cfg.CrossApplicationTracer.Enabled = false + cfg.DistributedTracer.Enabled = false + } replyfn := func(reply *internal.ConnectReply) { crossProcessReplyFn(reply) json.Unmarshal([]byte(`{"agent_config":{"cross_application_tracer.enabled":true}}`), reply) diff --git a/v3/newrelic/internal_errors_13_test.go b/v3/newrelic/internal_errors_13_test.go index af015fd81..8de679b63 100644 --- a/v3/newrelic/internal_errors_13_test.go +++ b/v3/newrelic/internal_errors_13_test.go @@ -25,7 +25,7 @@ func TestNoticedWrappedError(t *testing.T) { beta := func() error { return fmt.Errorf("problem in beta: %w", gamma()) } alpha := func() error { return fmt.Errorf("problem in alpha: %w", beta()) } - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(alpha()) app.expectNoLoggedErrors(t) diff --git a/v3/newrelic/internal_errors_test.go b/v3/newrelic/internal_errors_test.go index e74dd609e..d5fa710cd 100644 --- a/v3/newrelic/internal_errors_test.go +++ b/v3/newrelic/internal_errors_test.go @@ -17,7 +17,7 @@ type myError struct{} func (e myError) Error() string { return "my msg" } func TestNoticeErrorBackground(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) app.expectNoLoggedErrors(t) @@ -38,7 +38,7 @@ func TestNoticeErrorBackground(t *testing.T) { } func TestNoticeErrorWeb(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.NoticeError(myError{}) @@ -61,7 +61,7 @@ func TestNoticeErrorWeb(t *testing.T) { } func TestNoticeErrorTxnEnded(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.End() txn.NoticeError(myError{}) @@ -75,7 +75,10 @@ func TestNoticeErrorTxnEnded(t *testing.T) { } func TestNoticeErrorHighSecurity(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.HighSecurity = true } + cfgFn := func(cfg *Config) { + cfg.HighSecurity = true + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) @@ -98,7 +101,7 @@ func TestNoticeErrorHighSecurity(t *testing.T) { func TestNoticeErrorMessageSecurityPolicy(t *testing.T) { replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.AllowRawExceptionMessages.SetEnabled(false) } - app := testApp(replyfn, nil, t) + app := testApp(replyfn, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) app.expectNoLoggedErrors(t) @@ -119,7 +122,10 @@ func TestNoticeErrorMessageSecurityPolicy(t *testing.T) { } func TestNoticeErrorLocallyDisabled(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.ErrorCollector.Enabled = false } + cfgFn := func(cfg *Config) { + cfg.ErrorCollector.Enabled = false + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) @@ -134,7 +140,9 @@ func TestNoticeErrorLocallyDisabled(t *testing.T) { func TestErrorsDisabledByServerSideConfig(t *testing.T) { // Test that errors can be disabled by server-side-config. - cfgFn := func(cfg *Config) {} + cfgFn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false + } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"error_collector.enabled":false}}`), reply) } @@ -154,6 +162,7 @@ func TestErrorsEnabledByServerSideConfig(t *testing.T) { // Test that errors can be enabled by server-side-config. cfgFn := func(cfg *Config) { cfg.ErrorCollector.Enabled = false + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"error_collector.enabled":true}}`), reply) @@ -184,7 +193,7 @@ func TestNoticeErrorTracedErrorsRemotelyDisabled(t *testing.T) { // This tests that the connect reply field "collect_errors" controls the // collection of traced-errors, not error-events. replyfn := func(reply *internal.ConnectReply) { reply.CollectErrors = false } - app := testApp(replyfn, nil, t) + app := testApp(replyfn, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) app.expectNoLoggedErrors(t) @@ -203,7 +212,7 @@ func TestNoticeErrorTracedErrorsRemotelyDisabled(t *testing.T) { } func TestNoticeErrorNil(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(nil) app.expectSingleLoggedError(t, "unable to notice error", map[string]interface{}{ @@ -216,7 +225,10 @@ func TestNoticeErrorNil(t *testing.T) { } func TestNoticeErrorEventsLocallyDisabled(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.ErrorCollector.CaptureEvents = false } + cfgFn := func(cfg *Config) { + cfg.ErrorCollector.CaptureEvents = false + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) @@ -233,7 +245,7 @@ func TestNoticeErrorEventsLocallyDisabled(t *testing.T) { func TestNoticeErrorEventsRemotelyDisabled(t *testing.T) { replyfn := func(reply *internal.ConnectReply) { reply.CollectErrorEvents = false } - app := testApp(replyfn, nil, t) + app := testApp(replyfn, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) app.expectNoLoggedErrors(t) @@ -253,7 +265,7 @@ func (e errorWithClass) Error() string { return "my msg" } func (e errorWithClass) ErrorClass() string { return e.class } func TestErrorWithClasser(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(errorWithClass{class: "zap"}) app.expectNoLoggedErrors(t) @@ -274,7 +286,7 @@ func TestErrorWithClasser(t *testing.T) { } func TestErrorWithClasserReturnsEmpty(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(errorWithClass{class: ""}) app.expectNoLoggedErrors(t) @@ -308,7 +320,7 @@ func (e withStackTrace) Error() string { return "my msg" } func (e withStackTrace) StackTrace() []uintptr { return e.trace } func TestErrorWithStackTrace(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") e := makeErrorWithStackTrace() txn.NoticeError(e) @@ -330,7 +342,7 @@ func TestErrorWithStackTrace(t *testing.T) { } func TestErrorWithStackTraceReturnsNil(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") e := withStackTrace{trace: nil} txn.NoticeError(e) @@ -352,7 +364,7 @@ func TestErrorWithStackTraceReturnsNil(t *testing.T) { } func TestNewrelicErrorNoAttributes(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(Error{ Message: "my msg", @@ -379,7 +391,7 @@ func TestNewrelicErrorValidAttributes(t *testing.T) { extraAttributes := map[string]interface{}{ "zip": "zap", } - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(Error{ Message: "my msg", @@ -409,7 +421,10 @@ func TestNewrelicErrorAttributesHighSecurity(t *testing.T) { extraAttributes := map[string]interface{}{ "zip": "zap", } - cfgFn := func(cfg *Config) { cfg.HighSecurity = true } + cfgFn := func(cfg *Config) { + cfg.HighSecurity = true + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") txn.NoticeError(Error{ @@ -441,7 +456,7 @@ func TestNewrelicErrorAttributesSecurityPolicy(t *testing.T) { "zip": "zap", } replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.CustomParameters.SetEnabled(false) } - app := testApp(replyfn, nil, t) + app := testApp(replyfn, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(Error{ Message: "my msg", @@ -471,7 +486,7 @@ func TestNewrelicErrorAttributeOverridesNormalAttribute(t *testing.T) { extraAttributes := map[string]interface{}{ "zip": "zap", } - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.AddAttribute("zip", 123) txn.NoticeError(Error{ @@ -503,7 +518,7 @@ func TestNewrelicErrorInvalidAttributes(t *testing.T) { "zip": "zap", "INVALID": struct{}{}, } - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(Error{ Message: "my msg", @@ -522,6 +537,7 @@ func TestNewrelicErrorInvalidAttributes(t *testing.T) { func TestExtraErrorAttributeRemovedThroughConfiguration(t *testing.T) { cfgfn := func(cfg *Config) { cfg.ErrorCollector.Attributes.Exclude = []string{"IGNORE_ME"} + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -558,7 +574,7 @@ func TestTooManyExtraErrorAttributes(t *testing.T) { for i := 0; i <= attributeErrorLimit; i++ { attrs[strconv.Itoa(i)] = i } - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(Error{ Message: "my msg", diff --git a/v3/newrelic/internal_segment_attributes_test.go b/v3/newrelic/internal_segment_attributes_test.go index 71a075511..e85fda34c 100644 --- a/v3/newrelic/internal_segment_attributes_test.go +++ b/v3/newrelic/internal_segment_attributes_test.go @@ -181,6 +181,7 @@ func TestTraceStacktraceServerSideConfig(t *testing.T) { cfg.TransactionTracer.Segments.StackTraceThreshold = 1 * time.Hour cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(replyfn, cfgfn, t) txn := app.StartTransaction("hello") @@ -214,6 +215,7 @@ func TestTraceSegmentAttributesExcluded(t *testing.T) { reply.SetSampleEverything() } cfgfn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false cfg.TransactionTracer.Segments.Threshold = 0 cfg.TransactionTracer.Segments.StackTraceThreshold = 1 * time.Hour cfg.TransactionTracer.Threshold.IsApdexFailing = false @@ -371,6 +373,8 @@ func TestTraceSegmentAttributesDisabled(t *testing.T) { // Test that segment attributes can be disabled by Attributes.Enabled // but backtrace and transaction_guid still appear. cfgfn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false + cfg.CrossApplicationTracer.Enabled = true cfg.Attributes.Enabled = false cfg.TransactionTracer.Segments.Threshold = 0 cfg.TransactionTracer.Segments.StackTraceThreshold = 0 @@ -442,6 +446,8 @@ func TestTraceSegmentAttributesSpecificallyDisabled(t *testing.T) { // TransactionTracer.Segments.Attributes.Enabled but backtrace and // transaction_guid still appear. cfgfn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false + cfg.CrossApplicationTracer.Enabled = true cfg.TransactionTracer.Segments.Attributes.Enabled = false cfg.TransactionTracer.Segments.Threshold = 0 cfg.TransactionTracer.Segments.StackTraceThreshold = 0 diff --git a/v3/newrelic/internal_serverless_test.go b/v3/newrelic/internal_serverless_test.go index 766d809a8..53acadfb5 100644 --- a/v3/newrelic/internal_serverless_test.go +++ b/v3/newrelic/internal_serverless_test.go @@ -137,6 +137,7 @@ func TestServerlessLowApdex(t *testing.T) { cfgFn := func(cfg *Config) { cfg.ServerlessMode.Enabled = true cfg.ServerlessMode.ApdexThreshold = apdex + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") @@ -160,6 +161,7 @@ func TestServerlessHighApdex(t *testing.T) { cfgFn := func(cfg *Config) { cfg.ServerlessMode.Enabled = true cfg.ServerlessMode.ApdexThreshold = apdex + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") @@ -179,7 +181,10 @@ func TestServerlessHighApdex(t *testing.T) { } func TestServerlessRecordCustomMetric(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.ServerlessMode.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.ServerlessMode.Enabled = true + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) app.RecordCustomMetric("myMetric", 123.0) app.expectSingleLoggedError(t, "unable to record custom metric", map[string]interface{}{ @@ -189,7 +194,10 @@ func TestServerlessRecordCustomMetric(t *testing.T) { } func TestServerlessRecordCustomEvent(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.ServerlessMode.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.ServerlessMode.Enabled = true + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) attributes := map[string]interface{}{"zip": 1} @@ -225,6 +233,7 @@ func TestServerlessRecordCustomEvent(t *testing.T) { func TestServerlessJSON(t *testing.T) { cfgFn := func(cfg *Config) { cfg.ServerlessMode.Enabled = true + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") diff --git a/v3/newrelic/internal_set_web_response_test.go b/v3/newrelic/internal_set_web_response_test.go index 785b77a24..dd66e56b3 100644 --- a/v3/newrelic/internal_set_web_response_test.go +++ b/v3/newrelic/internal_set_web_response_test.go @@ -14,7 +14,7 @@ import ( func TestSetWebResponseNil(t *testing.T) { // Test that the methods of the txn.SetWebResponse(nil) return value // writer can safely be called. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") rw := txn.SetWebResponse(nil) rw.WriteHeader(123) @@ -38,7 +38,7 @@ func TestSetWebResponseNil(t *testing.T) { func TestSetWebResponseSuccess(t *testing.T) { // Test that the return value of txn.SetWebResponse delegates to the // input writer. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") w := httptest.NewRecorder() rw := txn.SetWebResponse(w) @@ -79,7 +79,7 @@ func (w writerWithFlush) Flush() {} func TestSetWebResponseTxnUpgraded(t *testing.T) { // Test that the writer returned by SetWebResponse has the optional // methods of the input writer. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") rw := txn.SetWebResponse(writerWithFlush{}) if _, ok := rw.(http.Flusher); !ok { diff --git a/v3/newrelic/internal_slow_queries_test.go b/v3/newrelic/internal_slow_queries_test.go index fd6a329df..c7df52554 100644 --- a/v3/newrelic/internal_slow_queries_test.go +++ b/v3/newrelic/internal_slow_queries_test.go @@ -15,6 +15,7 @@ import ( func TestSlowQueryBasic(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -45,6 +46,7 @@ func TestSlowQueryLocallyDisabled(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 cfg.DatastoreTracer.SlowQuery.Enabled = false + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -65,6 +67,7 @@ func TestSlowQueryLocallyDisabled(t *testing.T) { func TestSlowQueryRemotelyDisabled(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { reply.CollectTraces = false @@ -88,6 +91,7 @@ func TestSlowQueryRemotelyDisabled(t *testing.T) { func TestSlowQueryBelowThreshold(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 1 * time.Hour + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -107,6 +111,7 @@ func TestSlowQueryBelowThreshold(t *testing.T) { func TestSlowQueryDatabaseProvided(t *testing.T) { cfgfn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false cfg.DatastoreTracer.SlowQuery.Threshold = 0 } app := testApp(nil, cfgfn, t) @@ -138,6 +143,7 @@ func TestSlowQueryDatabaseProvided(t *testing.T) { func TestSlowQueryHostProvided(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -179,6 +185,7 @@ func TestSlowQueryHostProvided(t *testing.T) { func TestSlowQueryPortProvided(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -220,6 +227,7 @@ func TestSlowQueryPortProvided(t *testing.T) { func TestSlowQueryHostPortProvided(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -262,6 +270,7 @@ func TestSlowQueryHostPortProvided(t *testing.T) { func TestSlowQueryAggregation(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -317,6 +326,7 @@ func TestSlowQueryAggregation(t *testing.T) { func TestSlowQueryMissingQuery(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -345,6 +355,7 @@ func TestSlowQueryMissingQuery(t *testing.T) { func TestSlowQueryMissingEverything(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -379,6 +390,7 @@ func TestSlowQueryMissingEverything(t *testing.T) { func TestSlowQueryWithQueryParameters(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -415,6 +427,7 @@ func TestSlowQueryHighSecurity(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 cfg.HighSecurity = true + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -452,6 +465,7 @@ func TestSlowQuerySecurityPolicyFalse(t *testing.T) { // and the sql format string should be replaced. cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.RecordSQL.SetEnabled(false) @@ -492,6 +506,7 @@ func TestSlowQuerySecurityPolicyTrue(t *testing.T) { // should be omitted. cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.RecordSQL.SetEnabled(true) @@ -530,6 +545,7 @@ func TestSlowQuerySecurityPolicyTrue(t *testing.T) { func TestSlowQueryInvalidParameters(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -573,6 +589,7 @@ func TestSlowQueryParametersDisabled(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 cfg.DatastoreTracer.QueryParameters.Enabled = false + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -609,6 +626,7 @@ func TestSlowQueryInstanceDisabled(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 cfg.DatastoreTracer.InstanceReporting.Enabled = false + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -650,6 +668,7 @@ func TestSlowQueryInstanceDisabledLocalhost(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 cfg.DatastoreTracer.InstanceReporting.Enabled = false + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -692,6 +711,7 @@ func TestSlowQueryDatabaseNameDisabled(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 cfg.DatastoreTracer.DatabaseNameReporting.Enabled = false + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -763,6 +783,7 @@ func TestDatastoreAPICrossAgent(t *testing.T) { tc.Input.Configuration.InstanceEnabled cfg.DatastoreTracer.DatabaseNameReporting.Enabled = tc.Input.Configuration.DatabaseEnabled + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -834,6 +855,7 @@ func TestDatastoreAPICrossAgent(t *testing.T) { func TestSlowQueryParamsInvalid(t *testing.T) { cfgfn := func(cfg *Config) { cfg.DatastoreTracer.SlowQuery.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") diff --git a/v3/newrelic/internal_synthetics_test.go b/v3/newrelic/internal_synthetics_test.go index 3bd8dbb68..f315ddd33 100644 --- a/v3/newrelic/internal_synthetics_test.go +++ b/v3/newrelic/internal_synthetics_test.go @@ -76,7 +76,10 @@ func inboundSyntheticsRequestBuilder(oldCatEnabled bool, betterCatEnabled bool) } func TestSyntheticsOldCAT(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = true } + cfgFn := func(cfg *Config) { + cfg.CrossApplicationTracer.Enabled = true + cfg.DistributedTracer.Enabled = false + } app := testApp(syntheticsConnectReplyFn, cfgFn, t) clientTxn := app.StartTransaction("helloOldCAT") clientTxn.SetWebRequestHTTP(inboundSyntheticsRequestBuilder(true, false)) @@ -155,6 +158,7 @@ func TestSyntheticsBetterCAT(t *testing.T) { func TestSyntheticsStandalone(t *testing.T) { cfgFn := func(cfg *Config) { cfg.AppName = "syntheticsReceiver" + cfg.DistributedTracer.Enabled = false cfg.CrossApplicationTracer.Enabled = false } app := testApp(syntheticsConnectReplyFn, cfgFn, t) diff --git a/v3/newrelic/internal_test.go b/v3/newrelic/internal_test.go index 9860b6b4b..541a5e85a 100644 --- a/v3/newrelic/internal_test.go +++ b/v3/newrelic/internal_test.go @@ -257,19 +257,6 @@ func (ea expectApp) ExpectSpanEvents(t internal.Validator, want []internal.WantE ea.Application.Private.(internal.Expect).ExpectSpanEvents(t, want) } -func testAppMultiConfig(opts ...func(*Config)) func(*Config) { - return func(c *Config) { - for _, fn := range opts { - if fn != nil { - fn(c) - if c.Error != nil { - return - } - } - } - } -} - func testApp(replyfn func(*internal.ConnectReply), cfgfn func(*Config), t testing.TB) expectApp { lg := &errorSaverLogger{} app, err := NewApplication( @@ -443,7 +430,7 @@ func TestTxnResponseWriter(t *testing.T) { } func TestTransactionEventWeb(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.End() @@ -457,7 +444,7 @@ func TestTransactionEventWeb(t *testing.T) { } func TestTransactionEventBackground(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.End() app.expectNoLoggedErrors(t) @@ -469,7 +456,10 @@ func TestTransactionEventBackground(t *testing.T) { } func TestTransactionEventLocallyDisabled(t *testing.T) { - cfgFn := func(cfg *Config) { cfg.TransactionEvents.Enabled = false } + cfgFn := func(cfg *Config) { + cfg.TransactionEvents.Enabled = false + cfg.DistributedTracer.Enabled = false + } app := testApp(nil, cfgFn, t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) @@ -480,7 +470,7 @@ func TestTransactionEventLocallyDisabled(t *testing.T) { func TestTransactionEventRemotelyDisabled(t *testing.T) { replyfn := func(reply *internal.ConnectReply) { reply.CollectAnalyticsEvents = false } - app := testApp(replyfn, nil, t) + app := testApp(replyfn, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.End() @@ -489,7 +479,7 @@ func TestTransactionEventRemotelyDisabled(t *testing.T) { } func TestSetName(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("one") txn.SetName("hello") txn.End() @@ -516,7 +506,7 @@ func enableRecordPanics(cfg *Config) { cfg.ErrorCollector.RecordPanics = true } func TestPanicNotEnabled(t *testing.T) { // Test that panics are not recorded as errors if the config setting has // not been enabled. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") e := myError{} @@ -531,7 +521,10 @@ func TestPanicNotEnabled(t *testing.T) { } func TestPanicError(t *testing.T) { - app := testApp(nil, enableRecordPanics, t) + app := testApp(nil, func(cfg *Config) { + enableRecordPanics(cfg) + cfg.DistributedTracer.Enabled = false + }, t) txn := app.StartTransaction("hello") e := myError{} @@ -556,7 +549,10 @@ func TestPanicError(t *testing.T) { } func TestPanicString(t *testing.T) { - app := testApp(nil, enableRecordPanics, t) + app := testApp(nil, func(cfg *Config) { + enableRecordPanics(cfg) + cfg.DistributedTracer.Enabled = false + }, t) txn := app.StartTransaction("hello") e := "my string" @@ -581,7 +577,10 @@ func TestPanicString(t *testing.T) { } func TestPanicInt(t *testing.T) { - app := testApp(nil, enableRecordPanics, t) + app := testApp(nil, func(cfg *Config) { + enableRecordPanics(cfg) + cfg.DistributedTracer.Enabled = false + }, t) txn := app.StartTransaction("hello") e := 22 @@ -606,7 +605,10 @@ func TestPanicInt(t *testing.T) { } func TestPanicNil(t *testing.T) { - app := testApp(nil, enableRecordPanics, t) + app := testApp(nil, func(cfg *Config) { + enableRecordPanics(cfg) + cfg.DistributedTracer.Enabled = false + }, t) txn := app.StartTransaction("hello") r := deferEndPanic(txn, nil) @@ -620,7 +622,7 @@ func TestPanicNil(t *testing.T) { } func TestResponseCodeError(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) w := newCompatibleResponseRecorder() txn := app.StartTransaction("hello") rw := txn.SetWebResponse(w) @@ -655,7 +657,7 @@ func TestResponseCodeError(t *testing.T) { } func TestResponseCode404Filtered(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) w := newCompatibleResponseRecorder() txn := app.StartTransaction("hello") rw := txn.SetWebResponse(w) @@ -678,6 +680,7 @@ func TestResponseCodeCustomFilter(t *testing.T) { cfgFn := func(cfg *Config) { cfg.ErrorCollector.IgnoreStatusCodes = append(cfg.ErrorCollector.IgnoreStatusCodes, 405) + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgFn, t) w := newCompatibleResponseRecorder() @@ -698,6 +701,7 @@ func TestResponseCodeServerSideFilterObserved(t *testing.T) { // Test that server-side ignore_status_codes are observed. cfgFn := func(cfg *Config) { cfg.ErrorCollector.IgnoreStatusCodes = nil + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"error_collector.ignore_status_codes":[405]}}`), reply) @@ -721,6 +725,7 @@ func TestResponseCodeServerSideOverwriteLocal(t *testing.T) { // Test that server-side ignore_status_codes are used in place of local // Config.ErrorCollector.IgnoreStatusCodes. cfgFn := func(cfg *Config) { + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"error_collector.ignore_status_codes":[402]}}`), reply) @@ -755,7 +760,7 @@ func TestResponseCodeServerSideOverwriteLocal(t *testing.T) { } func TestResponseCodeAfterEnd(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) w := newCompatibleResponseRecorder() txn := app.StartTransaction("hello") rw := txn.SetWebResponse(w) @@ -774,7 +779,7 @@ func TestResponseCodeAfterEnd(t *testing.T) { } func TestResponseCodeAfterWrite(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) w := newCompatibleResponseRecorder() txn := app.StartTransaction("hello") rw := txn.SetWebResponse(w) @@ -799,7 +804,7 @@ func TestResponseCodeAfterWrite(t *testing.T) { } func TestQueueTime(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) req, err := http.NewRequest("GET", helloPath+helloQueryParams, nil) req.Header.Add("X-Queue-Start", "1465793282.12345") if nil != err { @@ -841,7 +846,7 @@ func TestQueueTime(t *testing.T) { } func TestIgnore(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) txn.Ignore() @@ -854,7 +859,7 @@ func TestIgnore(t *testing.T) { } func TestIgnoreAlreadyEnded(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) txn.End() @@ -1022,7 +1027,7 @@ func TestZeroSegmentsSafe(t *testing.T) { } func TestTraceSegmentDefer(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) func() { @@ -1037,7 +1042,7 @@ func TestTraceSegmentDefer(t *testing.T) { } func TestTraceSegmentNilErr(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.StartSegment("segment").End() @@ -1051,7 +1056,7 @@ func TestTraceSegmentNilErr(t *testing.T) { } func TestTraceSegmentOutOfOrder(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s1 := txn.StartSegment("s1") @@ -1071,7 +1076,7 @@ func TestTraceSegmentOutOfOrder(t *testing.T) { } func TestTraceSegmentEndedBeforeStartSegment(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.End() @@ -1084,7 +1089,7 @@ func TestTraceSegmentEndedBeforeStartSegment(t *testing.T) { } func TestTraceSegmentEndedBeforeEndSegment(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := txn.StartSegment("segment") @@ -1097,7 +1102,7 @@ func TestTraceSegmentEndedBeforeEndSegment(t *testing.T) { } func TestTraceSegmentPanic(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) func() { @@ -1137,7 +1142,7 @@ func TestTraceSegmentPanic(t *testing.T) { } func TestTraceSegmentNilTxn(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := Segment{Name: "hello"} @@ -1148,7 +1153,7 @@ func TestTraceSegmentNilTxn(t *testing.T) { } func TestTraceDatastore(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := DatastoreSegment{} @@ -1190,7 +1195,7 @@ func TestTraceDatastore(t *testing.T) { } func TestTraceDatastoreBackground(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s := DatastoreSegment{ StartTime: txn.StartSegmentNow(), @@ -1231,7 +1236,7 @@ func TestTraceDatastoreBackground(t *testing.T) { } func TestTraceDatastoreMissingProductOperationCollection(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := DatastoreSegment{ @@ -1270,7 +1275,7 @@ func TestTraceDatastoreMissingProductOperationCollection(t *testing.T) { } func TestTraceDatastoreNilTxn(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) var s DatastoreSegment @@ -1298,7 +1303,7 @@ func TestTraceDatastoreNilTxn(t *testing.T) { } func TestTraceDatastoreTxnEnded(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.NoticeError(myError{}) @@ -1330,7 +1335,7 @@ func TestTraceDatastoreTxnEnded(t *testing.T) { } func TestTraceExternal(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := ExternalSegment{ @@ -1570,7 +1575,7 @@ func TestExternalSegmentCustomFieldsWithResponse(t *testing.T) { } func TestTraceExternalBadURL(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := ExternalSegment{ @@ -1600,7 +1605,7 @@ func TestTraceExternalBadURL(t *testing.T) { } func TestTraceExternalBackground(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s := ExternalSegment{ StartTime: txn.StartSegmentNow(), @@ -1636,7 +1641,7 @@ func TestTraceExternalBackground(t *testing.T) { } func TestTraceExternalMissingURL(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) s := ExternalSegment{ @@ -1673,7 +1678,7 @@ func TestTraceExternalMissingURL(t *testing.T) { } func TestTraceExternalNilTxn(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.NoticeError(myError{}) @@ -1698,7 +1703,7 @@ func TestTraceExternalNilTxn(t *testing.T) { } func TestTraceExternalTxnEnded(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.NoticeError(myError{}) @@ -1728,7 +1733,7 @@ func TestTraceExternalTxnEnded(t *testing.T) { } func TestTraceBelowThreshold(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.SetWebRequestHTTP(helloRequest) txn.End() @@ -1736,7 +1741,7 @@ func TestTraceBelowThreshold(t *testing.T) { } func TestTraceBelowThresholdBackground(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.End() app.ExpectTxnTraces(t, []internal.WantTxnTrace{}) @@ -1747,6 +1752,7 @@ func TestTraceNoSegments(t *testing.T) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -1764,6 +1770,7 @@ func TestTraceDisabledLocally(t *testing.T) { cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 cfg.TransactionTracer.Enabled = false + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -1779,6 +1786,7 @@ func TestTraceDisabledByServerSideConfig(t *testing.T) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"transaction_tracer.enabled":false}}`), reply) @@ -1798,6 +1806,7 @@ func TestTraceEnabledByServerSideConfig(t *testing.T) { cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 cfg.TransactionTracer.Enabled = false + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"transaction_tracer.enabled":true}}`), reply) @@ -1820,6 +1829,7 @@ func TestTraceDisabledRemotelyOverridesServerSideConfig(t *testing.T) { cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 cfg.TransactionTracer.Enabled = true + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { json.Unmarshal([]byte(`{"agent_config":{"transaction_tracer.enabled":true},"collect_traces":false}`), reply) @@ -1836,6 +1846,7 @@ func TestTraceDisabledRemotely(t *testing.T) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 + cfg.DistributedTracer.Enabled = false } replyfn := func(reply *internal.ConnectReply) { reply.CollectTraces = false @@ -1852,6 +1863,7 @@ func TestTraceWithSegments(t *testing.T) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 0 + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -1882,6 +1894,7 @@ func TestTraceSegmentsBelowThreshold(t *testing.T) { cfg.TransactionTracer.Threshold.IsApdexFailing = false cfg.TransactionTracer.Threshold.Duration = 0 cfg.TransactionTracer.Segments.Threshold = 1 * time.Hour + cfg.DistributedTracer.Enabled = false } app := testApp(nil, cfgfn, t) txn := app.StartTransaction("hello") @@ -1908,7 +1921,7 @@ func TestTraceSegmentsBelowThreshold(t *testing.T) { } func TestNoticeErrorTxnEvents(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") txn.NoticeError(myError{}) app.expectNoLoggedErrors(t) @@ -1922,7 +1935,7 @@ func TestNoticeErrorTxnEvents(t *testing.T) { } func TestTransactionApplication(t *testing.T) { - ap := testApp(nil, nil, t) + ap := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := ap.StartTransaction("hello") app := txn.Application() app.RecordCustomMetric("myMetric", 123.0) @@ -1952,7 +1965,7 @@ func (f flushWriter) Header() http.Header { return nil } func (f flushWriter) Flush() {} func TestAsync(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s1 := txn.StartSegment("mainThread") asyncThread := txn.NewGoroutine() @@ -2044,7 +2057,7 @@ func TestMessageProducerSegmentBasic(t *testing.T) { } func TestMessageProducerSegmentMissingDestinationType(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s := MessageProducerSegment{ StartTime: txn.StartSegmentNow(), @@ -2065,7 +2078,7 @@ func TestMessageProducerSegmentMissingDestinationType(t *testing.T) { } func TestMessageProducerSegmentTemp(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s := MessageProducerSegment{ StartTime: txn.StartSegmentNow(), @@ -2088,7 +2101,7 @@ func TestMessageProducerSegmentTemp(t *testing.T) { } func TestMessageProducerSegmentNoName(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s := MessageProducerSegment{ StartTime: txn.StartSegmentNow(), @@ -2109,7 +2122,7 @@ func TestMessageProducerSegmentNoName(t *testing.T) { } func TestMessageProducerSegmentTxnEnded(t *testing.T) { - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) txn := app.StartTransaction("hello") s := MessageProducerSegment{ StartTime: txn.StartSegmentNow(), diff --git a/v3/newrelic/sql_driver_test.go b/v3/newrelic/sql_driver_test.go index 635d4cbb6..c6ea93ac2 100644 --- a/v3/newrelic/sql_driver_test.go +++ b/v3/newrelic/sql_driver_test.go @@ -95,7 +95,7 @@ var ( func TestDriverStmtExecContext(t *testing.T) { // Test that driver.Stmt.ExecContext calls get instrumented. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) dr := InstrumentSQLDriver(testDriver{}, testBuilder) txn := app.StartTransaction("hello") conn, _ := dr.Open("myhost,myport,mydatabase") @@ -108,7 +108,7 @@ func TestDriverStmtExecContext(t *testing.T) { func TestDriverStmtQueryContext(t *testing.T) { // Test that driver.Stmt.PrepareContext calls get instrumented. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) dr := InstrumentSQLDriver(testDriver{}, testBuilder) txn := app.StartTransaction("hello") conn, _ := dr.Open("myhost,myport,mydatabase") @@ -121,7 +121,7 @@ func TestDriverStmtQueryContext(t *testing.T) { func TestDriverConnExecContext(t *testing.T) { // Test that driver.Conn.ExecContext calls get instrumented. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) dr := InstrumentSQLDriver(testDriver{}, testBuilder) txn := app.StartTransaction("hello") conn, _ := dr.Open("myhost,myport,mydatabase") @@ -133,7 +133,7 @@ func TestDriverConnExecContext(t *testing.T) { func TestDriverConnQueryContext(t *testing.T) { // Test that driver.Conn.QueryContext calls get instrumented. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) dr := InstrumentSQLDriver(testDriver{}, testBuilder) txn := app.StartTransaction("hello") conn, _ := dr.Open("myhost,myport,mydatabase") @@ -145,7 +145,7 @@ func TestDriverConnQueryContext(t *testing.T) { func TestDriverContext(t *testing.T) { // Test that driver.OpenConnector returns an instrumented connector. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) dr := InstrumentSQLDriver(testDriver{}, testBuilder) txn := app.StartTransaction("hello") connector, _ := dr.(driver.DriverContext).OpenConnector("myhost,myport,mydatabase") @@ -159,7 +159,7 @@ func TestDriverContext(t *testing.T) { func TestInstrumentSQLConnector(t *testing.T) { // Test that connections returned by an instrumented driver.Connector // are instrumented. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) bld := testBuilder bld.BaseSegment.Host = "myhost" bld.BaseSegment.PortPathOrID = "myport" @@ -175,7 +175,7 @@ func TestInstrumentSQLConnector(t *testing.T) { func TestConnectorToDriver(t *testing.T) { // Test that driver.Connector.Driver returns an instrumented Driver. - app := testApp(nil, nil, t) + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) connector := InstrumentSQLConnector(testConnector{}, testBuilder) txn := app.StartTransaction("hello") dr := connector.Driver() From e8ef576a3712d34e05664f832a88da343f2bf64e Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Fri, 25 Feb 2022 15:56:24 -0800 Subject: [PATCH 19/30] (unstable commit) work in progress on changing reservoir size --- v3/newrelic/app_run.go | 25 ++++++++++++++++++++++--- v3/newrelic/app_run_test.go | 10 +++++----- v3/newrelic/config.go | 6 ++++-- v3/newrelic/harvest.go | 2 +- v3/newrelic/limits.go | 4 +++- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/v3/newrelic/app_run.go b/v3/newrelic/app_run.go index 9c0781371..6aa7f12f5 100644 --- a/v3/newrelic/app_run.go +++ b/v3/newrelic/app_run.go @@ -197,10 +197,29 @@ func (run *appRun) MaxCustomEvents() int { func (run *appRun) MaxErrorEvents() int { return run.limit(internal.MaxErrorEvents, run.ptrErrorEvents) } -func (run *appRun) MaxSpanEvents() int { return run.limit(maxSpanEvents, run.ptrSpanEvents) } + +// MaxSpanEvents returns the reservoir limit for collected span events, +// which will be the default or the user's configured size (if any), but +// may be capped to the maximum allowed by the collector. +func (run *appRun) MaxSpanEvents() int { + return run.maxLimit(run.Config.DistributedTracer.ReservoirLimit, run.ptrSpanEvents) +} + +// maxLimit is like limit, but rather than always allowing the collector's +// value to override the default, we will let the collector specify the maximum +// value, allowing the default to be less than that amount. +func (run *appRun) maxLimit(dflt int, field func() *uint) int { + if field() != nil { + maxAllowed := int(*field()) + if maxAllowed < dflt { + return maxAllowed + } + } + return dflt +} func (run *appRun) limit(dflt int, field func() *uint) int { - if nil != field() { + if field() != nil { return int(*field()) } return dflt @@ -216,7 +235,7 @@ func (run *appRun) ReportPeriods() map[harvestTypes]time.Duration { harvestErrorEvents: run.ptrErrorEvents, harvestSpanEvents: run.ptrSpanEvents, } { - if nil != run && fn() != nil { + if run != nil && fn() != nil { configurable |= tp } else { fixed |= tp diff --git a/v3/newrelic/app_run_test.go b/v3/newrelic/app_run_test.go index 7ed1067a8..56bd33c2f 100644 --- a/v3/newrelic/app_run_test.go +++ b/v3/newrelic/app_run_test.go @@ -129,7 +129,7 @@ func TestEmptyReplyEventHarvestDefaults(t *testing.T) { maxTxnEvents: internal.MaxTxnEvents, maxCustomEvents: internal.MaxCustomEvents, maxErrorEvents: internal.MaxErrorEvents, - maxSpanEvents: maxSpanEvents, + maxSpanEvents: run.Config.DistributedTracer.ReservoirLimit, periods: map[harvestTypes]time.Duration{ harvestTypesAll: 60 * time.Second, 0: 60 * time.Second, @@ -179,7 +179,7 @@ func TestZeroReportPeriod(t *testing.T) { maxTxnEvents: internal.MaxTxnEvents, maxCustomEvents: internal.MaxCustomEvents, maxErrorEvents: internal.MaxErrorEvents, - maxSpanEvents: maxSpanEvents, + maxSpanEvents: run.Config.DistributedTracer.ReservoirLimit, periods: map[harvestTypes]time.Duration{ harvestTypesAll: 60 * time.Second, 0: 60 * time.Second, @@ -223,7 +223,7 @@ func TestEventHarvestFieldsOnlyTxnEvents(t *testing.T) { maxTxnEvents: 3, maxCustomEvents: internal.MaxCustomEvents, maxErrorEvents: internal.MaxErrorEvents, - maxSpanEvents: maxSpanEvents, + maxSpanEvents: run.Config.DistributedTracer.ReservoirLimit, periods: map[harvestTypes]time.Duration{ harvestTypesAll ^ harvestTxnEvents: 60 * time.Second, harvestTxnEvents: 5 * time.Second, @@ -245,7 +245,7 @@ func TestEventHarvestFieldsOnlyErrorEvents(t *testing.T) { maxTxnEvents: internal.MaxTxnEvents, maxCustomEvents: internal.MaxCustomEvents, maxErrorEvents: 3, - maxSpanEvents: maxSpanEvents, + maxSpanEvents: run.Config.DistributedTracer.ReservoirLimit, periods: map[harvestTypes]time.Duration{ harvestTypesAll ^ harvestErrorEvents: 60 * time.Second, harvestErrorEvents: 5 * time.Second, @@ -267,7 +267,7 @@ func TestEventHarvestFieldsOnlyCustomEvents(t *testing.T) { maxTxnEvents: internal.MaxTxnEvents, maxCustomEvents: 3, maxErrorEvents: internal.MaxErrorEvents, - maxSpanEvents: maxSpanEvents, + maxSpanEvents: run.Config.DistributedTracer.ReservoirLimit, periods: map[harvestTypes]time.Duration{ harvestTypesAll ^ harvestCustomEvents: 60 * time.Second, harvestCustomEvents: 5 * time.Second, diff --git a/v3/newrelic/config.go b/v3/newrelic/config.go index 3ae6baa08..07535afe1 100644 --- a/v3/newrelic/config.go +++ b/v3/newrelic/config.go @@ -235,7 +235,9 @@ type Config struct { // Disabling the New Relic header here does not prevent the agent from // accepting *inbound* New Relic headers. ExcludeNewRelicHeader bool - ReservoirLimit int + // ReservoirLimit sets the desired maximum span event reservoir limit + // for collecting span event data. The collector MAY override this value. + ReservoirLimit int } // SpanEvents controls behavior relating to Span Events. Span Events @@ -416,7 +418,7 @@ func defaultConfig() Config { c.CrossApplicationTracer.Enabled = false c.DistributedTracer.Enabled = true - c.DistributedTracer.ReservoirLimit = 2000 + c.DistributedTracer.ReservoirLimit = defaultMaxSpanEvents c.SpanEvents.Enabled = true c.SpanEvents.Attributes.Enabled = true diff --git a/v3/newrelic/harvest.go b/v3/newrelic/harvest.go index 71874b463..b92865d4f 100644 --- a/v3/newrelic/harvest.go +++ b/v3/newrelic/harvest.go @@ -324,7 +324,7 @@ var ( dfltHarvestCfgr = harvestConfig{ ReportPeriods: map[harvestTypes]time.Duration{harvestTypesAll: fixedHarvestPeriod}, MaxTxnEvents: internal.MaxTxnEvents, - MaxSpanEvents: maxSpanEvents, + MaxSpanEvents: defaultMaxSpanEvents, MaxCustomEvents: internal.MaxCustomEvents, MaxErrorEvents: internal.MaxErrorEvents, } diff --git a/v3/newrelic/limits.go b/v3/newrelic/limits.go index 67ee68648..5d3200200 100644 --- a/v3/newrelic/limits.go +++ b/v3/newrelic/limits.go @@ -39,7 +39,9 @@ const ( // maxSpanEvents is the maximum number of Span Events that can be captured // per 60-second harvest cycle // XXX DEPRECATED: replaced with DistributedTracer.ReservoirLimit configuration value - maxSpanEvents = 1000 + // This constant is the default we start that value as, but it can be changed at runtime. + // always find the dynamic value, e.g. run.MaxSpanEvents(), instead of this value. + defaultMaxSpanEvents = 2000 // attributes attributeKeyLengthLimit = 255 From fdab64dd91f9d31b96688cd4a5e54aab06e2808e Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 12 May 2022 11:11:19 -0700 Subject: [PATCH 20/30] updates to several integration examples --- v3/examples/client/main.go | 15 +++---- v3/examples/server/main.go | 6 +-- .../nrelasticsearch-v7/example/main.go | 2 +- v3/integrations/nrgraphqlgo/example/main.go | 2 +- .../nrgrpc/example/client/client.go | 20 ++++------ .../nrgrpc/example/server/server.go | 6 +-- v3/integrations/nrredis-v8/example/main.go | 40 ++++++++++++++----- v3/integrations/nrsqlite3/example/main.go | 29 ++++++++++---- 8 files changed, 74 insertions(+), 46 deletions(-) diff --git a/v3/examples/client/main.go b/v3/examples/client/main.go index 5c194ef88..df76b2383 100644 --- a/v3/examples/client/main.go +++ b/v3/examples/client/main.go @@ -1,6 +1,6 @@ // Copyright 2020 New Relic Corporation. All rights reserved. // SPDX-License-Identifier: Apache-2.0 - +// package main import ( @@ -14,14 +14,14 @@ import ( func doRequest(txn *newrelic.Transaction) error { req, err := http.NewRequest("GET", "http://localhost:8000/segments", nil) - if nil != err { + if err != nil { return err } client := &http.Client{} seg := newrelic.StartExternalSegment(txn, req) defer seg.End() resp, err := client.Do(req) - if nil != err { + if err != nil { return err } fmt.Println("response code is", resp.StatusCode) @@ -35,19 +35,14 @@ func main() { newrelic.ConfigDebugLogger(os.Stdout), newrelic.ConfigDistributedTracerEnabled(true), ) - if nil != err { + if err != nil { fmt.Println(err) os.Exit(1) } - // Wait for the application to connect. - if err = app.WaitForConnection(5 * time.Second); nil != err { - fmt.Println(err) - } - txn := app.StartTransaction("client-txn") err = doRequest(txn) - if nil != err { + if err != nil { txn.NoticeError(err) } txn.End() diff --git a/v3/examples/server/main.go b/v3/examples/server/main.go index 16e6c0458..af1496e34 100644 --- a/v3/examples/server/main.go +++ b/v3/examples/server/main.go @@ -168,7 +168,7 @@ func external(w http.ResponseWriter, r *http.Request) { resp, err := http.DefaultClient.Do(req) es.End() - if nil != err { + if err != nil { io.WriteString(w, err.Error()) return } @@ -199,7 +199,7 @@ func roundtripper(w http.ResponseWriter, r *http.Request) { // request = newrelic.RequestWithTransactionContext(request, txn) resp, err := client.Do(request) - if nil != err { + if err != nil { io.WriteString(w, err.Error()) return } @@ -252,7 +252,7 @@ func main() { newrelic.ConfigFromEnvironment(), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { + if err != nil { fmt.Println(err) os.Exit(1) } diff --git a/v3/integrations/nrelasticsearch-v7/example/main.go b/v3/integrations/nrelasticsearch-v7/example/main.go index 59d81d08f..9100cfd70 100644 --- a/v3/integrations/nrelasticsearch-v7/example/main.go +++ b/v3/integrations/nrelasticsearch-v7/example/main.go @@ -27,7 +27,7 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { + if err != nil { panic(err) } app.WaitForConnection(5 * time.Second) diff --git a/v3/integrations/nrgraphqlgo/example/main.go b/v3/integrations/nrgraphqlgo/example/main.go index 2c11d0e45..b15a73537 100644 --- a/v3/integrations/nrgraphqlgo/example/main.go +++ b/v3/integrations/nrgraphqlgo/example/main.go @@ -61,7 +61,7 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { + if err != nil { fmt.Println(err) os.Exit(1) } diff --git a/v3/integrations/nrgrpc/example/client/client.go b/v3/integrations/nrgrpc/example/client/client.go index 7406e605e..66fdf5b11 100644 --- a/v3/integrations/nrgrpc/example/client/client.go +++ b/v3/integrations/nrgrpc/example/client/client.go @@ -18,7 +18,7 @@ import ( func doUnaryUnary(ctx context.Context, client sampleapp.SampleApplicationClient) { msg, err := client.DoUnaryUnary(ctx, &sampleapp.Message{Text: "Hello DoUnaryUnary"}) - if nil != err { + if err != nil { panic(err) } fmt.Println(msg.Text) @@ -26,7 +26,7 @@ func doUnaryUnary(ctx context.Context, client sampleapp.SampleApplicationClient) func doUnaryStream(ctx context.Context, client sampleapp.SampleApplicationClient) { stream, err := client.DoUnaryStream(ctx, &sampleapp.Message{Text: "Hello DoUnaryStream"}) - if nil != err { + if err != nil { panic(err) } for { @@ -34,7 +34,7 @@ func doUnaryStream(ctx context.Context, client sampleapp.SampleApplicationClient if err == io.EOF { break } - if nil != err { + if err != nil { panic(err) } fmt.Println(msg.Text) @@ -43,11 +43,11 @@ func doUnaryStream(ctx context.Context, client sampleapp.SampleApplicationClient func doStreamUnary(ctx context.Context, client sampleapp.SampleApplicationClient) { stream, err := client.DoStreamUnary(ctx) - if nil != err { + if err != nil { panic(err) } for i := 0; i < 3; i++ { - if err := stream.Send(&sampleapp.Message{Text: "Hello DoStreamUnary"}); nil != err { + if err := stream.Send(&sampleapp.Message{Text: "Hello DoStreamUnary"}); err != nil { if err == io.EOF { break } @@ -55,7 +55,7 @@ func doStreamUnary(ctx context.Context, client sampleapp.SampleApplicationClient } } msg, err := stream.CloseAndRecv() - if nil != err { + if err != nil { panic(err) } fmt.Println(msg.Text) @@ -63,7 +63,7 @@ func doStreamUnary(ctx context.Context, client sampleapp.SampleApplicationClient func doStreamStream(ctx context.Context, client sampleapp.SampleApplicationClient) { stream, err := client.DoStreamStream(ctx) - if nil != err { + if err != nil { panic(err) } waitc := make(chan struct{}) @@ -95,11 +95,7 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { - panic(err) - } - err = app.WaitForConnection(10 * time.Second) - if nil != err { + if err != nil { panic(err) } defer app.Shutdown(10 * time.Second) diff --git a/v3/integrations/nrgrpc/example/server/server.go b/v3/integrations/nrgrpc/example/server/server.go index 469f3c80d..b521ae61e 100644 --- a/v3/integrations/nrgrpc/example/server/server.go +++ b/v3/integrations/nrgrpc/example/server/server.go @@ -12,7 +12,7 @@ import ( "github.com/newrelic/go-agent/v3/integrations/nrgrpc" sampleapp "github.com/newrelic/go-agent/v3/integrations/nrgrpc/example/sampleapp" - newrelic "github.com/newrelic/go-agent/v3/newrelic" + "github.com/newrelic/go-agent/v3/newrelic" "google.golang.org/grpc" ) @@ -77,7 +77,7 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { + if err != nil { panic(err) } @@ -86,10 +86,10 @@ func main() { panic(err) } grpcServer := grpc.NewServer( - // Add the New Relic gRPC server instrumentation grpc.UnaryInterceptor(nrgrpc.UnaryServerInterceptor(app)), grpc.StreamInterceptor(nrgrpc.StreamServerInterceptor(app)), ) sampleapp.RegisterSampleApplicationServer(grpcServer, &Server{}) grpcServer.Serve(lis) + } diff --git a/v3/integrations/nrredis-v8/example/main.go b/v3/integrations/nrredis-v8/example/main.go index adfe597af..2d29adcc8 100644 --- a/v3/integrations/nrredis-v8/example/main.go +++ b/v3/integrations/nrredis-v8/example/main.go @@ -4,9 +4,12 @@ package main import ( + "bufio" "context" "fmt" "os" + "strconv" + "strings" "time" redis "github.com/go-redis/redis/v8" @@ -20,10 +23,10 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { + if err != nil { panic(err) } - app.WaitForConnection(10 * time.Second) + txn := app.StartTransaction("ping txn") opts := &redis.Options{ @@ -31,15 +34,8 @@ func main() { } client := redis.NewClient(opts) - // - // Step 1: Add a nrredis.NewHook() to your redis client. - // client.AddHook(nrredis.NewHook(opts)) - // - // Step 2: Ensure that all client calls contain a context which includes - // the transaction. - // ctx := newrelic.NewContext(context.Background(), txn) pipe := client.WithContext(ctx).Pipeline() incr := pipe.Incr(ctx, "pipeline_counter") @@ -47,6 +43,32 @@ func main() { _, err = pipe.Exec(ctx) fmt.Println(incr.Val(), err) + result, err := client.Do(ctx, "INFO", "STATS").Result() + if err != nil { + panic(err) + } + hits := 0 + misses := 0 + if stats, ok := result.(string); ok { + sc := bufio.NewScanner(strings.NewReader(stats)) + for sc.Scan() { + fields := strings.Split(sc.Text(), ":") + if len(fields) == 2 { + if v, err := strconv.Atoi(fields[1]); err == nil { + switch fields[0] { + case "keyspace_hits": + hits = v + case "keyspace_misses": + misses = v + } + } + } + } + } + if hits+misses > 0 { + app.RecordCustomMetric("Custom/RedisCache/HitRatio", float64(hits)/(float64(hits+misses))) + } + txn.End() app.Shutdown(5 * time.Second) } diff --git a/v3/integrations/nrsqlite3/example/main.go b/v3/integrations/nrsqlite3/example/main.go index b0e710e15..9d1e1c0d1 100644 --- a/v3/integrations/nrsqlite3/example/main.go +++ b/v3/integrations/nrsqlite3/example/main.go @@ -19,6 +19,7 @@ func main() { if err != nil { panic(err) } + defer db.Close() db.Exec("CREATE TABLE zaps ( zap_num INTEGER )") @@ -29,19 +30,33 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) - if nil != err { - panic(err) - } - app.WaitForConnection(5 * time.Second) - txn := app.StartTransaction("sqliteQuery") + txn := app.StartTransaction("sqliteQuery") ctx := newrelic.NewContext(context.Background(), txn) row := db.QueryRowContext(ctx, "SELECT count(*) from zaps") var count int row.Scan(&count) + txn.End() + txn = app.StartTransaction("CustomSQLQuery") + s := newrelic.DatastoreSegment{ + Product: newrelic.DatastoreMySQL, + Collection: "users", + Operation: "INSERT", + ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", + QueryParameters: map[string]interface{}{ + "name": "Dracula", + "age": 439, + }, + Host: "mysql-server-1", + PortPathOrID: "3306", + DatabaseName: "my_database", + } + s.StartTime = txn.StartSegmentNow() + // ... do the operation + s.End() txn.End() - app.Shutdown(5 * time.Second) - fmt.Println("number of entries in table", count) + app.Shutdown(5 * time.Second) + fmt.Printf("number of elements in table: %v\n", count) } From f6ab4946e8f5c872ecda22fefd42b7a284b355b1 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Wed, 18 May 2022 13:25:28 -0700 Subject: [PATCH 21/30] checkpoint --- v3/newrelic/app_run.go | 21 ++++-------------- v3/newrelic/config_options.go | 5 +++-- v3/newrelic/limits.go | 2 +- v3/newrelic/tracing.go | 42 +++++++++++++++++------------------ 4 files changed, 29 insertions(+), 41 deletions(-) diff --git a/v3/newrelic/app_run.go b/v3/newrelic/app_run.go index 6aa7f12f5..3df42ea55 100644 --- a/v3/newrelic/app_run.go +++ b/v3/newrelic/app_run.go @@ -109,7 +109,7 @@ func newAppRun(config config, reply *internal.ConnectReply) *appRun { reply.SamplingTarget, time.Now()) - if "" != run.Reply.RunID { + if run.Reply.RunID != "" { js, _ := json.Marshal(settings(run.Config.Config)) run.Config.Logger.Debug("final configuration", map[string]interface{}{ "config": jsonString(js), @@ -148,13 +148,13 @@ func newServerlessConnectReply(config config) *internal.ConnectReply { reply.TrustedAccountKey = config.ServerlessMode.TrustedAccountKey reply.PrimaryAppID = config.ServerlessMode.PrimaryAppID - if "" == reply.TrustedAccountKey { + if reply.TrustedAccountKey == "" { // The trust key does not need to be provided by customers whose // account ID is the same as the trust key. reply.TrustedAccountKey = reply.AccountID } - if "" == reply.PrimaryAppID { + if reply.PrimaryAppID == "" { reply.PrimaryAppID = serverlessDefaultPrimaryAppID } @@ -202,20 +202,7 @@ func (run *appRun) MaxErrorEvents() int { // which will be the default or the user's configured size (if any), but // may be capped to the maximum allowed by the collector. func (run *appRun) MaxSpanEvents() int { - return run.maxLimit(run.Config.DistributedTracer.ReservoirLimit, run.ptrSpanEvents) -} - -// maxLimit is like limit, but rather than always allowing the collector's -// value to override the default, we will let the collector specify the maximum -// value, allowing the default to be less than that amount. -func (run *appRun) maxLimit(dflt int, field func() *uint) int { - if field() != nil { - maxAllowed := int(*field()) - if maxAllowed < dflt { - return maxAllowed - } - } - return dflt + return run.limit(run.Config.DistributedTracer.ReservoirLimit, run.ptrSpanEvents) } func (run *appRun) limit(dflt int, field func() *uint) int { diff --git a/v3/newrelic/config_options.go b/v3/newrelic/config_options.go index 4b935ebb7..3ba323924 100644 --- a/v3/newrelic/config_options.go +++ b/v3/newrelic/config_options.go @@ -36,8 +36,9 @@ func ConfigDistributedTracerEnabled(enabled bool) ConfigOption { return func(cfg *Config) { cfg.DistributedTracer.Enabled = enabled } } -// ConfigDistributedTracerReservoirLimit alters the sample reservoir size to be -// used for distributed tracing instead of using the built-in default. +// ConfigDistributedTracerReservoirLimit alters the sample reservoir size (maximum +// number of span events to be collected) for distributed tracing instead of +// using the built-in default. // Alters the DistributedTracer.ReservoirLimit setting. func ConfigDistributedTracerReservoirLimit(limit int) ConfigOption { return func(cfg *Config) { cfg.DistributedTracer.ReservoirLimit = limit } diff --git a/v3/newrelic/limits.go b/v3/newrelic/limits.go index 5d3200200..372ea8c53 100644 --- a/v3/newrelic/limits.go +++ b/v3/newrelic/limits.go @@ -38,7 +38,7 @@ const ( maxHarvestSlowSQLs = 10 // maxSpanEvents is the maximum number of Span Events that can be captured // per 60-second harvest cycle - // XXX DEPRECATED: replaced with DistributedTracer.ReservoirLimit configuration value + // DEPRECATED: replaced with DistributedTracer.ReservoirLimit configuration value // This constant is the default we start that value as, but it can be changed at runtime. // always find the dynamic value, e.g. run.MaxSpanEvents(), instead of this value. defaultMaxSpanEvents = 2000 diff --git a/v3/newrelic/tracing.go b/v3/newrelic/tracing.go index 3d4c42ab5..4421abda1 100644 --- a/v3/newrelic/tracing.go +++ b/v3/newrelic/tracing.go @@ -189,7 +189,7 @@ func (b boolJSONWriter) WriteJSON(buf *bytes.Buffer) { type spanAttributeMap map[string]jsonWriter func (m *spanAttributeMap) addString(key string, val string) { - if "" != val { + if val != "" { m.add(key, stringJSONWriter(val)) } } @@ -300,7 +300,7 @@ type segmentEnd struct { } func (end segmentEnd) spanEvent() *spanEvent { - if "" == end.SpanID { + if end.SpanID == "" { return nil } return &spanEvent{ @@ -378,7 +378,7 @@ func startSegment(t *txnData, thread *tracingThread, now time.Time) segmentStart // GetRootSpanID returns the root span ID. func (t *txnData) GetRootSpanID() string { - if "" == t.rootSpanID { + if t.rootSpanID == "" { t.rootSpanID = t.TraceIDGenerator.GenerateSpanID() } return t.rootSpanID @@ -387,10 +387,10 @@ func (t *txnData) GetRootSpanID() string { // CurrentSpanIdentifier returns the identifier of the span at the top of the // segment stack. func (t *txnData) CurrentSpanIdentifier(thread *tracingThread) string { - if 0 == len(thread.stack) { + if len(thread.stack) == 0 { return t.GetRootSpanID() } - if "" == thread.stack[len(thread.stack)-1].spanID { + if thread.stack[len(thread.stack)-1].spanID == "" { thread.stack[len(thread.stack)-1].spanID = t.TraceIDGenerator.GenerateSpanID() } return thread.stack[len(thread.stack)-1].spanID @@ -412,7 +412,7 @@ var ( ) func endSegment(t *txnData, thread *tracingThread, start segmentStartTime, now time.Time) (segmentEnd, error) { - if 0 == start.Stamp { + if start.Stamp == 0 { return segmentEnd{}, errMalformedSegment } if start.Depth >= len(thread.stack) { @@ -453,14 +453,14 @@ func endSegment(t *txnData, thread *tracingThread, start segmentStartTime, now t thread.stack = thread.stack[0:start.Depth] - if fn := t.ShouldCreateSpanGUID; nil != fn && fn() { + if fn := t.ShouldCreateSpanGUID; fn != nil && fn() { s.SpanID = frame.spanID - if "" == s.SpanID { + if s.SpanID == "" { s.SpanID = t.TraceIDGenerator.GenerateSpanID() } } - if fn := t.ShouldCollectSpanEvents; nil != fn && fn() { + if fn := t.ShouldCollectSpanEvents; fn != nil && fn() { // Note that the current span identifier is the parent's // identifier because we've already popped the segment that's // ending off of the stack. @@ -478,7 +478,7 @@ func endSegment(t *txnData, thread *tracingThread, start segmentStartTime, now t // endBasicSegment ends a basic segment. func endBasicSegment(t *txnData, thread *tracingThread, start segmentStartTime, now time.Time, name string) error { end, err := endSegment(t, thread, start, now) - if nil != err { + if err != nil { return err } if nil == t.customSegments { @@ -528,7 +528,7 @@ type endExternalParams struct { func endExternalSegment(p endExternalParams) error { t := p.TxnData end, err := endSegment(t, p.Thread, p.Start, p.Now) - if nil != err { + if err != nil { return err } @@ -573,7 +573,7 @@ func endExternalSegment(p endExternalParams) error { ExternalCrossProcessID: crossProcessID, ExternalTransactionName: transactionName, } - if nil == t.externalSegments { + if t.externalSegments == nil { t.externalSegments = make(map[externalMetricKey]*metricData) } t.externalCallCount++ @@ -634,7 +634,7 @@ type endMessageParams struct { func endMessageSegment(p endMessageParams) error { t := p.TxnData end, err := endSegment(t, p.Thread, p.Start, p.Now) - if nil != err { + if err != nil { return err } @@ -645,7 +645,7 @@ func endMessageSegment(p endMessageParams) error { DestinationTemp: p.DestinationTemp, } - if nil == t.messageSegments { + if t.messageSegments == nil { t.messageSegments = make(map[internal.MessageMetricKey]*metricData) } m := metricDataFromDuration(end.duration, end.exclusive) @@ -712,10 +712,10 @@ func (t txnData) slowQueryWorthy(d time.Duration) bool { } func datastoreSpanAddress(host, portPathOrID string) string { - if "" != host && "" != portPathOrID { + if host != "" && portPathOrID != "" { return host + ":" + portPathOrID } - if "" != host { + if host != "" { return host } return portPathOrID @@ -724,7 +724,7 @@ func datastoreSpanAddress(host, portPathOrID string) string { // endDatastoreSegment ends a datastore segment. func endDatastoreSegment(p endDatastoreParams) error { end, err := endSegment(p.TxnData, p.Thread, p.Start, p.Now) - if nil != err { + if err != nil { return err } if p.Operation == "" { @@ -748,7 +748,7 @@ func endDatastoreSegment(p endDatastoreParams) error { // has value. if p.ParameterizedQuery == "" { collection := p.Collection - if "" == collection { + if collection == "" { collection = "unknown" } p.ParameterizedQuery = fmt.Sprintf(`'%s' on '%s' using '%s'`, @@ -762,7 +762,7 @@ func endDatastoreSegment(p endDatastoreParams) error { Host: p.Host, PortPathOrID: p.PortPathOrID, } - if nil == p.TxnData.datastoreSegments { + if p.TxnData.datastoreSegments == nil { p.TxnData.datastoreSegments = make(map[datastoreMetricKey]*metricData) } p.TxnData.datastoreCallCount++ @@ -846,7 +846,7 @@ func mergeBreakdownMetrics(t *txnData, metrics *metricTable) { hostMetric := externalHostMetric(key) metrics.add(hostMetric, "", *data, unforced) - if "" != key.ExternalCrossProcessID && "" != key.ExternalTransactionName { + if key.ExternalCrossProcessID != "" && key.ExternalTransactionName != "" { txnMetric := externalTransactionMetric(key) // Unscoped CAT metrics @@ -875,7 +875,7 @@ func mergeBreakdownMetrics(t *txnData, metrics *metricTable) { operation := datastoreOperationMetric(key) metrics.add(operation, "", *data, unforced) - if "" != key.Collection { + if key.Collection != "" { statement := datastoreStatementMetric(key) metrics.add(statement, "", *data, unforced) From 24918bf15fe9d49638ad8521258abbe8c2960cd4 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Wed, 18 May 2022 14:39:57 -0700 Subject: [PATCH 22/30] tests passing --- v3/newrelic/harvest_test.go | 4 ++-- v3/newrelic/tracing.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/v3/newrelic/harvest_test.go b/v3/newrelic/harvest_test.go index 90def7011..76317ed4d 100644 --- a/v3/newrelic/harvest_test.go +++ b/v3/newrelic/harvest_test.go @@ -136,7 +136,7 @@ func TestCreateFinalMetrics(t *testing.T) { {Name: "Supportability/EventHarvest/AnalyticEventData/HarvestLimit", Scope: "", Forced: true, Data: []float64{1, 10 * 1000, 10 * 1000, 10 * 1000, 10 * 1000, 10 * 1000 * 10 * 1000}}, {Name: "Supportability/EventHarvest/CustomEventData/HarvestLimit", Scope: "", Forced: true, Data: []float64{1, 10 * 1000, 10 * 1000, 10 * 1000, 10 * 1000, 10 * 1000 * 10 * 1000}}, {Name: "Supportability/EventHarvest/ErrorEventData/HarvestLimit", Scope: "", Forced: true, Data: []float64{1, 100, 100, 100, 100, 100 * 100}}, - {Name: "Supportability/EventHarvest/SpanEventData/HarvestLimit", Scope: "", Forced: true, Data: []float64{1, 1000, 1000, 1000, 1000, 1000 * 1000}}, + {Name: "Supportability/EventHarvest/SpanEventData/HarvestLimit", Scope: "", Forced: true, Data: []float64{1, 2000, 2000, 2000, 2000, 2000 * 2000}}, {Name: "Supportability/Go/Version/" + Version, Scope: "", Forced: true, Data: []float64{1, 0, 0, 0, 0, 0}}, {Name: "Supportability/Go/Runtime/Version/" + goVersionSimple, Scope: "", Forced: true, Data: []float64{1, 0, 0, 0, 0, 0}}, {Name: "Supportability/Go/gRPC/Version/" + grpcVersion, Scope: "", Forced: true, Data: []float64{1, 0, 0, 0, 0, 0}}, @@ -829,7 +829,7 @@ func TestNewHarvestSetsDefaultValues(t *testing.T) { if cp := h.ErrorEvents.capacity(); cp != internal.MaxErrorEvents { t.Error("wrong error event capacity", cp) } - if cp := h.SpanEvents.capacity(); cp != maxSpanEvents { + if cp := h.SpanEvents.capacity(); cp != defaultMaxSpanEvents { t.Error("wrong span event capacity", cp) } } diff --git a/v3/newrelic/tracing.go b/v3/newrelic/tracing.go index 4421abda1..ee8db4983 100644 --- a/v3/newrelic/tracing.go +++ b/v3/newrelic/tracing.go @@ -398,7 +398,7 @@ func (t *txnData) CurrentSpanIdentifier(thread *tracingThread) string { func (t *txnData) saveSpanEvent(e *spanEvent) { e.AgentAttributes = t.Attrs.filterSpanAttributes(e.AgentAttributes, destSpan) - if len(t.SpanEvents) < maxSpanEvents { + if len(t.SpanEvents) < defaultMaxSpanEvents { t.SpanEvents = append(t.SpanEvents, e) } } From bb325e0a1fd2ba372834fca902c96fadbd252aa2 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 12:20:08 -0700 Subject: [PATCH 23/30] corrected collector negotiation for DT reservoir size --- v3/internal/connect_reply.go | 10 ++++++++++ v3/newrelic/config.go | 2 +- v3/newrelic/config_test.go | 6 ++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/v3/internal/connect_reply.go b/v3/internal/connect_reply.go index 2e5f86379..84b5d00b6 100644 --- a/v3/internal/connect_reply.go +++ b/v3/internal/connect_reply.go @@ -145,6 +145,16 @@ func DefaultEventHarvestConfig(maxTxnEvents int) EventHarvestConfig { return cfg } +// DefaultEventHarvestConfigWithDT is an extended version of DefaultEventHarvestConfig, +// with the addition that it takes into account distributed tracer span event harvest limits. +func DefaultEventHarvestConfigWithDT(maxTxnEvents int, dtEnabled bool, spanEventLimit int) EventHarvestConfig { + cfg := DefaultEventHarvestConfig(maxTxnEvents) + if dtEnabled { + cfg.Limits.SpanEvents = uintPtr(uint(spanEventLimit)) + } + return cfg +} + // TrustedAccountSet is used for CAT. type TrustedAccountSet map[int]struct{} diff --git a/v3/newrelic/config.go b/v3/newrelic/config.go index 07535afe1..fe0f7c7f7 100644 --- a/v3/newrelic/config.go +++ b/v3/newrelic/config.go @@ -667,7 +667,7 @@ func configConnectJSONInternal(c Config, pid int, util *utilization.Data, e envi Util: util, SecurityPolicies: securityPolicies, Metadata: metadata, - EventData: internal.DefaultEventHarvestConfig(c.maxTxnEvents()), + EventData: internal.DefaultEventHarvestConfigWithDT(c.maxTxnEvents(), c.DistributedTracer.Enabled, c.DistributedTracer.ReservoirLimit), }}) } diff --git a/v3/newrelic/config_test.go b/v3/newrelic/config_test.go index 4ee6dc8c1..b6df1731b 100644 --- a/v3/newrelic/config_test.go +++ b/v3/newrelic/config_test.go @@ -250,7 +250,8 @@ func TestCopyConfigReferenceFieldsPresent(t *testing.T) { "harvest_limits": { "analytic_event_data": 10000, "custom_event_data": 10000, - "error_event_data": 100 + "error_event_data": 100, + "span_event_data": 2000 } } }]`) @@ -414,7 +415,8 @@ func TestCopyConfigReferenceFieldsAbsent(t *testing.T) { "harvest_limits": { "analytic_event_data": 10000, "custom_event_data": 10000, - "error_event_data": 100 + "error_event_data": 100, + "span_event_data": 2000 } } }]`) From e45b12a5250aadba7a97fe5a5ae14da15145f330 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 13:19:52 -0700 Subject: [PATCH 24/30] updated changelog for 3.16 release --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4c9887e..7c80718f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,19 @@ # ChangeLog +## 3.16.0 +### Added +* Distributed Tracing is now the default mode of operation. It may be disabled by user configuration if so desired. [PR #495](https://github.com/newrelic/go-agent/pull/495) + * To disable DT, add `newrelic.ConfigDistributedTracerEnabled(false)` to your application configuration. + * To change the reservoir limit for how many span events are to be collected per harvest cycle from the default, add `newrelic.ConfigDistributedTracerReservoirLimit(`*newlimit*`)` to your application configuration. + * The reservoir limit's default was increased from 1000 to 2000. +### Fixed +* Corrected some example code to be cleaner. +* Updated version of nats-streaming-server. [PR #458](https://github.com/newrelic/go-agent/pull/458) +* Correction ot nrpkgerrors so that `nrpkgerrors.Wrap` now checks if the error it is passed has attributes, and if it does, copies them into the New Relic error it creates. +This fixes [issue #409](https://github.com/newrelic/go-agent/issues/409) via [PR #441](https://github.com/newrelic/go-agent/pull/441). + +### Support Statement +New Relic recommends that you upgrade the agent regularly to ensure that you’re getting the latest features and performance benefits. Additionally, older releases will no longer be supported when they reach end-of-life. + ## 3.15.2 ### Added * Strings logged via the Go Agent's built-in logger will have strings of the form `license_key=`*hex-string* changed to `license_key=[redacted]` before they are output, regardless of severity level, where *hex-string* means a sequence of upper- or lower-case hexadecimal digits and dots ('.'). This incorporates [PR #415](https://github.com/newrelic/go-agent/pull/415). From 11c5c371dbd49d55e73af919fd4075b282411158 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 13:22:51 -0700 Subject: [PATCH 25/30] updated version.go --- v3/newrelic/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v3/newrelic/version.go b/v3/newrelic/version.go index a7485271d..bc40e2661 100644 --- a/v3/newrelic/version.go +++ b/v3/newrelic/version.go @@ -11,7 +11,7 @@ import ( const ( // Version is the full string version of this Go Agent. - Version = "3.15.2" + Version = "3.16.0" ) var ( From feb7843c19ee124944d1e75163fbadce24c559ae Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 13:29:50 -0700 Subject: [PATCH 26/30] updated nrpkgerrors version --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c80718f2..7d195654c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * Updated version of nats-streaming-server. [PR #458](https://github.com/newrelic/go-agent/pull/458) * Correction ot nrpkgerrors so that `nrpkgerrors.Wrap` now checks if the error it is passed has attributes, and if it does, copies them into the New Relic error it creates. This fixes [issue #409](https://github.com/newrelic/go-agent/issues/409) via [PR #441](https://github.com/newrelic/go-agent/pull/441). + * This increments the `nrpkgerrors` version to v1.1.0. ### Support Statement New Relic recommends that you upgrade the agent regularly to ensure that you’re getting the latest features and performance benefits. Additionally, older releases will no longer be supported when they reach end-of-life. From 88c21acd528bbdd8760935420e66a965c979f708 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 13:53:55 -0700 Subject: [PATCH 27/30] updated changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80ba54ca6..55c7ab21e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ * To disable DT, add `newrelic.ConfigDistributedTracerEnabled(false)` to your application configuration. * To change the reservoir limit for how many span events are to be collected per harvest cycle from the default, add `newrelic.ConfigDistributedTracerReservoirLimit(`*newlimit*`)` to your application configuration. * The reservoir limit's default was increased from 1000 to 2000. + * The maximum reservoir limit supported is 10,000. +* Note that Cross Application Tracing is now deprecated. ### Fixed * Corrected some example code to be cleaner. * Updated version of nats-streaming-server. [PR #458](https://github.com/newrelic/go-agent/pull/458) -* Correction ot nrpkgerrors so that `nrpkgerrors.Wrap` now checks if the error it is passed has attributes, and if it does, copies them into the New Relic error it creates. +* Correction to nrpkgerrors so that `nrpkgerrors.Wrap` now checks if the error it is passed has attributes, and if it does, copies them into the New Relic error it creates. This fixes [issue #409](https://github.com/newrelic/go-agent/issues/409) via [PR #441](https://github.com/newrelic/go-agent/pull/441). * This increments the `nrpkgerrors` version to v1.1.0. From c2426dfde4669f2489e2eb98847b5fb072bafa49 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 14:50:51 -0700 Subject: [PATCH 28/30] updated nrredis example --- v3/integrations/nrredis-v8/example/main.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/v3/integrations/nrredis-v8/example/main.go b/v3/integrations/nrredis-v8/example/main.go index 2d29adcc8..c5e38296e 100644 --- a/v3/integrations/nrredis-v8/example/main.go +++ b/v3/integrations/nrredis-v8/example/main.go @@ -27,6 +27,11 @@ func main() { panic(err) } + // normally, production code wouldn't require the WaitForConnection call, + // but for an extremely short-lived script, we want to be sure we are + // connected before we've already exited. + app.WaitForConnection(10 * time.Second) + txn := app.StartTransaction("ping txn") opts := &redis.Options{ @@ -34,8 +39,15 @@ func main() { } client := redis.NewClient(opts) + // + // Step 1: Add a nrredis.NewHook() to your redis client. + // client.AddHook(nrredis.NewHook(opts)) + // + // Step 2: Ensure that all client calls contain a context which includes + // the transaction. + // ctx := newrelic.NewContext(context.Background(), txn) pipe := client.WithContext(ctx).Pipeline() incr := pipe.Incr(ctx, "pipeline_counter") From a08d833e64d5e591966382a2823820cc8effad6a Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 14:54:05 -0700 Subject: [PATCH 29/30] fixed nrgrpc and nrsqlite3 examples --- v3/integrations/nrgrpc/example/client/client.go | 1 + v3/integrations/nrsqlite3/example/main.go | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/v3/integrations/nrgrpc/example/client/client.go b/v3/integrations/nrgrpc/example/client/client.go index 66fdf5b11..8f7cac0cb 100644 --- a/v3/integrations/nrgrpc/example/client/client.go +++ b/v3/integrations/nrgrpc/example/client/client.go @@ -100,6 +100,7 @@ func main() { } defer app.Shutdown(10 * time.Second) + app.WaitForConnection(10 * time.Second) txn := app.StartTransaction("main") defer txn.End() diff --git a/v3/integrations/nrsqlite3/example/main.go b/v3/integrations/nrsqlite3/example/main.go index 9d1e1c0d1..3463413c2 100644 --- a/v3/integrations/nrsqlite3/example/main.go +++ b/v3/integrations/nrsqlite3/example/main.go @@ -30,7 +30,11 @@ func main() { newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), newrelic.ConfigDebugLogger(os.Stdout), ) + if err != nil { + panic(err) + } + app.WaitForConnection(10 * time.Second) txn := app.StartTransaction("sqliteQuery") ctx := newrelic.NewContext(context.Background(), txn) row := db.QueryRowContext(ctx, "SELECT count(*) from zaps") From f9ca4724536a73702fbf646b74c00900b584c053 Mon Sep 17 00:00:00 2001 From: Steve Willoughby Date: Thu, 19 May 2022 15:21:00 -0700 Subject: [PATCH 30/30] added line to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55c7ab21e..ea427746f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * The reservoir limit's default was increased from 1000 to 2000. * The maximum reservoir limit supported is 10,000. * Note that Cross Application Tracing is now deprecated. +* Added support for gathering memory statistics via `PhysicalMemoryBytes` functions for OpenBSD. + ### Fixed * Corrected some example code to be cleaner. * Updated version of nats-streaming-server. [PR #458](https://github.com/newrelic/go-agent/pull/458)