From 548f986c1af4f4859737beae63274ce9a9fa5772 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 1 Oct 2023 10:37:21 +0700 Subject: [PATCH 1/7] feat(performance): start transaction for fasthttp integration --- fasthttp/sentryfasthttp.go | 30 ++++- fasthttp/sentryfasthttp_test.go | 223 +++++++++++++++++++++++++++++++- 2 files changed, 245 insertions(+), 8 deletions(-) diff --git a/fasthttp/sentryfasthttp.go b/fasthttp/sentryfasthttp.go index f6b6787af..20cbb04f7 100644 --- a/fasthttp/sentryfasthttp.go +++ b/fasthttp/sentryfasthttp.go @@ -20,6 +20,7 @@ type contextKey int const ContextKey = contextKey(1) const valuesKey = "sentry" +const transactionKey = "sentry_transaction" type Handler struct { repanic bool @@ -66,10 +67,28 @@ func (h *Handler) Handle(handler fasthttp.RequestHandler) fasthttp.RequestHandle client.SetSDKIdentifier(sdkIdentifier) } + convertedHttpRequest := convert(ctx) + + options := []sentry.SpanOption{ + sentry.WithOpName("http.server"), + sentry.ContinueFromRequest(convertedHttpRequest), + sentry.WithTransactionSource(sentry.SourceRoute), + } + transaction := sentry.StartTransaction( + sentry.SetHubOnContext(ctx, hub), + fmt.Sprintf("%s %s", string(ctx.Method()), string(ctx.Path())), + options..., + ) + defer func() { + transaction.Status = sentry.HTTPtoSpanStatus(ctx.Response.StatusCode()) + transaction.Finish() + }() + scope := hub.Scope() - scope.SetRequest(convert(ctx)) + scope.SetRequest(convertedHttpRequest) scope.SetRequestBody(ctx.Request.Body()) ctx.SetUserValue(valuesKey, hub) + ctx.SetUserValue(transactionKey, transaction) defer h.recoverWithSentry(hub, ctx) handler(ctx) } @@ -99,6 +118,15 @@ func GetHubFromContext(ctx *fasthttp.RequestCtx) *sentry.Hub { return nil } +// GetTransactionFromContext retrieves attached *sentry.Span instance from *fasthttp.RequestCtx. +// If there is no transaction on *fasthttp.RequestCtx, it will return nil. +func GetTransactionFromContext(ctx *fasthttp.RequestCtx) *sentry.Span { + if span, ok := ctx.UserValue(transactionKey).(*sentry.Span); ok { + return span + } + return nil +} + func convert(ctx *fasthttp.RequestCtx) *http.Request { defer func() { if err := recover(); err != nil { diff --git a/fasthttp/sentryfasthttp_test.go b/fasthttp/sentryfasthttp_test.go index 25187acb9..5642540c7 100644 --- a/fasthttp/sentryfasthttp_test.go +++ b/fasthttp/sentryfasthttp_test.go @@ -26,7 +26,8 @@ func TestIntegration(t *testing.T) { Body string Handler fasthttp.RequestHandler - WantEvent *sentry.Event + WantEvent *sentry.Event + WantTransaction *sentry.Event }{ { Path: "/panic", @@ -46,6 +47,20 @@ func TestIntegration(t *testing.T) { }, }, }, + WantTransaction: &sentry.Event{ + Level: sentry.LevelInfo, + Type: "transaction", + Transaction: "GET /panic", + Request: &sentry.Request{ + URL: "http://example.com/panic", + Method: "GET", + Headers: map[string]string{ + "Host": "example.com", + "User-Agent": "fasthttp", + }, + }, + TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + }, }, { Path: "/post", @@ -69,6 +84,21 @@ func TestIntegration(t *testing.T) { }, }, }, + WantTransaction: &sentry.Event{ + Level: sentry.LevelInfo, + Type: "transaction", + Transaction: "POST /post", + Request: &sentry.Request{ + URL: "http://example.com/post", + Method: "POST", + Data: "payload", + Headers: map[string]string{ + "Host": "example.com", + "User-Agent": "fasthttp", + }, + }, + TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + }, }, { Path: "/get", @@ -89,6 +119,20 @@ func TestIntegration(t *testing.T) { }, }, }, + WantTransaction: &sentry.Event{ + Level: sentry.LevelInfo, + Type: "transaction", + Transaction: "GET /get", + Request: &sentry.Request{ + URL: "http://example.com/get", + Method: "GET", + Headers: map[string]string{ + "Host": "example.com", + "User-Agent": "fasthttp", + }, + }, + TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + }, }, { Path: "/post/large", @@ -113,6 +157,21 @@ func TestIntegration(t *testing.T) { }, }, }, + WantTransaction: &sentry.Event{ + Level: sentry.LevelInfo, + Type: "transaction", + Transaction: "POST /post/large", + Request: &sentry.Request{ + URL: "http://example.com/post/large", + Method: "POST", + Data: "", + Headers: map[string]string{ + "Host": "example.com", + "User-Agent": "fasthttp", + }, + }, + TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + }, }, { Path: "/post/body-ignored", @@ -138,15 +197,37 @@ func TestIntegration(t *testing.T) { }, }, }, + WantTransaction: &sentry.Event{ + Level: sentry.LevelInfo, + Type: "transaction", + Transaction: "POST /post/body-ignored", + Request: &sentry.Request{ + URL: "http://example.com/post/body-ignored", + Method: "POST", + Data: "client sends, fasthttp always reads, SDK reports", + Headers: map[string]string{ + "Host": "example.com", + "User-Agent": "fasthttp", + }, + }, + TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + }, }, } eventsCh := make(chan *sentry.Event, len(tests)) + transactionsCh := make(chan *sentry.Event, len(tests)) err := sentry.Init(sentry.ClientOptions{ + EnableTracing: true, + TracesSampleRate: 1.0, BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event { eventsCh <- event return event }, + BeforeSendTransaction: func(tx *sentry.Event, hint *sentry.EventHint) *sentry.Event { + transactionsCh <- tx + return tx + }, }) if err != nil { t.Fatal(err) @@ -179,9 +260,11 @@ func TestIntegration(t *testing.T) { WriteTimeout: time.Second, } - var want []*sentry.Event + var wantEvents []*sentry.Event + var wantTransactions []*sentry.Event for _, tt := range tests { - want = append(want, tt.WantEvent) + wantEvents = append(wantEvents, tt.WantEvent) + wantTransactions = append(wantTransactions, tt.WantTransaction) req, res := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() req.SetHost("example.com") req.URI().SetPath(tt.Path) @@ -198,11 +281,13 @@ func TestIntegration(t *testing.T) { if ok := sentry.Flush(testutils.FlushTimeout()); !ok { t.Fatal("sentry.Flush timed out") } + close(eventsCh) - var got []*sentry.Event + var gotEvents []*sentry.Event for e := range eventsCh { - got = append(got, e) + gotEvents = append(gotEvents, e) } + opts := cmp.Options{ cmpopts.IgnoreFields( sentry.Event{}, @@ -221,10 +306,134 @@ func TestIntegration(t *testing.T) { return k == "Content-Length" || k == "Content-Type" }), } - if diff := cmp.Diff(want, got, opts); diff != "" { - t.Fatalf("Events mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantEvents, gotEvents, opts); diff != "" { + t.Fatalf("Events mismatch (-want +gotEvents):\n%s", diff) + } + + close(transactionsCh) + var gotTransactions []*sentry.Event + for e := range transactionsCh { + gotTransactions = append(gotTransactions, e) + } + optstrans := cmp.Options{ + cmpopts.IgnoreFields( + sentry.Event{}, + "Contexts", "EventID", "Platform", "Modules", + "Release", "Sdk", "ServerName", "Timestamp", + "sdkMetaData", "StartTime", "Spans", "attachments", + ), + cmpopts.IgnoreFields( + sentry.Request{}, + "Env", + ), + cmpopts.IgnoreMapEntries(func(k string, v string) bool { + // fasthttp changed Content-Length behavior in + // https://github.com/valyala/fasthttp/commit/097fa05a697fc638624a14ab294f1336da9c29b0. + // fasthttp changed Content-Type behavior in + // https://github.com/valyala/fasthttp/commit/ffa0cabed8199819e372ebd2c739998914150ff2. + // Since the specific values of those headers are not + // important from the perspective of sentry-go, we + // ignore them. + return k == "Content-Length" || k == "Content-Type" + }), + } + if diff := cmp.Diff(wantTransactions, gotTransactions, optstrans); diff != "" { + t.Fatalf("Transactions mismatch (-want +gotEvents):\n%s", diff) } ln.Close() <-done } + +func TestGetTransactionFromContext(t *testing.T) { + err := sentry.Init(sentry.ClientOptions{ + EnableTracing: true, + TracesSampleRate: 1.0, + }) + if err != nil { + t.Fatal(err) + } + + t.Run("With Transaction", func(t *testing.T) { + sentryHandler := sentryfasthttp.New(sentryfasthttp.Options{}) + ln := fasthttputil.NewInmemoryListener() + handler := func(ctx *fasthttp.RequestCtx) { + span := sentryfasthttp.GetTransactionFromContext(ctx) + if span == nil { + t.Error("expecting span to be not nil") + } + + ctx.SetStatusCode(200) + } + done := make(chan struct{}) + go func() { + if err := fasthttp.Serve(ln, sentryHandler.Handle(handler)); err != nil { + t.Errorf("error in Serve: %s", err) + } + close(done) + }() + + c := &fasthttp.Client{ + Dial: func(addr string) (net.Conn, error) { + return ln.Dial() + }, + ReadTimeout: time.Second, + WriteTimeout: time.Second, + } + + req, res := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() + req.SetHost("example.com") + req.URI().SetPath("/") + req.Header.SetMethod("GET") + if err := c.Do(req, res); err != nil { + t.Fatalf("Request failed: %s", err) + } + if res.StatusCode() != http.StatusOK { + t.Errorf("Status code = %d", res.StatusCode()) + } + + ln.Close() + <-done + }) + + t.Run("Without Transaction", func(t *testing.T) { + ln := fasthttputil.NewInmemoryListener() + handler := func(ctx *fasthttp.RequestCtx) { + span := sentryfasthttp.GetTransactionFromContext(ctx) + if span != nil { + t.Error("expecting span to be nil") + } + + ctx.SetStatusCode(200) + } + done := make(chan struct{}) + go func() { + if err := fasthttp.Serve(ln, handler); err != nil { + t.Errorf("error in Serve: %s", err) + } + close(done) + }() + + c := &fasthttp.Client{ + Dial: func(addr string) (net.Conn, error) { + return ln.Dial() + }, + ReadTimeout: time.Second, + WriteTimeout: time.Second, + } + + req, res := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() + req.SetHost("example.com") + req.URI().SetPath("/") + req.Header.SetMethod("GET") + if err := c.Do(req, res); err != nil { + t.Fatalf("Request failed: %s", err) + } + if res.StatusCode() != http.StatusOK { + t.Errorf("Status code = %d", res.StatusCode()) + } + + ln.Close() + <-done + }) +} From d7237a7ab5782f6883f4b5f00505343d83b84905 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 1 Oct 2023 11:53:59 +0700 Subject: [PATCH 2/7] lint: rename convertedHttpRequest to convertedHTTPRequest --- fasthttp/sentryfasthttp.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fasthttp/sentryfasthttp.go b/fasthttp/sentryfasthttp.go index 20cbb04f7..70625f29e 100644 --- a/fasthttp/sentryfasthttp.go +++ b/fasthttp/sentryfasthttp.go @@ -67,11 +67,11 @@ func (h *Handler) Handle(handler fasthttp.RequestHandler) fasthttp.RequestHandle client.SetSDKIdentifier(sdkIdentifier) } - convertedHttpRequest := convert(ctx) + convertedHTTPRequest := convert(ctx) options := []sentry.SpanOption{ sentry.WithOpName("http.server"), - sentry.ContinueFromRequest(convertedHttpRequest), + sentry.ContinueFromRequest(convertedHTTPRequest), sentry.WithTransactionSource(sentry.SourceRoute), } transaction := sentry.StartTransaction( @@ -85,7 +85,7 @@ func (h *Handler) Handle(handler fasthttp.RequestHandler) fasthttp.RequestHandle }() scope := hub.Scope() - scope.SetRequest(convertedHttpRequest) + scope.SetRequest(convertedHTTPRequest) scope.SetRequestBody(ctx.Request.Body()) ctx.SetUserValue(valuesKey, hub) ctx.SetUserValue(transactionKey, transaction) From 962d44829fc33d436319764701974fa17d541bc0 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 2 Mar 2024 07:30:54 +0700 Subject: [PATCH 3/7] fix(fasthttp): remove attachments from ignored compare list --- fasthttp/sentryfasthttp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fasthttp/sentryfasthttp_test.go b/fasthttp/sentryfasthttp_test.go index d0471d67c..12e0e141f 100644 --- a/fasthttp/sentryfasthttp_test.go +++ b/fasthttp/sentryfasthttp_test.go @@ -320,7 +320,7 @@ func TestIntegration(t *testing.T) { sentry.Event{}, "Contexts", "EventID", "Platform", "Modules", "Release", "Sdk", "ServerName", "Timestamp", - "sdkMetaData", "StartTime", "Spans", "attachments", + "sdkMetaData", "StartTime", "Spans", ), cmpopts.IgnoreFields( sentry.Request{}, From f332718c8386e632010af8a99442c4f9ecf5b490 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 2 Mar 2024 07:37:19 +0700 Subject: [PATCH 4/7] chore(fasthttp): rename GetTransactionFromContext to GetSpanFromContext --- _examples/fasthttp/main.go | 19 +++++++++++++++++++ fasthttp/sentryfasthttp.go | 4 ++-- fasthttp/sentryfasthttp_test.go | 4 ++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/_examples/fasthttp/main.go b/_examples/fasthttp/main.go index 8ced31107..827048bb8 100644 --- a/_examples/fasthttp/main.go +++ b/_examples/fasthttp/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "github.com/getsentry/sentry-go" @@ -13,6 +14,24 @@ func enhanceSentryEvent(handler fasthttp.RequestHandler) fasthttp.RequestHandler if hub := sentryfasthttp.GetHubFromContext(ctx); hub != nil { hub.Scope().SetTag("someRandomTag", "maybeYouNeedIt") } + + expensiveThing := func(ctx context.Context) error { + span := sentry.StartTransaction(ctx, "expensive_thing") + defer span.Finish() + // do resource intensive thing + return nil + } + + // Acquire transaction on current hub that's created by the SDK. + // Be careful, it might be a nil value if you didn't set up sentryecho middleware. + sentrySpan := sentryfasthttp.GetSpanFromContext(ctx) + // Pass in the `.Context()` method from `*sentry.Span` struct. + // The `context.Context` instance inherits the context from `echo.Context`. + err := expensiveThing(sentrySpan.Context()) + if err != nil { + sentry.CaptureException(err) + } + handler(ctx) } } diff --git a/fasthttp/sentryfasthttp.go b/fasthttp/sentryfasthttp.go index 70625f29e..41ca2f096 100644 --- a/fasthttp/sentryfasthttp.go +++ b/fasthttp/sentryfasthttp.go @@ -118,9 +118,9 @@ func GetHubFromContext(ctx *fasthttp.RequestCtx) *sentry.Hub { return nil } -// GetTransactionFromContext retrieves attached *sentry.Span instance from *fasthttp.RequestCtx. +// GetSpanFromContext retrieves attached *sentry.Span instance from *fasthttp.RequestCtx. // If there is no transaction on *fasthttp.RequestCtx, it will return nil. -func GetTransactionFromContext(ctx *fasthttp.RequestCtx) *sentry.Span { +func GetSpanFromContext(ctx *fasthttp.RequestCtx) *sentry.Span { if span, ok := ctx.UserValue(transactionKey).(*sentry.Span); ok { return span } diff --git a/fasthttp/sentryfasthttp_test.go b/fasthttp/sentryfasthttp_test.go index 12e0e141f..0124c8457 100644 --- a/fasthttp/sentryfasthttp_test.go +++ b/fasthttp/sentryfasthttp_test.go @@ -358,7 +358,7 @@ func TestGetTransactionFromContext(t *testing.T) { sentryHandler := sentryfasthttp.New(sentryfasthttp.Options{}) ln := fasthttputil.NewInmemoryListener() handler := func(ctx *fasthttp.RequestCtx) { - span := sentryfasthttp.GetTransactionFromContext(ctx) + span := sentryfasthttp.GetSpanFromContext(ctx) if span == nil { t.Error("expecting span to be not nil") } @@ -399,7 +399,7 @@ func TestGetTransactionFromContext(t *testing.T) { t.Run("Without Transaction", func(t *testing.T) { ln := fasthttputil.NewInmemoryListener() handler := func(ctx *fasthttp.RequestCtx) { - span := sentryfasthttp.GetTransactionFromContext(ctx) + span := sentryfasthttp.GetSpanFromContext(ctx) if span != nil { t.Error("expecting span to be nil") } From 24a2843b88b77e00501cf59dd10a8b0dee19e6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emir=20Ribi=C4=87?= Date: Sun, 24 Mar 2024 20:20:29 +0100 Subject: [PATCH 5/7] add http.request.method attribute to span data --- fasthttp/sentryfasthttp.go | 20 ++++++++----- fasthttp/sentryfasthttp_test.go | 53 ++++++++++++++++----------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/fasthttp/sentryfasthttp.go b/fasthttp/sentryfasthttp.go index 41ca2f096..8ceb33c1a 100644 --- a/fasthttp/sentryfasthttp.go +++ b/fasthttp/sentryfasthttp.go @@ -13,14 +13,15 @@ import ( "github.com/valyala/fasthttp" ) -// The identifier of the FastHTTP SDK. -const sdkIdentifier = "sentry.go.fasthttp" - type contextKey int -const ContextKey = contextKey(1) -const valuesKey = "sentry" -const transactionKey = "sentry_transaction" +const ( + ContextKey = contextKey(1) + // The identifier of the FastHTTP SDK. + sdkIdentifier = "sentry.go.fasthttp" + valuesKey = "sentry" + transactionKey = "sentry_transaction" +) type Handler struct { repanic bool @@ -74,9 +75,12 @@ func (h *Handler) Handle(handler fasthttp.RequestHandler) fasthttp.RequestHandle sentry.ContinueFromRequest(convertedHTTPRequest), sentry.WithTransactionSource(sentry.SourceRoute), } + + method := string(ctx.Method()) + transaction := sentry.StartTransaction( sentry.SetHubOnContext(ctx, hub), - fmt.Sprintf("%s %s", string(ctx.Method()), string(ctx.Path())), + fmt.Sprintf("%s %s", method, string(ctx.Path())), options..., ) defer func() { @@ -84,6 +88,8 @@ func (h *Handler) Handle(handler fasthttp.RequestHandler) fasthttp.RequestHandle transaction.Finish() }() + transaction.SetData("http.request.method", method) + scope := hub.Scope() scope.SetRequest(convertedHTTPRequest) scope.SetRequestBody(ctx.Request.Body()) diff --git a/fasthttp/sentryfasthttp_test.go b/fasthttp/sentryfasthttp_test.go index 0124c8457..3e916543a 100644 --- a/fasthttp/sentryfasthttp_test.go +++ b/fasthttp/sentryfasthttp_test.go @@ -21,11 +21,10 @@ func TestIntegration(t *testing.T) { largePayload := strings.Repeat("Large", 3*1024) // 15 KB tests := []struct { - Path string - Method string - Body string - Handler fasthttp.RequestHandler - + Path string + Method string + Body string + Handler fasthttp.RequestHandler WantEvent *sentry.Event WantTransaction *sentry.Event }{ @@ -34,13 +33,12 @@ func TestIntegration(t *testing.T) { Handler: func(*fasthttp.RequestCtx) { panic("test") }, - WantEvent: &sentry.Event{ Level: sentry.LevelFatal, Message: "test", Request: &sentry.Request{ URL: "http://example.com/panic", - Method: "GET", + Method: http.MethodGet, Headers: map[string]string{ "Host": "example.com", "User-Agent": "fasthttp", @@ -53,30 +51,30 @@ func TestIntegration(t *testing.T) { Transaction: "GET /panic", Request: &sentry.Request{ URL: "http://example.com/panic", - Method: "GET", + Method: http.MethodGet, Headers: map[string]string{ "Host": "example.com", "User-Agent": "fasthttp", }, }, TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + Extra: map[string]any{"http.request.method": http.MethodGet}, }, }, { Path: "/post", - Method: "POST", + Method: http.MethodPost, Body: "payload", Handler: func(ctx *fasthttp.RequestCtx) { hub := sentryfasthttp.GetHubFromContext(ctx) hub.CaptureMessage("post: " + string(ctx.Request.Body())) }, - WantEvent: &sentry.Event{ Level: sentry.LevelInfo, Message: "post: payload", Request: &sentry.Request{ URL: "http://example.com/post", - Method: "POST", + Method: http.MethodPost, Data: "payload", Headers: map[string]string{ "Host": "example.com", @@ -90,7 +88,7 @@ func TestIntegration(t *testing.T) { Transaction: "POST /post", Request: &sentry.Request{ URL: "http://example.com/post", - Method: "POST", + Method: http.MethodPost, Data: "payload", Headers: map[string]string{ "Host": "example.com", @@ -98,21 +96,21 @@ func TestIntegration(t *testing.T) { }, }, TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + Extra: map[string]any{"http.request.method": http.MethodPost}, }, }, { Path: "/get", Handler: func(ctx *fasthttp.RequestCtx) { hub := sentryfasthttp.GetHubFromContext(ctx) - hub.CaptureMessage("get") + hub.CaptureMessage(http.MethodGet) }, - WantEvent: &sentry.Event{ Level: sentry.LevelInfo, - Message: "get", + Message: http.MethodGet, Request: &sentry.Request{ URL: "http://example.com/get", - Method: "GET", + Method: http.MethodGet, Headers: map[string]string{ "Host": "example.com", "User-Agent": "fasthttp", @@ -125,30 +123,30 @@ func TestIntegration(t *testing.T) { Transaction: "GET /get", Request: &sentry.Request{ URL: "http://example.com/get", - Method: "GET", + Method: http.MethodGet, Headers: map[string]string{ "Host": "example.com", "User-Agent": "fasthttp", }, }, TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + Extra: map[string]any{"http.request.method": http.MethodGet}, }, }, { Path: "/post/large", - Method: "POST", + Method: http.MethodPost, Body: largePayload, Handler: func(ctx *fasthttp.RequestCtx) { hub := sentryfasthttp.GetHubFromContext(ctx) hub.CaptureMessage(fmt.Sprintf("post: %d KB", len(ctx.Request.Body())/1024)) }, - WantEvent: &sentry.Event{ Level: sentry.LevelInfo, Message: "post: 15 KB", Request: &sentry.Request{ URL: "http://example.com/post/large", - Method: "POST", + Method: http.MethodPost, // Actual request body omitted because too large. Data: "", Headers: map[string]string{ @@ -163,7 +161,7 @@ func TestIntegration(t *testing.T) { Transaction: "POST /post/large", Request: &sentry.Request{ URL: "http://example.com/post/large", - Method: "POST", + Method: http.MethodPost, Data: "", Headers: map[string]string{ "Host": "example.com", @@ -171,23 +169,23 @@ func TestIntegration(t *testing.T) { }, }, TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + Extra: map[string]any{"http.request.method": http.MethodPost}, }, }, { Path: "/post/body-ignored", - Method: "POST", + Method: http.MethodPost, Body: "client sends, fasthttp always reads, SDK reports", Handler: func(ctx *fasthttp.RequestCtx) { hub := sentryfasthttp.GetHubFromContext(ctx) hub.CaptureMessage("body ignored") }, - WantEvent: &sentry.Event{ Level: sentry.LevelInfo, Message: "body ignored", Request: &sentry.Request{ URL: "http://example.com/post/body-ignored", - Method: "POST", + Method: http.MethodPost, // Actual request body included because fasthttp always // reads full request body. Data: "client sends, fasthttp always reads, SDK reports", @@ -203,7 +201,7 @@ func TestIntegration(t *testing.T) { Transaction: "POST /post/body-ignored", Request: &sentry.Request{ URL: "http://example.com/post/body-ignored", - Method: "POST", + Method: http.MethodPost, Data: "client sends, fasthttp always reads, SDK reports", Headers: map[string]string{ "Host": "example.com", @@ -211,6 +209,7 @@ func TestIntegration(t *testing.T) { }, }, TransactionInfo: &sentry.TransactionInfo{Source: "route"}, + Extra: map[string]any{"http.request.method": http.MethodPost}, }, }, } @@ -384,7 +383,7 @@ func TestGetTransactionFromContext(t *testing.T) { req, res := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() req.SetHost("example.com") req.URI().SetPath("/") - req.Header.SetMethod("GET") + req.Header.SetMethod(http.MethodGet) if err := c.Do(req, res); err != nil { t.Fatalf("Request failed: %s", err) } @@ -425,7 +424,7 @@ func TestGetTransactionFromContext(t *testing.T) { req, res := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() req.SetHost("example.com") req.URI().SetPath("/") - req.Header.SetMethod("GET") + req.Header.SetMethod(http.MethodGet) if err := c.Do(req, res); err != nil { t.Fatalf("Request failed: %s", err) } From 55aa0308db2cbbf74fc0361d318cb3490826395e Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 26 Mar 2024 20:11:06 +0700 Subject: [PATCH 6/7] chore(fasthttp): remove unrelated docstring for hub --- fasthttp/sentryfasthttp.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fasthttp/sentryfasthttp.go b/fasthttp/sentryfasthttp.go index 8ceb33c1a..795c70a79 100644 --- a/fasthttp/sentryfasthttp.go +++ b/fasthttp/sentryfasthttp.go @@ -58,10 +58,6 @@ func New(options Options) *Handler { // Handle wraps fasthttp.RequestHandler and recovers from caught panics. func (h *Handler) Handle(handler fasthttp.RequestHandler) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { - // Unlike for other integrations, we don't support getting an existing - // hub from the current request context because fasthttp doesn't use the - // standard net/http.Request and because fasthttp.RequestCtx implements - // context.Context but requires string keys. hub := sentry.CurrentHub().Clone() if client := hub.Client(); client != nil { From 0623e4a7f5df4bf2a6ff6c17614a03704a5346ee Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 26 Mar 2024 20:11:42 +0700 Subject: [PATCH 7/7] chore: add changellog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c21aa40c0..e3a084b15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Accept `interface{}` for span data values ([#784](https://github.com/getsentry/sentry-go/pull/784)) - Automatic transactions for Echo integration ([#722](https://github.com/getsentry/sentry-go/pull/722)) +- Automatic transactions for Fasthttp integration ([#732](https://github.com/getsentry/sentry-go/pull/723)) ## 0.27.0