From aa0a1a2e87be02f1527f334620c4d45f6fb6ffd4 Mon Sep 17 00:00:00 2001 From: Evan Jones Date: Tue, 2 Jun 2020 14:59:11 -0400 Subject: [PATCH] Add gzip response compression; Update to latest version Add a test to ensure this keeps working! --- Dockerfile | 12 +- cloudbuild.yaml | 6 +- go.mod | 8 +- go.sum | 15 +- pprofweb.go | 32 +++- pprofweb_test.go | 427 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 479 insertions(+), 21 deletions(-) create mode 100644 pprofweb_test.go diff --git a/Dockerfile b/Dockerfile index ffab68b..7476fba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,15 @@ -FROM golang:1.14.2-buster AS builder -COPY go.mod go.sum pprofweb.go /go/src/pprofweb/ -WORKDIR /go/src/pprofweb -RUN go build --mod=readonly pprofweb.go - - # Extract graphviz and dependencies -FROM golang:1.14.2-buster AS deb_extractor +FROM golang:1.14.3-buster AS deb_extractor RUN cd /tmp && \ apt-get update && apt-get download \ graphviz libgvc6 libcgraph6 libltdl7 libxdot4 libcdt5 libpathplan4 libexpat1 zlib1g && \ mkdir /dpkg && \ for deb in *.deb; do dpkg --extract $deb /dpkg || exit 10; done +FROM golang:1.14.3-buster AS builder +COPY go.mod go.sum pprofweb.go /go/src/pprofweb/ +WORKDIR /go/src/pprofweb +RUN go build --mod=readonly pprofweb.go FROM gcr.io/distroless/base-debian10:latest AS run COPY --from=builder /go/src/pprofweb/pprofweb /pprofweb diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 19ec57b..55d726b 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,5 +1,7 @@ +# build with: +# gcloud builds submit . --substitutions=SHORT_SHA=$(git rev-parse --short=10 HEAD) steps: - name: 'gcr.io/cloud-builders/docker' - args: ['build', '--tag=us.gcr.io/$PROJECT_ID/pprofweb', '.'] + args: ['build', '--tag=us.gcr.io/$PROJECT_ID/pprofweb:$SHORT_SHA', '.'] images: -- 'us.gcr.io/$PROJECT_ID/pprofweb' +- 'us.gcr.io/$PROJECT_ID/pprofweb:$SHORT_SHA' diff --git a/go.mod b/go.mod index 8024eae..6cf3180 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,10 @@ module github.com/evanj/pprofweb go 1.13 -require github.com/google/pprof v0.0.0-20200407193738-d6d2dc122c20 +require ( + github.com/NYTimes/gziphandler v1.1.1 + // commit 427632fa3b1c fails as user nobody: + // https://github.com/google/pprof/pull/542 + github.com/google/pprof v0.0.0-20200504201735-160c4290d1d8 + github.com/ianlancetaylor/demangle v0.0.0-20200524003926-2c5affb30a03 // indirect +) diff --git a/go.sum b/go.sum index 74aa05b..6d47091 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,21 @@ +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/google/pprof v0.0.0-20200407193738-d6d2dc122c20 h1:ckvXA2EKYK4RORZWjE+V7VrWRBLYeQHe4J4pmoMLgT0= -github.com/google/pprof v0.0.0-20200407193738-d6d2dc122c20/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/pprof v0.0.0-20200504201735-160c4290d1d8 h1:ZgqXCvT0BTD13IbwObhtnwUMzfgA+/MTn7dhqb9x9EI= +github.com/google/pprof v0.0.0-20200504201735-160c4290d1d8/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200524003926-2c5affb30a03 h1:FjiybxAA4IL7VWbzhdskUDIXM2yIyE+/PRchayObTC4= +github.com/ianlancetaylor/demangle v0.0.0-20200524003926-2c5affb30a03/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pprofweb.go b/pprofweb.go index 19cb33a..6368419 100644 --- a/pprofweb.go +++ b/pprofweb.go @@ -8,8 +8,10 @@ import ( "net/http/pprof" "os" "path" + "path/filepath" "strings" + "github.com/NYTimes/gziphandler" "github.com/google/pprof/driver" ) @@ -17,19 +19,21 @@ const portEnvVar = "PORT" const defaultPort = "8080" const maxUploadSize = 32 << 20 // 32 MiB -const pprofFilePath = "/tmp/pprofweb-temp" - const fileFormID = "file" const uploadPath = "/upload" const pprofWebPath = "/pprofweb/" +// use the system-specified temporary directory +// TODO: do something smarter with a real temporary directory +var pprofFilePath = filepath.Join(os.TempDir(), "pprofweb-temp") + type server struct { // serves pprof handlers after it is loaded - pprofMux *http.ServeMux + pprofMux http.Handler } func (s *server) startHTTP(args *driver.HTTPServerArgs) error { - s.pprofMux = http.NewServeMux() + mux := http.NewServeMux() for pattern, handler := range args.Handlers { var joinedPattern string if pattern == "/" { @@ -37,8 +41,12 @@ func (s *server) startHTTP(args *driver.HTTPServerArgs) error { } else { joinedPattern = path.Join(pprofWebPath, pattern) } - s.pprofMux.Handle(joinedPattern, handler) + mux.Handle(joinedPattern, handler) } + + // enable gzip compression: flamegraphs can be big! + s.pprofMux = gziphandler.GzipHandler(mux) + return nil } @@ -72,6 +80,7 @@ func (s *server) uploadHandlerErrHandler(w http.ResponseWriter, r *http.Request) } err := s.uploadHandler(w, r) if err != nil { + log.Printf("upload error: %s", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -121,9 +130,8 @@ func (s *server) uploadHandler(w http.ResponseWriter, r *http.Request) error { return nil } -func main() { - s := &server{} - +// handler returns a handler that servers the pprof web UI. +func (s *server) handler() *http.ServeMux { mux := http.NewServeMux() mux.HandleFunc("/", rootHandler) mux.HandleFunc(uploadPath, s.uploadHandlerErrHandler) @@ -135,6 +143,12 @@ func main() { mux.HandleFunc("/debug/pprof/profile", pprof.Profile) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) mux.HandleFunc("/debug/pprof/trace", pprof.Trace) + return mux +} + +func main() { + s := &server{} + handler := s.handler() port := os.Getenv(portEnvVar) if port == "" { @@ -144,7 +158,7 @@ func main() { addr := ":" + port log.Printf("listen addr %s (http://localhost:%s/)", addr, port) - if err := http.ListenAndServe(addr, mux); err != nil { + if err := http.ListenAndServe(addr, handler); err != nil { panic(err) } } diff --git a/pprofweb_test.go b/pprofweb_test.go new file mode 100644 index 0000000..0a266c8 --- /dev/null +++ b/pprofweb_test.go @@ -0,0 +1,427 @@ +package main + +import ( + "bytes" + "encoding/base64" + "mime/multipart" + "net/http" + "net/http/httptest" + "testing" +) + +func TestE2E(t *testing.T) { + allocsPprof, err := base64.StdEncoding.DecodeString(b64AllocsPprof) + if err != nil { + t.Fatal(err) + } + s := &server{} + handler := s.handler() + + // write the pprof request + uploadReqBody := &bytes.Buffer{} + writer := multipart.NewWriter(uploadReqBody) + part, err := writer.CreateFormFile(fileFormID, "file.pprof") + if err != nil { + t.Fatal(err) + } + _, err = part.Write(allocsPprof) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // send the request! + req := httptest.NewRequest(http.MethodPost, uploadPath, uploadReqBody) + req.Header.Set("Content-Type", writer.FormDataContentType()) + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + resp := w.Result() + + if resp.StatusCode != http.StatusSeeOther { + t.Error("unexpected Status:", resp.Status) + } + if resp.Header.Get("Location") != pprofWebPath { + t.Error("unexpected Location header:", resp.Header.Get("Location")) + } + + // load the flame graph! + req = httptest.NewRequest(http.MethodGet, pprofWebPath+"flamegraph", nil) + w = httptest.NewRecorder() + handler.ServeHTTP(w, req) + resp = w.Result() + + if resp.StatusCode != http.StatusOK { + t.Error("unexpected Status:", resp.Status) + } + if resp.Header.Get("Content-Type") != "text/html" { + t.Error("unexpected Content-Type:", resp.Header.Get("Content-Type")) + } + if resp.Header.Get("Content-Encoding") != "" { + t.Error("request without Accept-Encoding: should not set Content-Encoding:", + resp.Header.Get("Content-Encoding")) + } + + // Chrome sends "gzip, deflate, br" + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding + // req.Header.Set("Accept-Encoding", "deflate;q=0.1, gzip;q=1.0, *, identity, br") + req.Header.Set("Accept-Encoding", "gzip") + w = httptest.NewRecorder() + handler.ServeHTTP(w, req) + resp = w.Result() + + if resp.StatusCode != http.StatusOK { + t.Error("unexpected Status:", resp.Status) + } + if resp.Header.Get("Content-Type") != "text/html" { + t.Error("unexpected Content-Type:", resp.Header.Get("Content-Type")) + } + if resp.Header.Get("Content-Encoding") != "gzip" { + t.Error("request with Accept-Encoding: should set Content-Encoding:", + resp.Header.Get("Content-Encoding")) + } + +} + +const b64AllocsPprof = ` +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 +qRlZU+ytqPjL/wsAAP//89xlkkbAAAA= +`