Skip to content

Commit d083918

Browse files
Merge pull request #326 from newrelic/develop
Merging develop to create v3.13.0
2 parents 5a0eaeb + 11f7414 commit d083918

File tree

14 files changed

+411
-423
lines changed

14 files changed

+411
-423
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,17 @@ jobs:
113113
extratesting: go get -u github.com/sirupsen/logrus@master
114114
- go-version: 1.15.x
115115
dirs: v3/integrations/nrawssdk-v1
116-
extratesting: go get -u github.com/aws/aws-sdk-go@master
116+
extratesting: go get -u github.com/aws/aws-sdk-go@main
117117
- go-version: 1.15.x
118118
dirs: v3/integrations/nrawssdk-v2
119-
extratesting: go get -u github.com/aws/aws-sdk-go-v2@master
119+
extratesting: go get -u github.com/aws/aws-sdk-go-v2@main
120120
- go-version: 1.15.x
121121
dirs: v3/integrations/nrecho-v3
122122
# Test against the latest v3 Echo:
123123
extratesting: go get -u github.com/labstack/echo@v3
124124
- go-version: 1.15.x
125125
dirs: v3/integrations/nrecho-v4
126-
extratesting: go get -u github.com/labstack/echo/v4@master
126+
extratesting: go get -u github.com/labstack/echo@master
127127
- go-version: 1.15.x
128128
dirs: v3/integrations/nrelasticsearch-v7
129129
extratesting: go get -u github.com/elastic/go-elasticsearch/[email protected]

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
## Unreleased
44

