Skip to content

Commit

Permalink
Feat: Auto-label profiles based on request baggage (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanhuhta authored Jun 18, 2024
1 parent ed0d159 commit f1a626f
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 9 deletions.
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
GO_VERSION_PRE20 := $(shell go version | awk '{print $$3}' | awk -F '.' '{print ($$1 == "go1" && int($$2) < 20)}')
TEST_PACKAGES := ./... ./godeltaprof/compat/... ./godeltaprof/...
GO_VERSION_PRE20 := $(shell go version | awk '{print $$3}' | awk -F '.' '{print ($$1 == "go1" && int($$2) < 20)}')
TEST_PACKAGES := ./... ./godeltaprof/compat/... ./godeltaprof/... ./x/k6/...

.PHONY: test
test:
Expand All @@ -12,6 +12,7 @@ go/mod:
GO111MODULE=on go mod tidy
cd godeltaprof/compat/ && GO111MODULE=on go mod download
cd godeltaprof/compat/ && GO111MODULE=on go mod tidy
cd godeltaprof/ && GO111MODULE=on go mod download
cd godeltaprof/ && GO111MODULE=on go mod download
cd godeltaprof/ && GO111MODULE=on go mod tidy

cd x/k6/ && GO111MODULE=on go mod download
cd x/k6/ && GO111MODULE=on go mod tidy
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ use (
.
godeltaprof
godeltaprof/compat
x/k6
)
14 changes: 12 additions & 2 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,32 @@ github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3I
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe6ZTd9F8kXETBoijjFJ/ntaa//1wiH9BZu4zU=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc=
go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o=
go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ=
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
Expand Down
2 changes: 1 addition & 1 deletion godeltaprof/compat/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.18
require (
github.com/google/pprof v0.0.0-20231127191134-f3a68a39ae15
github.com/grafana/pyroscope-go/godeltaprof v0.1.5
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
golang.org/x/tools v0.16.0
)

Expand Down
4 changes: 2 additions & 2 deletions godeltaprof/compat/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.5 h1:gkFVqihFRL1Nro2FCC0u6mW47j
github.com/grafana/pyroscope-go/godeltaprof v0.1.5/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
Expand Down
72 changes: 72 additions & 0 deletions x/k6/baggage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package k6

import (
"net/http"
"runtime/pprof"
"strings"

"github.com/grafana/pyroscope-go"
"go.opentelemetry.io/otel/baggage"
)

// LabelsFromBaggageHandler is a middleware that will extract key-value pairs
// from the request baggage and make them profiling labels.
func LabelsFromBaggageHandler(handler http.Handler) http.Handler {
lh := &labelHandler{
innerHandler: handler,
}

return lh
}

type labelHandler struct {
innerHandler http.Handler
}

func (lh *labelHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
labels := getBaggageLabels(r)
if labels == nil {
lh.innerHandler.ServeHTTP(w, r)
return
}

// Inlined version of pryoscope.TagWrapper and pprof.Do to reduce noise in
// the stack trace.
ctx := r.Context()
defer pprof.SetGoroutineLabels(ctx)
ctx = pprof.WithLabels(ctx, *labels)
pprof.SetGoroutineLabels(ctx)

lh.innerHandler.ServeHTTP(w, r.WithContext(ctx))
}

// getBaggageLabels applies filters and transformations to request baggage and
// returns the resulting LabelSet.
func getBaggageLabels(r *http.Request) *pyroscope.LabelSet {
b, err := baggage.Parse(r.Header.Get("Baggage"))
if err != nil {
return nil
}

labels := baggageToLabels(b)
return &labels
}

// baggageToLabels converts request baggage to a LabelSet.
func baggageToLabels(b baggage.Baggage) pyroscope.LabelSet {
labelPairs := make([]string, 0, len(b.Members())*2)
for _, m := range b.Members() {
if !strings.HasPrefix(m.Key(), "k6.") {
continue
}

if m.Value() == "" {
continue
}

key := strings.ReplaceAll(m.Key(), ".", "_")
labelPairs = append(labelPairs, key, m.Value())
}

return pyroscope.Labels(labelPairs...)
}
82 changes: 82 additions & 0 deletions x/k6/baggage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package k6

import (
"context"
"net/http"
"net/http/httptest"
"runtime/pprof"
"testing"

"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/baggage"
)

func Test_getBaggageLabels(t *testing.T) {
t.Run("empty values are skipped", func(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
req = testRequestWithBaggage(t, req, map[string]string{
"blank": "",
})

labelSet := getBaggageLabels(req)
gotLabels := testPprofLabelsToMap(t, *labelSet)

expectedLabels := map[string]string{}
require.Equal(t, expectedLabels, gotLabels)
})

t.Run("with K6Options", func(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
req = testRequestWithBaggage(t, req, map[string]string{
"k6.test_run_id": "123",
"not_k6.some_other_key": "value",
})

labelSet := getBaggageLabels(req)
gotLabels := testPprofLabelsToMap(t, *labelSet)

expectedLabels := map[string]string{
"k6_test_run_id": "123",
}
require.Equal(t, expectedLabels, gotLabels)
})

t.Run("does not allocate with failure to parse baggage", func(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
req.Header.Add("Baggage", "invalid")

labelSet := getBaggageLabels(req)
require.Nil(t, labelSet)
})
}

func testRequestWithBaggage(t *testing.T, req *http.Request, bag map[string]string) *http.Request {
t.Helper()

members := []baggage.Member{}
for k, v := range bag {
member, err := baggage.NewMember(k, v)
require.NoError(t, err)

members = append(members, member)
}

b, err := baggage.New(members...)
require.NoError(t, err)

req.Header.Add("Baggage", b.String())
return req
}

func testPprofLabelsToMap(t *testing.T, labelSet pprof.LabelSet) map[string]string {
t.Helper()

gotLabels := map[string]string{}
ctx := pprof.WithLabels(context.Background(), labelSet)
pprof.ForLabels(ctx, func(key, value string) bool {
gotLabels[key] = value
return true
})

return gotLabels
}
17 changes: 17 additions & 0 deletions x/k6/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module github.com/grafana/pyroscope-go/x/k6

go 1.18

require (
github.com/grafana/pyroscope-go v1.1.1
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel v1.17.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
19 changes: 19 additions & 0 deletions x/k6/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88=
github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo=
github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM=
go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 comments on commit f1a626f

Please sign in to comment.