From a8c6bf874136d1f3f9833bbf68dcbd9868345186 Mon Sep 17 00:00:00 2001 From: Mirac Kara <55501260+mirackara@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:35:03 -0500 Subject: [PATCH 1/2] 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 Co-authored-by: Steve Willoughby <76975199+nr-swilloughby@users.noreply.github.com> Co-authored-by: Julien Erard Co-authored-by: Emilio Garcia Co-authored-by: Steve Willoughby --- CHANGELOG.md | 17 +++- v3/examples/client-fasthttp/main.go | 62 ++++++++++++ v3/examples/server-fasthttp/main.go | 58 +++++++++++ v3/go.mod | 1 + v3/integrations/nrfasthttp/go.mod | 9 ++ .../server-http-logs-in-context/main.go | 97 +++++++++++++++++++ .../{example => examples/server}/main.go | 0 v3/integrations/nrsecurityagent/go.mod | 2 +- .../nrsecurityagent/nrsecurityagent.go | 2 +- v3/newrelic/context.go | 14 +++ v3/newrelic/instrumentation.go | 91 ++++++++++++++++- v3/newrelic/internal_17_test.go | 43 ++++++++ v3/newrelic/internal_context_test.go | 25 +++++ v3/newrelic/segments.go | 33 +++++++ v3/newrelic/version.go | 2 +- 15 files changed, 447 insertions(+), 9 deletions(-) create mode 100644 v3/examples/client-fasthttp/main.go create mode 100644 v3/examples/server-fasthttp/main.go create mode 100644 v3/integrations/nrfasthttp/go.mod create mode 100644 v3/integrations/nrlogrus/examples/server-http-logs-in-context/main.go rename v3/integrations/nrlogrus/{example => examples/server}/main.go (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5719b313b..92ae88fa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,30 @@ +## 3.25.0 +### Added + * Added Support for FastHTTP package + * Added newrelic.WrapHandleFuncFastHTTP() and newrelic.StartExternalSegmentFastHTTP() functions to instrument fasthttp context and create wrapped handlers. These functions work similarly to the existing ones for net/http + * Added client-fasthttp and server-fasthttp examples to help get started with FastHTTP integration + +### Fixed + * Corrected a bug where the security agent failed to correctly parse the `NEW_RELIC_SECURITY_AGENT_ENABLED` environment variable. + +### 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 (i.e., Go versions 1.19 and later are supported). +We recommend updating to the latest agent version as soon as it’s available. If you can’t upgrade to the latest version, update your agents to a version no more than 90 days old. Read more about keeping agents up to date. (https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/install-configure/update-new-relic-agent/) +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.24.1 ### Fixed * Performance improvement around calls to security agent. In some cases, unnecessary setup operations were being performed even if there was no security agent present to use that. These are now conditional on the security agent being present in the application (note that this will enable the setup code if the security agent is *present* in the application, regardless of whether it's currently enabled to run). This affects: * Base agent code (updated to v3.24.1) * `nrmongo` integration (updated to v1.1.1) + * Resolved a race condition caused by the above-mentioned calls to the security agent. * Fixed unit tests for integrations which were failing because code level metrics are enabled by default now: * `nrawssdk-v1` (updated to v1.1.2) * `nrawssdk-v2` (updated to v1.2.2) * `nrecho-v3` (updated to v1.0.2) * `nrecho-v4` (updated to v1.0.4) - * `nrhttprouter` (updated to + * `nrhttprouter` (updated to v1.0.2) * `nrlambda` (updated to v1.2.2) * `nrnats` (updated to v1.1.5) * `nrredis-v8` (updated to v1.0.1) diff --git a/v3/examples/client-fasthttp/main.go b/v3/examples/client-fasthttp/main.go new file mode 100644 index 000000000..7a26b605f --- /dev/null +++ b/v3/examples/client-fasthttp/main.go @@ -0,0 +1,62 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "fmt" + "os" + "time" + + newrelic "github.com/newrelic/go-agent/v3/newrelic" + "github.com/valyala/fasthttp" +) + +func doRequest(txn *newrelic.Transaction) error { + req := fasthttp.AcquireRequest() + resp := fasthttp.AcquireResponse() + defer fasthttp.ReleaseRequest(req) + defer fasthttp.ReleaseResponse(resp) + + req.SetRequestURI("http://localhost:8080/hello") + req.Header.SetMethod("GET") + + ctx := &fasthttp.RequestCtx{} + seg := newrelic.StartExternalSegmentFastHTTP(txn, ctx) + defer seg.End() + + err := fasthttp.Do(req, resp) + if err != nil { + return err + } + + fmt.Println("Response Code is ", resp.StatusCode()) + return nil + +} + +func main() { + app, err := newrelic.NewApplication( + newrelic.ConfigAppName("Client App"), + newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), + newrelic.ConfigDebugLogger(os.Stdout), + newrelic.ConfigDistributedTracerEnabled(true), + ) + + if err := app.WaitForConnection(5 * time.Second); nil != err { + fmt.Println(err) + } + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + txn := app.StartTransaction("client-txn") + err = doRequest(txn) + if err != nil { + txn.NoticeError(err) + } + txn.End() + + // Shut down the application to flush data to New Relic. + app.Shutdown(10 * time.Second) +} diff --git a/v3/examples/server-fasthttp/main.go b/v3/examples/server-fasthttp/main.go new file mode 100644 index 000000000..8ed532670 --- /dev/null +++ b/v3/examples/server-fasthttp/main.go @@ -0,0 +1,58 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "errors" + "fmt" + "os" + "time" + + newrelic "github.com/newrelic/go-agent/v3/newrelic" + + "github.com/valyala/fasthttp" +) + +func index(ctx *fasthttp.RequestCtx) { + ctx.WriteString("Hello World") +} + +func noticeError(ctx *fasthttp.RequestCtx) { + ctx.WriteString("noticing an error") + txn := ctx.UserValue("transaction").(*newrelic.Transaction) + txn.NoticeError(errors.New("my error message")) +} + +func main() { + // Initialize New Relic + app, err := newrelic.NewApplication( + newrelic.ConfigAppName("FastHTTP App"), + newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), + newrelic.ConfigDebugLogger(os.Stdout), + newrelic.ConfigDistributedTracerEnabled(true), + ) + if err != nil { + fmt.Println(err) + return + } + if err := app.WaitForConnection(5 * time.Second); nil != err { + fmt.Println(err) + } + _, helloRoute := newrelic.WrapHandleFuncFastHTTP(app, "/hello", index) + _, errorRoute := newrelic.WrapHandleFuncFastHTTP(app, "/error", noticeError) + handler := func(ctx *fasthttp.RequestCtx) { + path := string(ctx.Path()) + method := string(ctx.Method()) + + switch { + case method == "GET" && path == "/hello": + helloRoute(ctx) + case method == "GET" && path == "/error": + errorRoute(ctx) + } + } + + // Start the server with the instrumented handler + fasthttp.ListenAndServe(":8080", handler) +} diff --git a/v3/go.mod b/v3/go.mod index d00562a5a..910c288d1 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -4,6 +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 ) diff --git a/v3/integrations/nrfasthttp/go.mod b/v3/integrations/nrfasthttp/go.mod new file mode 100644 index 000000000..d4e207230 --- /dev/null +++ b/v3/integrations/nrfasthttp/go.mod @@ -0,0 +1,9 @@ +module github.com/newrelic/go-agent/v3/integrations/nrfasthttp + +go 1.19 + +require ( + github.com/newrelic/go-agent/v3 v3.23.1 + github.com/stretchr/testify v1.8.4 + github.com/valyala/fasthttp v1.48.0 +) diff --git a/v3/integrations/nrlogrus/examples/server-http-logs-in-context/main.go b/v3/integrations/nrlogrus/examples/server-http-logs-in-context/main.go new file mode 100644 index 000000000..7ce3a5782 --- /dev/null +++ b/v3/integrations/nrlogrus/examples/server-http-logs-in-context/main.go @@ -0,0 +1,97 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// An application that illustrates Distributed Tracing with Logs-in-Context +// when using http.Server or similar frameworks. +package main + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "time" + + "github.com/newrelic/go-agent/v3/integrations/logcontext-v2/nrlogrus" + newrelic "github.com/newrelic/go-agent/v3/newrelic" + "github.com/sirupsen/logrus" +) + +type handler struct { + App *newrelic.Application +} + +func (h *handler) ServeHTTP(writer http.ResponseWriter, req *http.Request) { + // The call to StartTransaction must include the response writer and the + // request. + txn := h.App.StartTransaction("server-txn") + defer txn.End() + + txnLogger := logrus.WithContext(newrelic.NewContext(context.Background(), txn)) + + writer = txn.SetWebResponse(writer) + txn.SetWebRequestHTTP(req) + + if req.URL.String() == "/segments" { + defer txn.StartSegment("f1").End() + + txnLogger.Infof("/segments just started") + + func() { + defer txn.StartSegment("f2").End() + + io.WriteString(writer, "segments!") + time.Sleep(10 * time.Millisecond) + + txnLogger.Infof("segment func just about to complete") + }() + time.Sleep(10 * time.Millisecond) + } else { + // Transaction.WriteHeader has to be used instead of invoking + // WriteHeader on the response writer. + writer.WriteHeader(http.StatusNotFound) + } + txnLogger.Infof("handler completing") +} + +func makeApplication() (*newrelic.Application, error) { + app, err := newrelic.NewApplication( + newrelic.ConfigAppName("HTTP Server App"), + newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")), + ) + if nil != err { + return nil, err + } + nrlogrusFormatter := nrlogrus.NewFormatter(app, &logrus.TextFormatter{}) + logrus.SetFormatter(nrlogrusFormatter) + // Alternatively and if preferred, create a new logger and use that logger + // for logging with + // log := logrus.New() + // log.SetFormatter(nrlogrusFormatter) + + // Wait for the application to connect. + if err = app.WaitForConnection(5 * time.Second); nil != err { + return nil, err + } + + return app, nil +} + +func main() { + + app, err := makeApplication() + if nil != err { + fmt.Println(err) + os.Exit(1) + } + + logrus.Infof("Application Starting") + + server := http.Server{ + Addr: ":8000", + Handler: &handler{App: app}, + } + + server.ListenAndServe() +} diff --git a/v3/integrations/nrlogrus/example/main.go b/v3/integrations/nrlogrus/examples/server/main.go similarity index 100% rename from v3/integrations/nrlogrus/example/main.go rename to v3/integrations/nrlogrus/examples/server/main.go diff --git a/v3/integrations/nrsecurityagent/go.mod b/v3/integrations/nrsecurityagent/go.mod index 2e805f3b8..990ec08c0 100644 --- a/v3/integrations/nrsecurityagent/go.mod +++ b/v3/integrations/nrsecurityagent/go.mod @@ -3,7 +3,7 @@ module github.com/newrelic/go-agent/v3/integrations/nrsecurityagent go 1.19 require ( - github.com/newrelic/csec-go-agent v0.3.0 + github.com/newrelic/csec-go-agent v0.4.0 github.com/newrelic/go-agent/v3 v3.24.1 github.com/newrelic/go-agent/v3/integrations/nrsqlite3 v1.2.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/v3/integrations/nrsecurityagent/nrsecurityagent.go b/v3/integrations/nrsecurityagent/nrsecurityagent.go index acc994eca..c7264d7ad 100644 --- a/v3/integrations/nrsecurityagent/nrsecurityagent.go +++ b/v3/integrations/nrsecurityagent/nrsecurityagent.go @@ -37,7 +37,7 @@ func defaultSecurityConfig() SecurityConfig { // If env is set to false,the security module is not loaded func isSecurityAgentEnabled() bool { if env := os.Getenv("NEW_RELIC_SECURITY_AGENT_ENABLED"); env != "" { - if b, err := strconv.ParseBool("false"); err == nil { + if b, err := strconv.ParseBool(env); err == nil { return b } } diff --git a/v3/newrelic/context.go b/v3/newrelic/context.go index 5ce186f3d..731dcb73f 100644 --- a/v3/newrelic/context.go +++ b/v3/newrelic/context.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/newrelic/go-agent/v3/internal" + "github.com/valyala/fasthttp" ) // NewContext returns a new context.Context that carries the provided @@ -52,3 +53,16 @@ func transactionFromRequestContext(req *http.Request) *Transaction { } return txn } + +func transactionFromRequestContextFastHTTP(ctx *fasthttp.RequestCtx) *Transaction { + var txn *Transaction + if nil != ctx { + txn := ctx.UserValue("transaction").(*Transaction) + return txn + } + + if txn != nil { + return txn + } + return nil +} diff --git a/v3/newrelic/instrumentation.go b/v3/newrelic/instrumentation.go index 4e37e5316..e4351a955 100644 --- a/v3/newrelic/instrumentation.go +++ b/v3/newrelic/instrumentation.go @@ -5,18 +5,41 @@ package newrelic import ( "net/http" + + "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) +} + // instrumentation.go contains helpers built on the lower level api. // WrapHandle instruments http.Handler handlers with Transactions. To // instrument this code: // -// http.Handle("/foo", myHandler) +// http.Handle("/foo", myHandler) // // Perform this replacement: // -// http.Handle(newrelic.WrapHandle(app, "/foo", myHandler)) +// http.Handle(newrelic.WrapHandle(app, "/foo", myHandler)) // // WrapHandle adds the Transaction to the request's context. Access it using // FromContext to add attributes, create segments, or notice errors: @@ -76,6 +99,56 @@ func WrapHandle(app *Application, pattern string, handler http.Handler, options }) } +func WrapHandleFastHTTP(app *Application, pattern string, handler fasthttp.RequestHandler, options ...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). + cache := NewCachedCodeLocation() + + return pattern, func(ctx *fasthttp.RequestCtx) { + var tOptions *traceOptSet + var txnOptionList []TraceOption + + if app.app != nil && app.app.run != nil && app.app.run.Config.CodeLevelMetrics.Enabled { + tOptions = resolveCLMTraceOptions(options) + if tOptions != nil && !tOptions.SuppressCLM && (tOptions.DemandCLM || app.app.run.Config.CodeLevelMetrics.Scope == 0 || (app.app.run.Config.CodeLevelMetrics.Scope&TransactionCLM) != 0) { + // we are for sure collecting CLM here, so go to the trouble of collecting this code location if nothing else has yet. + if tOptions.LocationOverride == nil { + if loc, err := cache.FunctionLocation(handler); err == nil { + WithCodeLocation(loc)(tOptions) + } + } + } + } + if tOptions == nil { + // we weren't able to curate the options above, so pass whatever we were given downstream + txnOptionList = options + } else { + txnOptionList = append(txnOptionList, withPreparedOptions(tOptions)) + } + + 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) + + r = RequestWithTransactionContext(r, txn) + + handler(ctx) + } +} + // WrapHandleFunc instruments handler functions using Transactions. To // instrument this code: // @@ -111,15 +184,23 @@ func WrapHandleFunc(app *Application, pattern string, handler func(http.Response return p, func(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) } } -// +func WrapHandleFuncFastHTTP(app *Application, pattern string, handler func(*fasthttp.RequestCtx), options ...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 := WrapHandleFastHTTP(app, pattern, fasthttp.RequestHandler(handler), options...) + return p, func(ctx *fasthttp.RequestCtx) { h(ctx) } +} + // WrapListen wraps an HTTP endpoint reference passed to functions like http.ListenAndServe, // which causes security scanning to be done for that incoming endpoint when vulnerability // scanning is enabled. It returns the endpoint string, so you can replace a call like // -// http.ListenAndServe(":8000", nil) +// http.ListenAndServe(":8000", nil) +// // with -// http.ListenAndServe(newrelic.WrapListen(":8000"), nil) // +// http.ListenAndServe(newrelic.WrapListen(":8000"), nil) func WrapListen(endpoint string) string { if IsSecurityAgentPresent() { secureAgent.SendEvent("APP_INFO", endpoint) diff --git a/v3/newrelic/internal_17_test.go b/v3/newrelic/internal_17_test.go index 82d1dc8f1..5ba7b6c7e 100644 --- a/v3/newrelic/internal_17_test.go +++ b/v3/newrelic/internal_17_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/newrelic/go-agent/v3/internal" + "github.com/valyala/fasthttp" ) func myErrorHandler(w http.ResponseWriter, req *http.Request) { @@ -18,6 +19,48 @@ func myErrorHandler(w http.ResponseWriter, req *http.Request) { txn.NoticeError(myError{}) } +func myErrorHandlerFastHTTP(ctx *fasthttp.RequestCtx) { + ctx.WriteString("noticing an error") + txn := ctx.UserValue("transaction").(*Transaction) + txn.NoticeError(myError{}) +} + +func TestWrapHandleFastHTTPFunc(t *testing.T) { + app := testApp(nil, ConfigDistributedTracerEnabled(true), t) + + _, wrappedHandler := WrapHandleFuncFastHTTP(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: "newrelic.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}, + }) +} + func TestWrapHandleFunc(t *testing.T) { app := testApp(nil, ConfigDistributedTracerEnabled(false), t) mux := http.NewServeMux() diff --git a/v3/newrelic/internal_context_test.go b/v3/newrelic/internal_context_test.go index 1e15e61cd..51372d382 100644 --- a/v3/newrelic/internal_context_test.go +++ b/v3/newrelic/internal_context_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/newrelic/go-agent/v3/internal" + "github.com/valyala/fasthttp" ) func TestWrapHandlerContext(t *testing.T) { @@ -36,6 +37,30 @@ func TestWrapHandlerContext(t *testing.T) { {Name: "Custom/mySegment", Scope: scope, Forced: false, Data: nil}, }) } +func TestExternalSegmentFastHTTP(t *testing.T) { + app := testApp(nil, ConfigDistributedTracerEnabled(false), t) + 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") + + ctx := &fasthttp.RequestCtx{} + seg := StartExternalSegmentFastHTTP(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 TestStartExternalSegmentNilTransaction(t *testing.T) { // Test that StartExternalSegment pulls the transaction from the diff --git a/v3/newrelic/segments.go b/v3/newrelic/segments.go index 91f8fcc5a..65344033a 100644 --- a/v3/newrelic/segments.go +++ b/v3/newrelic/segments.go @@ -5,6 +5,9 @@ package newrelic import ( "net/http" + + "github.com/valyala/fasthttp" + "github.com/valyala/fasthttp/fasthttpadaptor" ) // SegmentStartTime is created by Transaction.StartSegmentNow and marks the @@ -337,6 +340,36 @@ func StartExternalSegment(txn *Transaction, request *http.Request) *ExternalSegm return s } +func StartExternalSegmentFastHTTP(txn *Transaction, ctx *fasthttp.RequestCtx) *ExternalSegment { + if nil == txn { + txn = transactionFromRequestContextFastHTTP(ctx) + } + request := &http.Request{} + + fasthttpadaptor.ConvertRequest(ctx, request, true) + s := &ExternalSegment{ + StartTime: txn.StartSegmentNow(), + Request: request, + } + if IsSecurityAgentPresent() { + s.secureAgentEvent = secureAgent.SendEvent("OUTBOUND", request) + } + + if request != nil && request.Header != nil { + for key, values := range s.outboundHeaders() { + for _, value := range values { + request.Header.Set(key, value) + } + } + + if IsSecurityAgentPresent() { + secureAgent.DistributedTraceHeaders(request, s.secureAgentEvent) + } + } + + return s +} + func addSpanAttr(start SegmentStartTime, key string, val interface{}) { if nil == start.thread { return diff --git a/v3/newrelic/version.go b/v3/newrelic/version.go index b1a8adefd..c6b63256f 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.24.1" + Version = "3.25.0" ) var ( From e1c5027387550a83ca3c917fcd9ee8e6cb0f95bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 22:36:06 +0000 Subject: [PATCH 2/2] 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](https://github.com/grpc/grpc-go/compare/v1.54.0...v1.56.3) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] --- v3/integrations/nrgraphqlgo/example/go.mod | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/v3/integrations/nrgraphqlgo/example/go.mod b/v3/integrations/nrgraphqlgo/example/go.mod index d5a044811..8a0f85ece 100644 --- a/v3/integrations/nrgraphqlgo/example/go.mod +++ b/v3/integrations/nrgraphqlgo/example/go.mod @@ -16,12 +16,12 @@ require ( github.com/klauspost/compress v1.16.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.49.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.54.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.56.3 // indirect + google.golang.org/protobuf v1.30.0 // indirect ) replace github.com/newrelic/go-agent/v3/integrations/nrgraphqlgo => ../