Skip to content

Commit 7085a1d

Browse files
aldy505cleptric
andauthored
fix(http): use route name from 'r.Pattern' instead (#875)
* fix(http): use route name from 'r.Pattern' instead * fix(http): bump build version to 1.23 * ref(internal): move GetHTTPSpanName to internal package * chore: changelog entry --------- Co-authored-by: Michi Hoffmann <[email protected]>
1 parent e5d46d5 commit 7085a1d

7 files changed

+113
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- Add trace origin to span data ([#849](https://github.com/getsentry/sentry-go/pull/849))
44
- Add ability to skip frames in stacktrace ([#852](https://github.com/getsentry/sentry-go/pull/852))
55
- Remove Martini integration ([#861](https://github.com/getsentry/sentry-go/pull/861))
6+
- Use value from http.Request.Pattern as HTTP server span name ([#875](https://github.com/getsentry/sentry-go/pull/875))
67
- Fix closure functions name grouping ([#877](https://github.com/getsentry/sentry-go/pull/877))
78

89

http/sentryhttp.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ package sentryhttp
44

55
import (
66
"context"
7-
"fmt"
87
"net/http"
98
"time"
109

1110
"github.com/getsentry/sentry-go"
11+
"github.com/getsentry/sentry-go/internal/traceutils"
1212
)
1313

1414
// The identifier of the HTTP SDK.
@@ -102,7 +102,7 @@ func (h *Handler) handle(handler http.Handler) http.HandlerFunc {
102102
}
103103

104104
transaction := sentry.StartTransaction(ctx,
105-
fmt.Sprintf("%s %s", r.Method, r.URL.Path),
105+
traceutils.GetHTTPSpanName(r),
106106
options...,
107107
)
108108
transaction.SetData("http.request.method", r.Method)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//go:build !go1.23
2+
3+
package traceutils
4+
5+
import "net/http"
6+
7+
// GetHTTPSpanName grab needed fields from *http.Request to generate a span name for `http.server` span op.
8+
func GetHTTPSpanName(r *http.Request) string {
9+
return r.Method + " " + r.URL.Path
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//go:build !go1.23
2+
3+
package traceutils
4+
5+
import (
6+
"net/http"
7+
"net/url"
8+
"testing"
9+
)
10+
11+
func TestGetHTTPSpanName(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
got string
15+
want string
16+
}{
17+
{
18+
name: "Without Pattern",
19+
got: GetHTTPSpanName(&http.Request{Method: "GET", URL: &url.URL{Path: "/"}}),
20+
want: "GET /",
21+
},
22+
}
23+
for _, tt := range tests {
24+
t.Run(tt.name, func(t *testing.T) {
25+
if tt.got != tt.want {
26+
t.Errorf("got %q; want %q", tt.got, tt.want)
27+
}
28+
})
29+
}
30+
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//go:build go1.23
2+
3+
package traceutils
4+
5+
import (
6+
"net/http"
7+
"strings"
8+
)
9+
10+
// GetHTTPSpanName grab needed fields from *http.Request to generate a span name for `http.server` span op.
11+
func GetHTTPSpanName(r *http.Request) string {
12+
if r.Pattern != "" {
13+
// If value does not start with HTTP methods, add them.
14+
// The method and the path should be separated by a space.
15+
if parts := strings.SplitN(r.Pattern, " ", 2); len(parts) == 1 {
16+
return r.Method + " " + r.Pattern
17+
}
18+
19+
return r.Pattern
20+
}
21+
22+
return r.Method + " " + r.URL.Path
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//go:build go1.23
2+
3+
package traceutils
4+
5+
import (
6+
"net/http"
7+
"net/url"
8+
"testing"
9+
)
10+
11+
func TestGetHTTPSpanName(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
got string
15+
want string
16+
}{
17+
{
18+
name: "Without Pattern",
19+
got: GetHTTPSpanName(&http.Request{Method: "GET", URL: &url.URL{Path: "/"}}),
20+
want: "GET /",
21+
},
22+
{
23+
name: "Pattern with method",
24+
got: GetHTTPSpanName(&http.Request{Method: "GET", URL: &url.URL{Path: "/"}, Pattern: "POST /foo/{bar}"}),
25+
want: "POST /foo/{bar}",
26+
},
27+
{
28+
name: "Pattern without method",
29+
got: GetHTTPSpanName(&http.Request{Method: "GET", URL: &url.URL{Path: "/"}, Pattern: "/foo/{bar}"}),
30+
want: "GET /foo/{bar}",
31+
},
32+
{
33+
name: "Pattern without slash",
34+
got: GetHTTPSpanName(&http.Request{Method: "GET", URL: &url.URL{Path: "/"}, Pattern: "example.com/"}),
35+
want: "GET example.com/",
36+
},
37+
}
38+
for _, tt := range tests {
39+
t.Run(tt.name, func(t *testing.T) {
40+
if tt.got != tt.want {
41+
t.Errorf("got %q; want %q", tt.got, tt.want)
42+
}
43+
})
44+
}
45+
}

negroni/sentrynegroni.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package sentrynegroni
22

33
import (
44
"context"
5-
"fmt"
65
"net/http"
76
"time"
87

98
"github.com/getsentry/sentry-go"
9+
"github.com/getsentry/sentry-go/internal/traceutils"
1010
"github.com/urfave/negroni"
1111
)
1212

@@ -71,7 +71,7 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.Ha
7171
// We don't mind getting an existing transaction back so we don't need to
7272
// check if it is.
7373
transaction := sentry.StartTransaction(ctx,
74-
fmt.Sprintf("%s %s", r.Method, r.URL.Path),
74+
traceutils.GetHTTPSpanName(r),
7575
options...,
7676
)
7777
transaction.SetData("http.request.method", r.Method)

0 commit comments

Comments
 (0)