-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into synthetics_v1
- Loading branch information
Showing
26 changed files
with
531 additions
and
243 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
v3/integrations/nrfasthttp/examples/client-fasthttp/go.mod
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 => ../../ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
v3/integrations/nrfasthttp/examples/server-fasthttp/go.mod
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 => ../../ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}, | ||
}) | ||
} |
Oops, something went wrong.