Skip to content

Commit

Permalink
Release 3.28.0 (#818)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
8 people committed Nov 16, 2023
1 parent 79d3bfd commit 0e521dc
Show file tree
Hide file tree
Showing 27 changed files with 532 additions and 244 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
# v3 integrations
- go-version: 1.19.x
dirs: v3/integrations/nramqp
- go-version: 1.19.x
dirs: v3/integrations/nrfasthttp
- go-version: 1.19.x
dirs: v3/integrations/nrsarama
- go-version: 1.19.x
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 3.28.0
### Fixed
* Bumped gRPC from 1.54.0 -> 1.56.3 in the following packages /v3/integrations/nrgrpc, /v3/, /v3/integrations/nrgrpc
* Bumped golang.org/x/net from 0.8.0 -> 0.17.0 in package /v3/integrations/nrgraphqlgo
* Fixed issue where nrfasthttp would not properly register security agent headers
* Move fasthttp instrumentation into a new integration package, nrfasthttp
* Fixed issue where usage of io.ReadAll() was causing a memory leak

### Support statement

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.

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.


## 3.27.0
### Added
* Added Support for getting Container ID's from cgroup v2 docker containers
Expand Down
3 changes: 1 addition & 2 deletions v3/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ go 1.19

require (
github.com/golang/protobuf v1.5.3
github.com/valyala/fasthttp v1.49.0
google.golang.org/grpc v1.54.0
google.golang.org/grpc v1.56.3
)

retract v3.22.0 // release process error corrected in v3.22.1
Expand Down
11 changes: 11 additions & 0 deletions v3/integrations/nrfasthttp/examples/client-fasthttp/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module client-example

go 1.19

require (
github.com/newrelic/go-agent/v3 v3.28.0
github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0
github.com/valyala/fasthttp v1.49.0
)

replace github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0 => ../../
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"time"

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

ctx := &fasthttp.RequestCtx{}
seg := newrelic.StartExternalSegmentFastHTTP(txn, ctx)
seg := nrfasthttp.StartExternalSegment(txn, req)
defer seg.End()

err := fasthttp.Do(req, resp)
Expand Down
11 changes: 11 additions & 0 deletions v3/integrations/nrfasthttp/examples/server-fasthttp/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module server-example

go 1.19

require (
github.com/newrelic/go-agent/v3 v3.28.0
github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0
github.com/valyala/fasthttp v1.49.0
)

replace github.com/newrelic/go-agent/v3/integrations/nrfasthttp v1.0.0 => ../../
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import (
"os"
"time"

newrelic "github.com/newrelic/go-agent/v3/newrelic"
"github.com/newrelic/go-agent/v3/integrations/nrfasthttp"
"github.com/newrelic/go-agent/v3/newrelic"

"github.com/valyala/fasthttp"
)
Expand Down Expand Up @@ -39,8 +40,8 @@ func main() {
if err := app.WaitForConnection(5 * time.Second); nil != err {
fmt.Println(err)
}
_, helloRoute := newrelic.WrapHandleFuncFastHTTP(app, "/hello", index)
_, errorRoute := newrelic.WrapHandleFuncFastHTTP(app, "/error", noticeError)
_, helloRoute := nrfasthttp.WrapHandleFunc(app, "/hello", index)
_, errorRoute := nrfasthttp.WrapHandleFunc(app, "/error", noticeError)
handler := func(ctx *fasthttp.RequestCtx) {
path := string(ctx.Path())
method := string(ctx.Method())
Expand Down
6 changes: 2 additions & 4 deletions v3/integrations/nrfasthttp/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ module github.com/newrelic/go-agent/v3/integrations/nrfasthttp
go 1.19

require (
github.com/newrelic/go-agent/v3 v3.26.0
github.com/stretchr/testify v1.8.4
github.com/valyala/fasthttp v1.48.0
github.com/newrelic/go-agent/v3 v3.28.0
github.com/valyala/fasthttp v1.49.0
)
replace github.com/newrelic/go-agent/v3 => ../..
74 changes: 74 additions & 0 deletions v3/integrations/nrfasthttp/instrumentation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package nrfasthttp

import (
"net/http"

"github.com/newrelic/go-agent/v3/newrelic"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
)

type fasthttpWrapperResponse struct {
ctx *fasthttp.RequestCtx
}

func (rw fasthttpWrapperResponse) Header() http.Header {
hdrs := http.Header{}
rw.ctx.Request.Header.VisitAll(func(key, value []byte) {
hdrs.Add(string(key), string(value))
})
return hdrs
}

func (rw fasthttpWrapperResponse) Write(b []byte) (int, error) {
return rw.ctx.Write(b)
}

func (rw fasthttpWrapperResponse) WriteHeader(code int) {
rw.ctx.SetStatusCode(code)
}

func (rw fasthttpWrapperResponse) Body() string {
body := rw.ctx.Response.Body()
return string(body)
}

// WrapHandleFunc wrapps a fasthttp handler function for automatic instrumentation
func WrapHandleFunc(app *newrelic.Application, pattern string, handler func(*fasthttp.RequestCtx), options ...newrelic.TraceOption) (string, func(*fasthttp.RequestCtx)) {
// add the wrapped function to the trace options as the source code reference point
// (to the beginning of the option list, so that the user can override this)

p, h := WrapHandle(app, pattern, fasthttp.RequestHandler(handler), options...)
return p, func(ctx *fasthttp.RequestCtx) { h(ctx) }
}

// WrapHandle wraps a fasthttp request handler for automatic instrumentation
func WrapHandle(app *newrelic.Application, pattern string, handler fasthttp.RequestHandler, options ...newrelic.TraceOption) (string, fasthttp.RequestHandler) {
if app == nil {
return pattern, handler
}

// add the wrapped function to the trace options as the source code reference point
// (but only if we know we're collecting CLM for this transaction and the user didn't already
// specify a different code location explicitly).
return pattern, func(ctx *fasthttp.RequestCtx) {
cache := newrelic.NewCachedCodeLocation()
txnOptionList := newrelic.AddCodeLevelMetricsTraceOptions(app, options, cache, handler)
method := string(ctx.Method())
path := string(ctx.Path())
txn := app.StartTransaction(method+" "+path, txnOptionList...)
ctx.SetUserValue("transaction", txn)
defer txn.End()
r := &http.Request{}
fasthttpadaptor.ConvertRequest(ctx, r, true)
resp := fasthttpWrapperResponse{ctx: ctx}

txn.SetWebResponse(resp)
txn.SetWebRequestHTTP(r)

if newrelic.IsSecurityAgentPresent() {
newrelic.GetSecurityAgentInterface().SendEvent("INBOUND_WRITE", resp.Body(), resp.Header())
}
handler(ctx)
}
}
56 changes: 56 additions & 0 deletions v3/integrations/nrfasthttp/instrumentation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package nrfasthttp

import (
"testing"

"github.com/newrelic/go-agent/v3/internal"
"github.com/newrelic/go-agent/v3/newrelic"
"github.com/valyala/fasthttp"
)

type myError struct{}

func (e myError) Error() string { return "my msg" }

func myErrorHandlerFastHTTP(ctx *fasthttp.RequestCtx) {
ctx.WriteString("noticing an error")
txn := ctx.UserValue("transaction").(*newrelic.Transaction)
txn.NoticeError(myError{})
}

func TestWrapHandleFastHTTPFunc(t *testing.T) {
singleCount := []float64{1, 0, 0, 0, 0, 0, 0}
app := createTestApp(true)

_, wrappedHandler := WrapHandleFunc(app.Application, "/hello", myErrorHandlerFastHTTP)

if wrappedHandler == nil {
t.Error("Error when creating a wrapped handler")
}
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.SetMethod("GET")
ctx.Request.SetRequestURI("/hello")
wrappedHandler(ctx)
app.ExpectErrors(t, []internal.WantError{{
TxnName: "WebTransaction/Go/GET /hello",
Msg: "my msg",
Klass: "nrfasthttp.myError",
}})

app.ExpectMetrics(t, []internal.WantMetric{
{Name: "WebTransaction/Go/GET /hello", Scope: "", Forced: true, Data: nil},
{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
{Name: "WebTransactionTotalTime/Go/GET /hello", Scope: "", Forced: false, Data: nil},
{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
{Name: "Apdex", Scope: "", Forced: true, Data: nil},
{Name: "Apdex/Go/GET /hello", Scope: "", Forced: false, Data: nil},
{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
{Name: "Errors/all", Scope: "", Forced: true, Data: singleCount},
{Name: "Errors/allWeb", Scope: "", Forced: true, Data: singleCount},
{Name: "Errors/WebTransaction/Go/GET /hello", Scope: "", Forced: true, Data: singleCount},
{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
})
}
80 changes: 80 additions & 0 deletions v3/integrations/nrfasthttp/segment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package nrfasthttp

import (
"net/http"

"github.com/newrelic/go-agent/v3/newrelic"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
)

// StartExternalSegment automatically creates and fills out a New Relic external segment for a given
// fasthttp request object. This function will accept either a fasthttp.Request or a fasthttp.RequestContext
// object as the request argument.
func StartExternalSegment(txn *newrelic.Transaction, request any) *newrelic.ExternalSegment {
var secureAgentEvent any
var ctx *fasthttp.RequestCtx

switch reqObject := request.(type) {

case *fasthttp.RequestCtx:
ctx = reqObject

case *fasthttp.Request:
ctx = &fasthttp.RequestCtx{}
reqObject.CopyTo(&ctx.Request)

default:
return nil
}

if nil == txn {
txn = transactionFromRequestContext(ctx)
}
req := &http.Request{}

fasthttpadaptor.ConvertRequest(ctx, req, true)
s := &newrelic.ExternalSegment{
StartTime: txn.StartSegmentNow(),
Request: req,
}

if newrelic.IsSecurityAgentPresent() {
secureAgentEvent = newrelic.GetSecurityAgentInterface().SendEvent("OUTBOUND", request)
s.SetSecureAgentEvent(secureAgentEvent)
}

if request != nil && req.Header != nil {
for key, values := range s.GetOutboundHeaders() {
for _, value := range values {
req.Header.Set(key, value)
}
}

if newrelic.IsSecurityAgentPresent() {
newrelic.GetSecurityAgentInterface().DistributedTraceHeaders(req, secureAgentEvent)
}

for k, values := range req.Header {
for _, value := range values {
ctx.Request.Header.Set(k, value)
}
}
}

return s
}

// FromContext extracts a transaction pointer from a fasthttp.RequestContext object
func FromContext(ctx *fasthttp.RequestCtx) *newrelic.Transaction {
return transactionFromRequestContext(ctx)
}

func transactionFromRequestContext(ctx *fasthttp.RequestCtx) *newrelic.Transaction {
if nil != ctx {
txn := ctx.UserValue("transaction").(*newrelic.Transaction)
return txn
}

return nil
}
65 changes: 65 additions & 0 deletions v3/integrations/nrfasthttp/segment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package nrfasthttp

import (
"testing"

"github.com/newrelic/go-agent/v3/internal"
"github.com/newrelic/go-agent/v3/internal/integrationsupport"
"github.com/newrelic/go-agent/v3/newrelic"
"github.com/valyala/fasthttp"
)

func createTestApp(dt bool) integrationsupport.ExpectApp {
return integrationsupport.NewTestApp(replyFn, integrationsupport.ConfigFullTraces, newrelic.ConfigDistributedTracerEnabled(dt))
}

var replyFn = func(reply *internal.ConnectReply) {
reply.SetSampleEverything()
}

func TestExternalSegment(t *testing.T) {
app := createTestApp(false)
txn := app.StartTransaction("myTxn")

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

ctx := &fasthttp.RequestCtx{Request: fasthttp.Request{}}
ctx.Request.SetRequestURI("http://localhost:8080/hello")
ctx.Request.Header.SetMethod("GET")

seg := StartExternalSegment(txn, ctx)
defer seg.End()

txn.End()
app.ExpectMetrics(t, []internal.WantMetric{
{Name: "OtherTransaction/Go/myTxn", Scope: "", Forced: true, Data: nil},
{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
{Name: "OtherTransactionTotalTime/Go/myTxn", Scope: "", Forced: false, Data: nil},
{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
})
}

func TestExternalSegmentRequest(t *testing.T) {
app := createTestApp(false)
txn := app.StartTransaction("myTxn")

req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://localhost:8080/hello")
req.Header.SetMethod("GET")

seg := StartExternalSegment(txn, req)
defer seg.End()

txn.End()
app.ExpectMetrics(t, []internal.WantMetric{
{Name: "OtherTransaction/Go/myTxn", Scope: "", Forced: true, Data: nil},
{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
{Name: "OtherTransactionTotalTime/Go/myTxn", Scope: "", Forced: false, Data: nil},
{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
})
}

0 comments on commit 0e521dc

Please sign in to comment.