5+
## 3.13.0
6+
7+
### Fixed
8+
* Replaced the NR AWS SDK V2 integration for the v3 agent with a new version that works. See the v3/integrations/nrawssdk-v2/example/main.go file for an example of how to use it. Issues [#250](https://github.com/newrelic/go-agent/issues/250) and [#288](https://github.com/newrelic/go-agent/issues/288) are fixed by this PR. [#309](https://github.com/newrelic/go-agent/pull/309)
9+
10+
* Fixes issue [#221](https://github.com/newrelic/go-agent/issues/221): grpc errors reported in code watched by `UnaryServerInterceptor()` or `StreamServerInterceptor()` now create error events which are reported to the UI with the error message string included. [#317](https://github.com/newrelic/go-agent/pull/317)
11+
12+
* Fixes documentation in `GUIDE.md` for `txn.StartExternalSegment()` to reflect the v3 usage. Thanks to @abeltay for calling this to our attention and submitting PR [#320](https://github.com/newrelic/go-agent/pull/320).
13+
14+
### Changes
15+
* The v3/examples/server/main.go example now uses `newrelic.ConfigFromEnvironment()`, rather than explicitly pulling in the license key with `newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY"))`. The team is starting to use this as a general systems integration testing script, and this facilitates testing with different settings enabled.
16+
17+
### Support Statement
18+
* 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](https://docs.newrelic.com/docs/using-new-relic/cross-product-functions/install-configure/notification-changes-new-relic-saas-features-distributed-software).
19+
520
## 3.12.0
621

722
### Changes

GUIDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,8 @@ ways to use this functionality:
369369
For example:
370370

371371
```go
372-
func external(txn newrelic.Transaction, req *http.Request) (*http.Response, error) {
373-
s := txn.StartExternalSegment(req)
372+
func external(txn *newrelic.Transaction, req *http.Request) (*http.Response, error) {
373+
s := newrelic.StartExternalSegment(txn, req)
374374
response, err := http.DefaultClient.Do(req)
375375
s.Response = response
376376
s.End()

build-script.sh

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ for dir in $DIRS; do
3838
else
3939
# Only v3 code version 1.9+ needs GRPC dependencies
4040
VERSION=$(go version)
41-
V17="1.7"
42-
V18="1.8"
43-
V19="1.9"
44-
if [[ "$VERSION" =~ .*"$V17".* || "$VERSION" =~ .*"$V18".* ]]; then
41+
V1_7="1.7"
42+
V1_8="1.8"
43+
V1_9="1.9"
44+
V1_10="1.10"
45+
V1_11="1.11"
46+
V1_12="1.12"
47+
if [[ "$VERSION" =~ .*"$V1_7".* || "$VERSION" =~ .*"$V1_8".* ]]; then
4548
echo "Not installing GRPC for old versions"
46-
elif [[ "$VERSION" =~ .*"$V19" ]]; then
49+
elif [[ "$VERSION" =~ .*"$V1_9" || "$VERSION" =~ .*"$V1_10" || "$VERSION" =~ .*"$V1_11" || "$VERSION" =~ .*"$V1_12" ]]; then
4750
# install v3 dependencies that support this go version
4851
set +e
4952
go get -u google.golang.org/grpc # this go get will fail to build
@@ -52,6 +55,13 @@ for dir in $DIRS; do
5255
git checkout v1.31.0
5356
cd -
5457

58+
set +e
59+
go get -u golang.org/x/net/http2 # this go get will fail to build
60+
set -e
61+
cd $GOPATH/src/golang.org/x/net/http2
62+
git checkout 7fd8e65b642006927f6cec5cb4241df7f98a2210
63+
cd -
64+
5565
go get -u github.com/golang/protobuf/protoc-gen-go
5666
else
5767
go get -u github.com/golang/protobuf/protoc-gen-go

v3/examples/server/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ func browser(w http.ResponseWriter, r *http.Request) {
249249
func main() {
250250
app, err := newrelic.NewApplication(
251251
newrelic.ConfigAppName("Example App"),
252-
newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")),
252+
newrelic.ConfigFromEnvironment(),
253253
newrelic.ConfigDebugLogger(os.Stdout),
254254
)
255255
if nil != err {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"os"
8+
"time"
9+
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
"github.com/aws/aws-sdk-go-v2/config"
12+
"github.com/aws/aws-sdk-go-v2/service/s3"
13+
nraws "github.com/newrelic/go-agent/v3/integrations/nrawssdk-v2"
14+
"github.com/newrelic/go-agent/v3/newrelic"
15+
)
16+
17+
func main() {
18+
19+
// Create a New Relic application. This will look for your license key in an
20+
// environment varluable called NEW_RELIC_LICENSE_KEY. This example turns on
21+
// Distributed Tracing, but that's not required.
22+
app, err := newrelic.NewApplication(
23+
newrelic.ConfigFromEnvironment(),
24+
newrelic.ConfigAppName("Example App"),
25+
newrelic.ConfigInfoLogger(os.Stdout),
26+
newrelic.ConfigDistributedTracerEnabled(true),
27+
)
28+
if nil != err {
29+
fmt.Println(err)
30+
os.Exit(1)
31+
}
32+
33+
// For demo purposes only. Don't use the app.WaitForConnection call in
34+
// production unless this is a very short-lived process and the caller
35+
// doesn't block or exit if there's an error.
36+
app.WaitForConnection(5 * time.Second)
37+
38+
// Start recording a New Relic transaction
39+
txn := app.StartTransaction("My sample transaction")
40+
41+
ctx := context.Background()
42+
awsConfig, err := config.LoadDefaultConfig(ctx)
43+
if err != nil {
44+
log.Fatal(err)
45+
}
46+
47+
// Instrument all new AWS clients with New Relic
48+
nraws.AppendMiddlewares(&awsConfig.APIOptions, txn)
49+
50+
s3Client := s3.NewFromConfig(awsConfig)
51+
output, err := s3Client.ListBuckets(ctx, nil)
52+
if err != nil {
53+
log.Fatal(err)
54+
}
55+
56+
for _, object := range output.Buckets {
57+
log.Printf("Bucket name is %s\n", aws.ToString(object.Name))
58+
}
59+
60+
// End the New Relic transaction
61+
txn.End()
62+
63+
// Force all the harvests and shutdown. Like the app.WaitForConnection call
64+
// above, this is for the purposes of this demo only and can be safely
65+
// removed for longer-running processes.
66+
app.Shutdown(10 * time.Second)
67+
}

v3/integrations/nrawssdk-v2/go.mod

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
module github.com/newrelic/go-agent/v3/integrations/nrawssdk-v2
22

3-
// As of Dec 2019, the aws-sdk-go-v2 go.mod file uses 1.12:
3+
// As of May 2021, the aws-sdk-go-v2 go.mod file uses 1.15:
44
// https://github.com/aws/aws-sdk-go-v2/blob/master/go.mod
5-
go 1.12
5+
go 1.15
6+
7+
replace github.com/newrelic/go-agent/v3 => ../../
68

79
require (
8-
// v0.8.0 is the earliest aws-sdk-go-v2 version where
9-
// dynamodb.DescribeTableRequest.Send takes a context.Context parameter.
10-
github.com/aws/aws-sdk-go-v2 v0.8.0
10+
github.com/aws/aws-sdk-go-v2 v1.4.0
11+
github.com/aws/aws-sdk-go-v2/config v1.1.7
12+
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.2.3
13+
github.com/aws/aws-sdk-go-v2/service/lambda v1.2.3
14+
github.com/aws/aws-sdk-go-v2/service/s3 v1.6.0
15+
github.com/aws/smithy-go v1.4.0
1116
github.com/newrelic/go-agent/v3 v3.0.0
17+
golang.org/x/tools v0.1.0 // indirect
1218
)
Lines changed: 110 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,124 @@
1-
// Copyright 2020 New Relic Corporation. All rights reserved.
2-
// SPDX-License-Identifier: Apache-2.0
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
314

4-
// Package nrawssdk instruments https://github.com/aws/aws-sdk-go-v2 requests.
15+
// Package nrawssdk instruments requests made by the
16+
// https://github.com/aws/aws-sdk-go-v2 library.
17+
//
18+
// For most operations, external segments and spans are automatically created
19+
// for display in the New Relic UI on the External services section. For
20+
// DynamoDB operations, datastore segements and spans are created and will be
21+
// displayed on the Databases page. All operations will also be displayed on
22+
// transaction traces and distributed traces.
23+
//
24+
// To use this integration, simply apply the AppendMiddlewares fuction to the apiOptions in
25+
// your AWS Config object before performing any AWS operations. See
26+
// example/main.go for a working sample.
527
package nrawssdk
628

729
import (
8-
"github.com/aws/aws-sdk-go-v2/aws"
9-
"github.com/newrelic/go-agent/v3/internal"
10-
"github.com/newrelic/go-agent/v3/internal/awssupport"
11-
)
30+
"context"
31+
"strconv"
1232

13-
func init() { internal.TrackUsage("integration", "library", "aws-sdk-go-v2") }
33+
awsmiddle "github.com/aws/aws-sdk-go-v2/aws/middleware"
34+
smithymiddle "github.com/aws/smithy-go/middleware"
35+
smithyhttp "github.com/aws/smithy-go/transport/http"
36+
"github.com/newrelic/go-agent/v3/internal/integrationsupport"
37+
"github.com/newrelic/go-agent/v3/newrelic"
38+
)
1439

15-
func startSegment(req *aws.Request) {
16-
input := awssupport.StartSegmentInputs{
17-
HTTPRequest: req.HTTPRequest,
18-
ServiceName: req.Metadata.ServiceName,
19-
Operation: req.Operation.Name,
20-
Region: req.Metadata.SigningRegion,
21-
Params: req.Params,
22-
}
23-
req.HTTPRequest = awssupport.StartSegment(input)
40+
type nrMiddleware struct {
41+
txn *newrelic.Transaction
2442
}
2543

26-
func endSegment(req *aws.Request) {
27-
ctx := req.HTTPRequest.Context()
28-
awssupport.EndSegment(ctx, req.HTTPResponse.Header)
44+
type endable interface{ End() }
45+
46+
// See https://aws.github.io/aws-sdk-go-v2/docs/middleware/ for a description of
47+
// AWS SDK V2 middleware.
48+
func (m nrMiddleware) deserializeMiddleware(stack *smithymiddle.Stack) error {
49+
return stack.Deserialize.Add(smithymiddle.DeserializeMiddlewareFunc("NRDeserializeMiddleware", func(
50+
ctx context.Context, in smithymiddle.DeserializeInput, next smithymiddle.DeserializeHandler) (
51+
out smithymiddle.DeserializeOutput, metadata smithymiddle.Metadata, err error) {
52+
53+
smithyRequest := in.Request.(*smithyhttp.Request)
54+
55+
// The actual http.Request is inside the smithyhttp.Request
56+
httpRequest := smithyRequest.Request
57+
serviceName := awsmiddle.GetServiceID(ctx)
58+
operation := awsmiddle.GetOperationName(ctx)
59+
region := awsmiddle.GetRegion(ctx)
60+
61+
var segment endable
62+
// Service name capitalization is different for v1 and v2.
63+
if serviceName == "dynamodb" || serviceName == "DynamoDB" {
64+
segment = &newrelic.DatastoreSegment{
65+
Product: newrelic.DatastoreDynamoDB,
66+
Collection: "", // AWS SDK V2 doesn't expose TableName
67+
Operation: operation,
68+
ParameterizedQuery: "",
69+
QueryParameters: nil,
70+
Host: httpRequest.URL.Host,
71+
PortPathOrID: httpRequest.URL.Port(),
72+
DatabaseName: "",
73+
StartTime: m.txn.StartSegmentNow(),
74+
}
75+
} else {
76+
segment = newrelic.StartExternalSegment(m.txn, httpRequest)
77+
}
78+
79+
// Hand off execution to other middlewares and then perform the request
80+
out, metadata, err = next.HandleDeserialize(ctx, in)
81+
82+
// After the request
83+
response, ok := out.RawResponse.(*smithyhttp.Response)
84+
85+
if ok {
86+
// Set additional span attributes
87+
integrationsupport.AddAgentSpanAttribute(m.txn,
88+
newrelic.AttributeResponseCode, strconv.Itoa(response.StatusCode))
89+
integrationsupport.AddAgentSpanAttribute(m.txn,
90+
newrelic.SpanAttributeAWSOperation, operation)
91+
integrationsupport.AddAgentSpanAttribute(m.txn,
92+
newrelic.SpanAttributeAWSRegion, region)
93+
requestID, ok := awsmiddle.GetRequestIDMetadata(metadata)
94+
if ok {
95+
integrationsupport.AddAgentSpanAttribute(m.txn,
96+
newrelic.AttributeAWSRequestID, requestID)
97+
}
98+
}
99+
segment.End()
100+
return out, metadata, err
101+
}),
102+
smithymiddle.Before)
29103
}
30104

31-
// InstrumentHandlers will add instrumentation to the given *aws.Handlers.
32-
//
33-
// A Segment will be created for each out going request. The Transaction must
34-
// be added to the `http.Request`'s Context in order for the segment to be
35-
// recorded. For DynamoDB calls, these segments will be
36-
// `newrelic.DatastoreSegment` type and for all others they will be
37-
// `newrelic.ExternalSegment` type.
38-
//
39-
// Additional attributes will be added to Transaction Trace Segments and Span
40-
// Events: aws.region, aws.requestId, and aws.operation.
41-
//
42-
// To add instrumentation to a Config and see segments created for each
43-
// invocation that uses that Config, call InstrumentHandlers with the config's
44-
// Handlers and add the current Transaction to the `http.Request`'s Context:
45-
//
46-
// cfg, _ := external.LoadDefaultAWSConfig()
47-
// cfg.Region = "us-west-2"
48-
// // Add instrumentation to handlers
49-
// nrawssdk.InstrumentHandlers(&cfg.Handlers)
50-
// lambdaClient = lambda.New(cfg)
105+
// AppendMiddlewares inserts New Relic middleware in the given `apiOptions` for
106+
// the AWS SDK V2 for Go. It must be called only once per AWS configuration.
51107
//
52-
// req := lambdaClient.InvokeRequest(&lambda.InvokeInput{
53-
// ClientContext: aws.String("MyApp"),
54-
// FunctionName: aws.String("Function"),
55-
// InvocationType: lambda.InvocationTypeEvent,
56-
// LogType: lambda.LogTypeTail,
57-
// Payload: []byte("{}"),
58-
// }
59-
// // Add txn to http.Request's context
60-
// ctx := newrelic.NewContext(req.Context(), txn)
61-
// resp, err := req.Send(ctx)
108+
// Additional attributes will be added to transaction trace segments and span
109+
// events: aws.region, aws.requestId, and aws.operation. In addition,
110+
// http.statusCode will be added to span events.
62111
//
63-
// To add instrumentation to a Request and see a segment created just for the
64-
// individual request, call InstrumentHandlers with the `aws.Request`'s
65-
// Handlers and add the current Transaction to the `http.Request`'s Context:
112+
// To see segments and spans for each AWS invocation, call AppendMiddlewares
113+
// with the AWS Config `apiOptions` and pass in your current New Relic
114+
// transaction. For example:
66115
//
67-
// req := lambdaClient.InvokeRequest(&lambda.InvokeInput{
68-
// ClientContext: aws.String("MyApp"),
69-
// FunctionName: aws.String("Function"),
70-
// InvocationType: lambda.InvocationTypeEvent,
71-
// LogType: lambda.LogTypeTail,
72-
// Payload: []byte("{}"),
73-
// }
74-
// // Add instrumentation to handlers
75-
// nrawssdk.InstrumentHandlers(&req.Handlers)
76-
// // Add txn to http.Request's context
77-
// ctx := newrelic.NewContext(req.Context(), txn)
78-
// resp, err := req.Send(ctx)
79-
func InstrumentHandlers(handlers *aws.Handlers) {
80-
handlers.Send.SetFrontNamed(aws.NamedHandler{
81-
Name: "StartNewRelicSegment",
82-
Fn: startSegment,
83-
})
84-
handlers.Send.SetBackNamed(aws.NamedHandler{
85-
Name: "EndNewRelicSegment",
86-
Fn: endSegment,
87-
})
116+
// awsConfig, err := config.LoadDefaultConfig(ctx)
117+
// if err != nil {
118+
// log.Fatal(err)
119+
// }
120+
// nraws.AppendMiddlewares(ctx, &awsConfig.APIOptions, txn)
121+
func AppendMiddlewares(apiOptions *[]func(*smithymiddle.Stack) error, txn *newrelic.Transaction) {
122+
m := nrMiddleware{txn: txn}
123+
*apiOptions = append(*apiOptions, m.deserializeMiddleware)
88124
}

0 commit comments

Comments
 (0)