Skip to content

Commit 0e521dc

Browse files
iamemiliodependabot[bot]aayush-apmirackaranr-swilloughby
authored
Release 3.28.0 (#818)
* Error Expected Bug The attribute error.expected should be a boolean, not a string. It is also good practice to use a constant value for the key. * Bump google.golang.org/grpc from 1.54.0 to 1.56.3 in /v3/integrations/nrgraphqlgo/example (#811) --------- * Bump google.golang.org/grpc in /v3/integrations/nrgraphqlgo/example Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.54.0 to 1.56.3. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](grpc/grpc-go@v1.54.0...v1.56.3) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> --------- * Bump google.golang.org/grpc from 1.54.0 to 1.56.3 in /v3/integrations/nrgrpc (#810) --------- * Bump google.golang.org/grpc in /v3/integrations/nrgrpc Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.54.0 to 1.56.3. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](grpc/grpc-go@v1.54.0...v1.56.3) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production ... Signed-off-by: dependabot[bot] <[email protected]> --------- * Bump google.golang.org/grpc from 1.54.0 to 1.56.3 in /v3 (#809) --------- * Bump google.golang.org/grpc from 1.54.0 to 1.56.3 in /v3 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.54.0 to 1.56.3. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](grpc/grpc-go@v1.54.0...v1.56.3) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production ... Signed-off-by: dependabot[bot] <[email protected]> --------- * Bump golang.org/x/net from 0.8.0 to 0.17.0 in /v3/integrations/nrgraphqlgo/example (#804) --------- * Bump golang.org/x/net in /v3/integrations/nrgraphqlgo/example Bumps [golang.org/x/net](https://github.com/golang/net) from 0.8.0 to 0.17.0. - [Commits](golang/net@v0.8.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> --------- * Fix for out of memory error with request body (#806) * Release 3.25.0 (#782) * minor fix for complete security disable flag * Create FastHTTP Client Functions * FastHTTP Request Integration * FastHTTP example file * FastHTTP Request Integration * FastHTTP Response file * mod file * update security agent version * supportability metric * Created unit tests and removed extraneous file * Moved FastHTTP to internal instrumentation * Added testing for errors * chore: add logs-in-context example with logrus * chore: move example to specific folder * FastHTTP external segments/Client example * License for Server Example * Added test for external segment/minor fixes * FastHTTP Integration (#774) Added Support For FastHTTP * V3.25.0 Changelog (#781) * V3.25.0 * update version * corrected changelog for 3.25 release * Fixed test not passing * Update segments.go Removed extra function --------- Co-authored-by: aayush-ap <[email protected]> Co-authored-by: Steve Willoughby <[email protected]> Co-authored-by: Julien Erard <[email protected]> Co-authored-by: Emilio Garcia <[email protected]> Co-authored-by: Steve Willoughby <[email protected]> * fix out of memory issue for req body * Added new config parameter for read request body * update request body buffer * minor fix for dataTruncated * Update readme file * Update csec-go-agent version * Added new wrapper for go-micro stream server * minor fix for GHA * Fix for cpu overhead * backward compatibility * update agent version * minor fix --------- Co-authored-by: Mirac Kara <[email protected]> Co-authored-by: Steve Willoughby <[email protected]> Co-authored-by: Julien Erard <[email protected]> Co-authored-by: Emilio Garcia <[email protected]> Co-authored-by: Steve Willoughby <[email protected]> * move fasthttp out of core library, and into integration package (#808) * move fasthttp out of core library, and into integration package * move examples over * add security agent headers to fasthttp object * fix examples and external segment * add fasthttp tests * cleanup of go mods * fix segment collection * add security agent inbound write capture to wrapped handle func * Update go.mod * Update Changelog * update version.go --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: aayush-ap <[email protected]> Co-authored-by: Mirac Kara <[email protected]> Co-authored-by: Steve Willoughby <[email protected]> Co-authored-by: Julien Erard <[email protected]> Co-authored-by: Steve Willoughby <[email protected]> Co-authored-by: mirackara <[email protected]>
1 parent 79d3bfd commit 0e521dc

27 files changed

+532
-244
lines changed

.github/workflows/ci.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727
# v3 integrations
2828
- go-version: 1.19.x
2929
dirs: v3/integrations/nramqp
30+
- go-version: 1.19.x
31+
dirs: v3/integrations/nrfasthttp
3032
- go-version: 1.19.x
3133
dirs: v3/integrations/nrsarama
3234
- go-version: 1.19.x

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## 3.28.0
2+
### Fixed
3+
* Bumped gRPC from 1.54.0 -> 1.56.3 in the following packages /v3/integrations/nrgrpc, /v3/, /v3/integrations/nrgrpc
4+
* Bumped golang.org/x/net from 0.8.0 -> 0.17.0 in package /v3/integrations/nrgraphqlgo
5+
* Fixed issue where nrfasthttp would not properly register security agent headers
6+
* Move fasthttp instrumentation into a new integration package, nrfasthttp
7+
* Fixed issue where usage of io.ReadAll() was causing a memory leak
8+
9+
### Support statement
10+
11+
We use the latest version of the Go language. At minimum, you should be using no version of Go older than what is supported by the Go team themselves.
12+
13+
See the [Go agent EOL Policy](/docs/apm/agents/go-agent/get-started/go-agent-eol-policy) for details about supported versions of the Go agent and third-party components.
14+
15+
116
## 3.27.0
217
### Added
318
* Added Support for getting Container ID's from cgroup v2 docker containers

v3/go.mod

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ go 1.19
44

55
require (
66
github.com/golang/protobuf v1.5.3
7-
github.com/valyala/fasthttp v1.49.0
8-
google.golang.org/grpc v1.54.0
7+
google.golang.org/grpc v1.56.3
98
)
109

1110
retract v3.22.0 // release process error corrected in v3.22.1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module client-example
2+
3+
go 1.19
4+
5+
require (
6+
github.com/newrelic/go-agent/v3 v3.28.0
7+
github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0
8+
github.com/valyala/fasthttp v1.49.0
9+
)
10+
11+
replace github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0 => ../../

v3/examples/client-fasthttp/main.go v3/integrations/nrfasthttp/examples/client-fasthttp/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"time"
99

10+
"github.com/newrelic/go-agent/v3/integrations/nrfasthttp"
1011
newrelic "github.com/newrelic/go-agent/v3/newrelic"
1112
"github.com/valyala/fasthttp"
1213
)
@@ -20,8 +21,7 @@ func doRequest(txn *newrelic.Transaction) error {
2021
req.SetRequestURI("http://localhost:8080/hello")
2122
req.Header.SetMethod("GET")
2223

23-
ctx := &fasthttp.RequestCtx{}
24-
seg := newrelic.StartExternalSegmentFastHTTP(txn, ctx)
24+
seg := nrfasthttp.StartExternalSegment(txn, req)
2525
defer seg.End()
2626

2727
err := fasthttp.Do(req, resp)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module server-example
2+
3+
go 1.19
4+
5+
require (
6+
github.com/newrelic/go-agent/v3 v3.28.0
7+
github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0
8+
github.com/valyala/fasthttp v1.49.0
9+
)
10+
11+
replace github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0 => ../../

v3/examples/server-fasthttp/main.go v3/integrations/nrfasthttp/examples/server-fasthttp/main.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import (
99
"os"
1010
"time"
1111

12-
newrelic "github.com/newrelic/go-agent/v3/newrelic"
12+
"github.com/newrelic/go-agent/v3/integrations/nrfasthttp"
13+
"github.com/newrelic/go-agent/v3/newrelic"
1314

1415
"github.com/valyala/fasthttp"
1516
)
@@ -39,8 +40,8 @@ func main() {
3940
if err := app.WaitForConnection(5 * time.Second); nil != err {
4041
fmt.Println(err)
4142
}
42-
_, helloRoute := newrelic.WrapHandleFuncFastHTTP(app, "/hello", index)
43-
_, errorRoute := newrelic.WrapHandleFuncFastHTTP(app, "/error", noticeError)
43+
_, helloRoute := nrfasthttp.WrapHandleFunc(app, "/hello", index)
44+
_, errorRoute := nrfasthttp.WrapHandleFunc(app, "/error", noticeError)
4445
handler := func(ctx *fasthttp.RequestCtx) {
4546
path := string(ctx.Path())
4647
method := string(ctx.Method())

v3/integrations/nrfasthttp/go.mod

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ module github.com/newrelic/go-agent/v3/integrations/nrfasthttp
33
go 1.19
44

55
require (
6-
github.com/newrelic/go-agent/v3 v3.26.0
7-
github.com/stretchr/testify v1.8.4
8-
github.com/valyala/fasthttp v1.48.0
6+
github.com/newrelic/go-agent/v3 v3.28.0
7+
github.com/valyala/fasthttp v1.49.0
98
)
10-
replace github.com/newrelic/go-agent/v3 => ../..
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package nrfasthttp
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/newrelic/go-agent/v3/newrelic"
7+
"github.com/valyala/fasthttp"
8+
"github.com/valyala/fasthttp/fasthttpadaptor"
9+
)
10+
11+
type fasthttpWrapperResponse struct {
12+
ctx *fasthttp.RequestCtx
13+
}
14+
15+
func (rw fasthttpWrapperResponse) Header() http.Header {
16+
hdrs := http.Header{}
17+
rw.ctx.Request.Header.VisitAll(func(key, value []byte) {
18+
hdrs.Add(string(key), string(value))
19+
})
20+
return hdrs
21+
}
22+
23+
func (rw fasthttpWrapperResponse) Write(b []byte) (int, error) {
24+
return rw.ctx.Write(b)
25+
}
26+
27+
func (rw fasthttpWrapperResponse) WriteHeader(code int) {
28+
rw.ctx.SetStatusCode(code)
29+
}
30+
31+
func (rw fasthttpWrapperResponse) Body() string {
32+
body := rw.ctx.Response.Body()
33+
return string(body)
34+
}
35+
36+
// WrapHandleFunc wrapps a fasthttp handler function for automatic instrumentation
37+
func WrapHandleFunc(app *newrelic.Application, pattern string, handler func(*fasthttp.RequestCtx), options ...newrelic.TraceOption) (string, func(*fasthttp.RequestCtx)) {
38+
// add the wrapped function to the trace options as the source code reference point
39+
// (to the beginning of the option list, so that the user can override this)
40+
41+
p, h := WrapHandle(app, pattern, fasthttp.RequestHandler(handler), options...)
42+
return p, func(ctx *fasthttp.RequestCtx) { h(ctx) }
43+
}
44+
45+
// WrapHandle wraps a fasthttp request handler for automatic instrumentation
46+
func WrapHandle(app *newrelic.Application, pattern string, handler fasthttp.RequestHandler, options ...newrelic.TraceOption) (string, fasthttp.RequestHandler) {
47+
if app == nil {
48+
return pattern, handler
49+
}
50+
51+
// add the wrapped function to the trace options as the source code reference point
52+
// (but only if we know we're collecting CLM for this transaction and the user didn't already
53+
// specify a different code location explicitly).
54+
return pattern, func(ctx *fasthttp.RequestCtx) {
55+
cache := newrelic.NewCachedCodeLocation()
56+
txnOptionList := newrelic.AddCodeLevelMetricsTraceOptions(app, options, cache, handler)
57+
method := string(ctx.Method())
58+
path := string(ctx.Path())
59+
txn := app.StartTransaction(method+" "+path, txnOptionList...)
60+
ctx.SetUserValue("transaction", txn)
61+
defer txn.End()
62+
r := &http.Request{}
63+
fasthttpadaptor.ConvertRequest(ctx, r, true)
64+
resp := fasthttpWrapperResponse{ctx: ctx}
65+
66+
txn.SetWebResponse(resp)
67+
txn.SetWebRequestHTTP(r)
68+
69+
if newrelic.IsSecurityAgentPresent() {
70+
newrelic.GetSecurityAgentInterface().SendEvent("INBOUND_WRITE", resp.Body(), resp.Header())
71+
}
72+
handler(ctx)
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package nrfasthttp
2+
3+
import (
4+
"testing"
5+
6+
"github.com/newrelic/go-agent/v3/internal"
7+
"github.com/newrelic/go-agent/v3/newrelic"
8+
"github.com/valyala/fasthttp"
9+
)
10+
11+
type myError struct{}
12+
13+
func (e myError) Error() string { return "my msg" }
14+
15+
func myErrorHandlerFastHTTP(ctx *fasthttp.RequestCtx) {
16+
ctx.WriteString("noticing an error")
17+
txn := ctx.UserValue("transaction").(*newrelic.Transaction)
18+
txn.NoticeError(myError{})
19+
}
20+
21+
func TestWrapHandleFastHTTPFunc(t *testing.T) {
22+
singleCount := []float64{1, 0, 0, 0, 0, 0, 0}
23+
app := createTestApp(true)
24+
25+
_, wrappedHandler := WrapHandleFunc(app.Application, "/hello", myErrorHandlerFastHTTP)
26+
27+
if wrappedHandler == nil {
28+
t.Error("Error when creating a wrapped handler")
29+
}
30+
ctx := &fasthttp.RequestCtx{}
31+
ctx.Request.Header.SetMethod("GET")
32+
ctx.Request.SetRequestURI("/hello")
33+
wrappedHandler(ctx)
34+
app.ExpectErrors(t, []internal.WantError{{
35+
TxnName: "WebTransaction/Go/GET /hello",
36+
Msg: "my msg",
37+
Klass: "nrfasthttp.myError",
38+
}})
39+
40+
app.ExpectMetrics(t, []internal.WantMetric{
41+
{Name: "WebTransaction/Go/GET /hello", Scope: "", Forced: true, Data: nil},
42+
{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
43+
{Name: "WebTransactionTotalTime/Go/GET /hello", Scope: "", Forced: false, Data: nil},
44+
{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
45+
{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
46+
{Name: "Apdex", Scope: "", Forced: true, Data: nil},
47+
{Name: "Apdex/Go/GET /hello", Scope: "", Forced: false, Data: nil},
48+
{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
49+
{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
50+
{Name: "Errors/all", Scope: "", Forced: true, Data: singleCount},
51+
{Name: "Errors/allWeb", Scope: "", Forced: true, Data: singleCount},
52+
{Name: "Errors/WebTransaction/Go/GET /hello", Scope: "", Forced: true, Data: singleCount},
53+
{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
54+
{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
55+
})
56+
}

v3/integrations/nrfasthttp/segment.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package nrfasthttp
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/newrelic/go-agent/v3/newrelic"
7+
"github.com/valyala/fasthttp"
8+
"github.com/valyala/fasthttp/fasthttpadaptor"
9+
)
10+
11+
// StartExternalSegment automatically creates and fills out a New Relic external segment for a given
12+
// fasthttp request object. This function will accept either a fasthttp.Request or a fasthttp.RequestContext
13+
// object as the request argument.
14+
func StartExternalSegment(txn *newrelic.Transaction, request any) *newrelic.ExternalSegment {
15+
var secureAgentEvent any
16+
var ctx *fasthttp.RequestCtx
17+
18+
switch reqObject := request.(type) {
19+
20+
case *fasthttp.RequestCtx:
21+
ctx = reqObject
22+
23+
case *fasthttp.Request:
24+
ctx = &fasthttp.RequestCtx{}
25+
reqObject.CopyTo(&ctx.Request)
26+
27+
default:
28+
return nil
29+
}
30+
31+
if nil == txn {
32+
txn = transactionFromRequestContext(ctx)
33+
}
34+
req := &http.Request{}
35+
36+
fasthttpadaptor.ConvertRequest(ctx, req, true)
37+
s := &newrelic.ExternalSegment{
38+
StartTime: txn.StartSegmentNow(),
39+
Request: req,
40+
}
41+
42+
if newrelic.IsSecurityAgentPresent() {
43+
secureAgentEvent = newrelic.GetSecurityAgentInterface().SendEvent("OUTBOUND", request)
44+
s.SetSecureAgentEvent(secureAgentEvent)
45+
}
46+
47+
if request != nil && req.Header != nil {
48+
for key, values := range s.GetOutboundHeaders() {
49+
for _, value := range values {
50+
req.Header.Set(key, value)
51+
}
52+
}
53+
54+
if newrelic.IsSecurityAgentPresent() {
55+
newrelic.GetSecurityAgentInterface().DistributedTraceHeaders(req, secureAgentEvent)
56+
}
57+
58+
for k, values := range req.Header {
59+
for _, value := range values {
60+
ctx.Request.Header.Set(k, value)
61+
}
62+
}
63+
}
64+
65+
return s
66+
}
67+
68+
// FromContext extracts a transaction pointer from a fasthttp.RequestContext object
69+
func FromContext(ctx *fasthttp.RequestCtx) *newrelic.Transaction {
70+
return transactionFromRequestContext(ctx)
71+
}
72+
73+
func transactionFromRequestContext(ctx *fasthttp.RequestCtx) *newrelic.Transaction {
74+
if nil != ctx {
75+
txn := ctx.UserValue("transaction").(*newrelic.Transaction)
76+
return txn
77+
}
78+
79+
return nil
80+
}
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package nrfasthttp
2+
3+
import (
4+
"testing"
5+
6+
"github.com/newrelic/go-agent/v3/internal"
7+
"github.com/newrelic/go-agent/v3/internal/integrationsupport"
8+
"github.com/newrelic/go-agent/v3/newrelic"
9+
"github.com/valyala/fasthttp"
10+
)
11+
12+
func createTestApp(dt bool) integrationsupport.ExpectApp {
13+
return integrationsupport.NewTestApp(replyFn, integrationsupport.ConfigFullTraces, newrelic.ConfigDistributedTracerEnabled(dt))
14+
}
15+
16+
var replyFn = func(reply *internal.ConnectReply) {
17+
reply.SetSampleEverything()
18+
}
19+
20+
func TestExternalSegment(t *testing.T) {
21+
app := createTestApp(false)
22+
txn := app.StartTransaction("myTxn")
23+
24+
resp := fasthttp.AcquireResponse()
25+
defer fasthttp.ReleaseResponse(resp)
26+
27+
ctx := &fasthttp.RequestCtx{Request: fasthttp.Request{}}
28+
ctx.Request.SetRequestURI("http://localhost:8080/hello")
29+
ctx.Request.Header.SetMethod("GET")
30+
31+
seg := StartExternalSegment(txn, ctx)
32+
defer seg.End()
33+
34+
txn.End()
35+
app.ExpectMetrics(t, []internal.WantMetric{
36+
{Name: "OtherTransaction/Go/myTxn", Scope: "", Forced: true, Data: nil},
37+
{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
38+
{Name: "OtherTransactionTotalTime/Go/myTxn", Scope: "", Forced: false, Data: nil},
39+
{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
40+
})
41+
}
42+
43+
func TestExternalSegmentRequest(t *testing.T) {
44+
app := createTestApp(false)
45+
txn := app.StartTransaction("myTxn")
46+
47+
req := fasthttp.AcquireRequest()
48+
resp := fasthttp.AcquireResponse()
49+
defer fasthttp.ReleaseRequest(req)
50+
defer fasthttp.ReleaseResponse(resp)
51+
52+
req.SetRequestURI("http://localhost:8080/hello")
53+
req.Header.SetMethod("GET")
54+
55+
seg := StartExternalSegment(txn, req)
56+
defer seg.End()
57+
58+
txn.End()
59+
app.ExpectMetrics(t, []internal.WantMetric{
60+
{Name: "OtherTransaction/Go/myTxn", Scope: "", Forced: true, Data: nil},
61+
{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
62+
{Name: "OtherTransactionTotalTime/Go/myTxn", Scope: "", Forced: false, Data: nil},
63+
{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
64+
})
65+
}

0 commit comments

Comments
 (0)