├── .github ├── dependabot.yml ├── preview-01.png ├── preview-02.png └── workflows │ ├── release.yml │ └── scan.yml ├── .gitignore ├── .goreleaser.yaml ├── LICENSE ├── README.md ├── README_CN.md ├── docker ├── Dockerfile └── goreleaser.Dockerfile ├── go.mod ├── go.sum ├── internal ├── files │ ├── files.go │ └── files_test.go ├── pprof │ └── flags.go ├── server │ ├── assets.go │ ├── assets │ │ └── index.html │ ├── pprof.go │ └── server.go └── version │ └── version.go ├── main.go └── pkg └── random └── random.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/preview-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zjc17/pprof-web/acd4a2bcbffd3d6f5655f47dd8ca334ffe8606be/.github/preview-01.png -------------------------------------------------------------------------------- /.github/preview-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zjc17/pprof-web/acd4a2bcbffd3d6f5655f47dd8ca334ffe8606be/.github/preview-02.png -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - 'main' 8 | tags: 9 | - 'v*' 10 | env: 11 | GO_VERSION: "1.20" 12 | 13 | permissions: 14 | contents: write 15 | id-token: write 16 | packages: write 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | env: 22 | GO111MODULE: on 23 | DOCKER_CLI_EXPERIMENTAL: "enabled" 24 | steps: 25 | - 26 | name: Checkout 27 | uses: actions/checkout@v3 28 | with: 29 | fetch-depth: 0 30 | - 31 | name: Set up Go 32 | uses: actions/setup-go@v3 33 | with: 34 | go-version: ${{ env.GO_VERSION }} 35 | - 36 | name: Set up QEMU 37 | uses: docker/setup-qemu-action@v1 38 | - 39 | name: Cache Go modules 40 | uses: actions/cache@v1 41 | with: 42 | path: ~/go/pkg/mod 43 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 44 | restore-keys: | 45 | ${{ runner.os }}-go- 46 | - 47 | name: Tests 48 | run: | 49 | go mod tidy 50 | go test -v ./... 51 | - name: Login to Docker Hub 52 | if: github.event_name != 'pull_request' 53 | uses: docker/login-action@v2 54 | with: 55 | username: ${{ secrets.DOCKERHUB_USERNAME }} 56 | password: ${{ secrets.DOCKERHUB_TOKEN }} 57 | - 58 | name: Run GoReleaser 59 | uses: goreleaser/goreleaser-action@v3 60 | if: success() && startsWith(github.ref, 'refs/tags/') 61 | with: 62 | version: latest 63 | args: release --clean 64 | env: 65 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | -------------------------------------------------------------------------------- /.github/workflows/scan.yml: -------------------------------------------------------------------------------- 1 | name: "Security Scan" 2 | 3 | # Run workflow each time code is pushed to your repository and on a schedule. 4 | # The scheduled workflow runs every at 00:00 on Sunday UTC time. 5 | on: 6 | workflow_dispatch: 7 | push: 8 | branches: 9 | - main 10 | paths: 11 | - '*.go' 12 | pull_request: 13 | branches: 14 | - main 15 | schedule: 16 | - cron: '0 0 * * 0' 17 | 18 | jobs: 19 | scan: 20 | permissions: write-all 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Check out code into the Go module directory 24 | uses: actions/checkout@v2 25 | - name: Security Scan 26 | uses: securego/gosec@master 27 | with: 28 | # we let the report trigger content trigger a failure using the GitHub Security features. 29 | args: '-no-fail -fmt sarif -out results.sarif ./...' 30 | - name: Upload SARIF file 31 | uses: github/codeql-action/upload-sarif@v2 32 | with: 33 | # Path to SARIF file relative to the root of the repository 34 | sarif_file: results.sarif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | # If you prefer the allow list template instead of the deny list, see community template: 3 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 4 | # 5 | # Binaries for programs and plugins 6 | *.exe 7 | *.exe~ 8 | *.dll 9 | *.so 10 | *.dylib 11 | 12 | # Test binary, built with `go test -c` 13 | *.test 14 | 15 | # Output of the go coverage tool, specifically when used with LiteIDE 16 | *.out 17 | 18 | # Dependency directories (remove the comment below to include it) 19 | # vendor/ 20 | 21 | # Go workspace file 22 | go.work 23 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | project_name: pprof-web 2 | 3 | builds: 4 | - <<: &build_defaults 5 | env: 6 | - CGO_ENABLED=0 7 | ldflags: 8 | - -X "github.com/zjc17/pprof-web/internal/version.Version={{ .Tag }}" 9 | id: macos 10 | goos: [ darwin ] 11 | goarch: [ amd64, arm64 ] 12 | 13 | - <<: *build_defaults 14 | id: linux 15 | goos: [linux] 16 | goarch: ["386", arm, amd64, arm64] 17 | goarm: 18 | - "7" 19 | - "6" 20 | 21 | dockers: 22 | 23 | - image_templates: 24 | - "lovecho/pprof-web:linux-amd64-{{ .Tag }}" 25 | - "lovecho/pprof-web:linux-amd64" 26 | dockerfile: docker/goreleaser.Dockerfile 27 | use: buildx 28 | goarch: amd64 29 | build_flag_templates: 30 | - "--pull" 31 | - "--platform=linux/amd64" 32 | - "--label=org.opencontainers.image.title={{ .ProjectName }}" 33 | - "--label=org.opencontainers.image.description={{ .ProjectName }}" 34 | - "--label=org.opencontainers.image.url=https://github.com/zjc17/pprof-web" 35 | - "--label=org.opencontainers.image.source=https://github.com/zjc17/pprof-web" 36 | - "--label=org.opencontainers.image.version={{ .Version }}" 37 | - "--label=org.opencontainers.image.created={{ .Date }}" 38 | - "--label=org.opencontainers.image.revision={{ .FullCommit }}" 39 | - "--label=org.opencontainers.image.licenses=Apache-v2" 40 | 41 | - image_templates: 42 | - "lovecho/pprof-web:linux-arm64-{{ .Tag }}" 43 | - "lovecho/pprof-web:linux-arm64" 44 | dockerfile: docker/goreleaser.Dockerfile 45 | use: buildx 46 | goos: linux 47 | goarch: arm64 48 | goarm: '' 49 | build_flag_templates: 50 | - "--pull" 51 | - "--platform=linux/arm64" 52 | - "--label=org.opencontainers.image.title={{ .ProjectName }}" 53 | - "--label=org.opencontainers.image.description={{ .ProjectName }}" 54 | - "--label=org.opencontainers.image.url=https://github.com/zjc17/pprof-web" 55 | - "--label=org.opencontainers.image.source=https://github.com/zjc17/pprof-web" 56 | - "--label=org.opencontainers.image.version={{ .Version }}" 57 | - "--label=org.opencontainers.image.created={{ .Date }}" 58 | - "--label=org.opencontainers.image.revision={{ .FullCommit }}" 59 | - "--label=org.opencontainers.image.licenses=Apache-v2" 60 | 61 | - image_templates: 62 | - "lovecho/pprof-web:linux-armv7-{{ .Tag }}" 63 | - "lovecho/pprof-web:linux-armv7" 64 | dockerfile: docker/goreleaser.Dockerfile 65 | use: buildx 66 | goos: linux 67 | goarch: arm 68 | goarm: "7" 69 | build_flag_templates: 70 | - "--pull" 71 | - "--platform=linux/arm/v7" 72 | - "--label=org.opencontainers.image.title={{ .ProjectName }}" 73 | - "--label=org.opencontainers.image.description={{ .ProjectName }}" 74 | - "--label=org.opencontainers.image.url=https://github.com/zjc17/pprof-web" 75 | - "--label=org.opencontainers.image.source=https://github.com/zjc17/pprof-web" 76 | - "--label=org.opencontainers.image.version={{ .Version }}" 77 | - "--label=org.opencontainers.image.created={{ .Date }}" 78 | - "--label=org.opencontainers.image.revision={{ .FullCommit }}" 79 | - "--label=org.opencontainers.image.licenses=Apache-v2" 80 | 81 | - image_templates: 82 | - "lovecho/pprof-web:linux-armv6-{{ .Tag }}" 83 | - "lovecho/pprof-web:linux-armv6" 84 | dockerfile: docker/goreleaser.Dockerfile 85 | use: buildx 86 | goos: linux 87 | goarch: arm 88 | goarm: "6" 89 | build_flag_templates: 90 | - "--pull" 91 | - "--platform=linux/arm/v6" 92 | - "--label=org.opencontainers.image.title={{ .ProjectName }}" 93 | - "--label=org.opencontainers.image.description={{ .ProjectName }}" 94 | - "--label=org.opencontainers.image.url=https://github.com/zjc17/pprof-web" 95 | - "--label=org.opencontainers.image.source=https://github.com/zjc17/pprof-web" 96 | - "--label=org.opencontainers.image.version={{ .Version }}" 97 | - "--label=org.opencontainers.image.created={{ .Date }}" 98 | - "--label=org.opencontainers.image.revision={{ .FullCommit }}" 99 | - "--label=org.opencontainers.image.licenses=Apache-v2" 100 | 101 | 102 | docker_manifests: 103 | - name_template: "lovecho/pprof-web:{{ .Tag }}" 104 | image_templates: 105 | - "lovecho/pprof-web:linux-amd64-{{ .Tag }}" 106 | - "lovecho/pprof-web:linux-arm64-{{ .Tag }}" 107 | - "lovecho/pprof-web:linux-armv7-{{ .Tag }}" 108 | - "lovecho/pprof-web:linux-armv6-{{ .Tag }}" 109 | skip_push: "false" 110 | 111 | - name_template: "lovecho/pprof-web:latest" 112 | image_templates: 113 | - "lovecho/pprof-web:linux-amd64-{{ .Tag }}" 114 | - "lovecho/pprof-web:linux-arm64-{{ .Tag }}" 115 | - "lovecho/pprof-web:linux-armv7-{{ .Tag }}" 116 | - "lovecho/pprof-web:linux-armv6-{{ .Tag }}" 117 | skip_push: "false" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Jiachen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pprof Web Visualizer 2 | [![CodeQL](https://github.com/zjc17/pprof-web/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/zjc17/pprof-web/actions/workflows/github-code-scanning/codeql) 3 | [![Security Scan](https://github.com/zjc17/pprof-web/actions/workflows/scan.yml/badge.svg)](https://github.com/zjc17/pprof-web/actions/workflows/scan.yml) 4 | [![Release](https://github.com/zjc17/pprof-web/actions/workflows/release.yml/badge.svg)](https://github.com/zjc17/pprof-web/actions/workflows/release.yml) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/zjc17/pprof-web)](https://goreportcard.com/report/github.com/zjc17/pprof-web) 6 | [![Docker Image](https://img.shields.io/docker/pulls/lovecho/pprof-web.svg)](https://hub.docker.com/r/lovecho/pprof-web) 7 | 8 |

9 | ENGLISH | 中文文档 10 |

11 | 12 | Golang Pprof Web Visualizer is a web application that visualizes the output of the pprof tool in a web browser. 13 | 14 | The Size of the binary is < 10MB. 15 | 16 | Support on WebUI, x86, ARM, Linux and MacOS. 17 | 18 | ![preview 01](.github/preview-01.png) 19 | 20 | ![preview 02](.github/preview-02.png) 21 | 22 | ## Download 23 | 24 | Download the binaries for your system and architecture from the [release page](https://github.com/zjc17/pprof-web/releases). 25 | 26 | If you prefer docker, you can use the following command (DockerHub): 27 | 28 | ```bash 29 | docker pull lovecho/pprof-web:latest 30 | docker pull lovecho/pprof-web:latest 31 | ``` 32 | 33 | ## Usage 34 | 35 | Use default parameters to format all configuration files in the current directory: 36 | 37 | ```bash 38 | ./pprof-web 39 | ``` 40 | 41 | This will start a web server on port 8080. 42 | 43 | Then you can access it at [localhost:8080](http://localhost:8080). 44 | 45 | ### Docker Usage 46 | 47 | There is no difference between using parameters in Docker and the above, for example, we start a Web UI formatting tool service in Docker: 48 | 49 | ```bash 50 | docker run --rm -it -p 8080:8080 lovecho/pprof-web:latest 51 | ``` 52 | 53 | ## Live Demo 54 | 55 | You can access live demo at [pprof.gotool.tech](https://pprof.gotool.tech/). 56 | 57 | ### Best practice 58 | 59 | Upload the pprof result by curl inside a remote machine and then access the web UI from your local machine. 60 | 61 | ```bash 62 | # upload by curl 63 | curl -F "file=@$FILE_PATH" https://pprof.gotool.tech/submit -v 64 | ``` 65 | 66 | Then you can check the output and find something like below 67 | 68 | ```bash 69 | < HTTP/2 307 70 | < date: Thu, 27 Apr 2023 08:14:54 GMT 71 | < location: /pprof/?file_id=XXXXXXXX 72 | < vary: Accept-Encoding 73 | < cf-cache-status: DYNAMIC 74 | ``` 75 | 76 | You can then visit `https://pprof.gotool.tech/pprof/?file_id=XXXXXXXX` to view your pprof result. 77 | 78 | ## Credit 79 | 80 | Web Components: 81 | 82 | - Gin is a HTTP web framework written in Go (Golang), under [MIT license]. 83 | - https://github.com/gin-gonic/gin 84 | - Crayons - A UI Kit comprising of web components for building Freshworks Apps! - [License not specified yet] 85 | - https://github.com/freshworks/crayons -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # Pprof Web Visualizer 2 | [![CodeQL](https://github.com/zjc17/pprof-web/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/zjc17/pprof-web/actions/workflows/github-code-scanning/codeql) 3 | [![Security Scan](https://github.com/zjc17/pprof-web/actions/workflows/scan.yml/badge.svg)](https://github.com/zjc17/pprof-web/actions/workflows/scan.yml) 4 | [![Release](https://github.com/zjc17/pprof-web/actions/workflows/release.yml/badge.svg)](https://github.com/zjc17/pprof-web/actions/workflows/release.yml) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/zjc17/pprof-web)](https://goreportcard.com/report/github.com/zjc17/pprof-web) 6 | [![Docker Image](https://img.shields.io/docker/pulls/lovecho/pprof-web.svg)](https://hub.docker.com/r/lovecho/pprof-web) 7 | 8 |

9 | ENGLISH | 中文文档 10 |

11 | 12 | Golang Pprof Web Visualizer 是一个网络应用程序,可以在网络浏览器中对 pprof 工具的输出进行可视化。 13 | 14 | 二进制文件小于10MB。 15 | 16 | 支持 WebUI, x86, ARM, Linux 和 MacOS。 17 | 18 | ![预览01](.github/preview-01.png) 19 | 20 | ![预览02](.github/preview-02.png) 21 | 22 | ## 下载 23 | 24 | 从[发布页](https://github.com/zjc17/pprof-web/releases)下载适合你的系统和架构的二进制文件。 25 | 26 | 如果你喜欢docker,你可以使用以下命令(DockerHub): 27 | 28 | ```bash 29 | docker pull lovecho/pprof-web:latest 30 | docker pull lovecho/pprof-web:latest 31 | ``` 32 | 33 | ## 用法 34 | 35 | 使用默认参数来格式化当前目录下的所有配置文件: 36 | 37 | ```bash 38 | ./pprof-web 39 | ``` 40 | 41 | 这将在8080端口启动一个Web服务器。 42 | 43 | 然后你可以在[localhost:8080](http://localhost:8080)访问它。 44 | 45 | ### Docker用法 46 | 47 | 在Docker中使用参数和上面的方法没有区别,例如,我们在Docker中启动一个Web UI格式化工具服务: 48 | 49 | ```bash 50 | docker run --rm -it -p 8080:8080 lovecho/pprof-web:latest 51 | ``` 52 | 53 | ## 现场演示 54 | 55 | 你可以在 [pprof.gotool.tech](https://pprof.gotool.tech/) 访问实时演示。 56 | 57 | ### 最佳实践 58 | 59 | 在远程机器内通过curl上传pprof的结果,然后从你的本地机器访问 web UI。 60 | 61 | ```bash 62 | # 用curl上传 63 | curl -F "file=@$FILE_PATH" https://pprof.gotool.tech/submit -v 64 | ``` 65 | 66 | 然后你可以检查输出,发现如下内容 67 | 68 | ```bash 69 | < HTTP/2 307 70 | < date: Thu, 27 Apr 2023 08:14:54 GMT 71 | < location: /pprof/?file_id=XXXXXXXX 72 | < vary: Accept-Encoding 73 | < cf-cache-status: DYNAMIC 74 | ``` 75 | 76 | 然后你可以访问 `https://pprof.gotool.tech/pprof/?file_id=XXXXXXXX` 来查看你的pprof结果。 77 | 78 | 79 | ## 信用 80 | 81 | 网络组件: 82 | 83 | - Gin是一个用Go(Golang)编写的HTTP网络框架,在[MIT许可]下。 84 | - https://github.com/gin-gonic/gin 85 | - Crayons - 一个由Web组件组成的UI工具包,用于构建Freshworks的应用程序! - [还没有指定许可证] 。 86 | - https://github.com/freshworks/crayons 87 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-alpine AS base 2 | 3 | # Install dependency based on package manager 4 | FROM base AS deps 5 | WORKDIR /app 6 | COPY ../go.mod go.sum ./ 7 | RUN go mod download 8 | 9 | # Rebuild the source code only when needed 10 | FROM base AS go-builder 11 | WORKDIR /app 12 | COPY --from=deps /go/pkg/ /go/pkg/ 13 | COPY .. . 14 | 15 | RUN go build -ldflags="-X github.com/zjc17/pprof-web/internal/version.Version=1.0" -o ./pprof-web 16 | 17 | # Runner 18 | FROM alpine AS runner 19 | RUN apk add --update graphviz 20 | RUN rm -rf /var/cache/apk/* 21 | WORKDIR / 22 | COPY --from=go-builder /app/pprof-web /bin/pprof-web 23 | 24 | EXPOSE 8080 25 | ENTRYPOINT ["pprof-web"] 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docker/goreleaser.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.16 2 | RUN apk add --update graphviz 3 | RUN rm -rf /var/cache/apk/* 4 | WORKDIR / 5 | COPY pprof-web /bin/pprof-web 6 | ENTRYPOINT ["pprof-web"] -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/zjc17/pprof-web 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/gin-contrib/gzip v0.0.6 7 | github.com/gin-gonic/gin v1.9.1 8 | github.com/google/pprof v0.0.0-20230406165453-00490a63f317 9 | github.com/stretchr/testify v1.8.3 10 | ) 11 | 12 | require ( 13 | github.com/bytedance/sonic v1.9.1 // indirect 14 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 17 | github.com/gin-contrib/sse v0.1.0 // indirect 18 | github.com/go-playground/locales v0.14.1 // indirect 19 | github.com/go-playground/universal-translator v0.18.1 // indirect 20 | github.com/go-playground/validator/v10 v10.14.0 // indirect 21 | github.com/goccy/go-json v0.10.2 // indirect 22 | github.com/ianlancetaylor/demangle v0.0.0-20220517205856-0058ec4f073c // indirect 23 | github.com/json-iterator/go v1.1.12 // indirect 24 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 25 | github.com/leodido/go-urn v1.2.4 // indirect 26 | github.com/mattn/go-isatty v0.0.19 // indirect 27 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 28 | github.com/modern-go/reflect2 v1.0.2 // indirect 29 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 30 | github.com/pmezard/go-difflib v1.0.0 // indirect 31 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 32 | github.com/ugorji/go/codec v1.2.11 // indirect 33 | golang.org/x/arch v0.3.0 // indirect 34 | golang.org/x/crypto v0.9.0 // indirect 35 | golang.org/x/net v0.10.0 // indirect 36 | golang.org/x/sys v0.8.0 // indirect 37 | golang.org/x/text v0.9.0 // indirect 38 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 39 | google.golang.org/protobuf v1.30.0 // indirect 40 | gopkg.in/yaml.v3 v3.0.1 // indirect 41 | ) 42 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 2 | github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= 3 | github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 4 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 5 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 6 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 7 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= 12 | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= 13 | github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= 14 | github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= 15 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 16 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 17 | github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= 18 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= 19 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 20 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 21 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 22 | github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= 23 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 24 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 25 | github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= 26 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 27 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 28 | github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= 29 | github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= 30 | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= 31 | github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 32 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 33 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 34 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 35 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 36 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 37 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 38 | github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ= 39 | github.com/google/pprof v0.0.0-20230406165453-00490a63f317/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= 40 | github.com/ianlancetaylor/demangle v0.0.0-20220517205856-0058ec4f073c h1:rwmN+hgiyp8QyBqzdEX43lTjKAxaqCrYHaU5op5P9J8= 41 | github.com/ianlancetaylor/demangle v0.0.0-20220517205856-0058ec4f073c/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= 42 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 43 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 44 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 45 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 46 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 47 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 48 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 49 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 50 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 51 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 52 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 53 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 54 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 55 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 56 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 57 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 58 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 59 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 60 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 61 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 62 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 63 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 64 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 65 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 66 | github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= 67 | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= 68 | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= 69 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 70 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 71 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 72 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 73 | github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= 74 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 75 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 76 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 77 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 78 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 79 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 80 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 81 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 82 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 83 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 84 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 85 | github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= 86 | github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 87 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 88 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 89 | github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= 90 | github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 91 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 92 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 93 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 94 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= 95 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 96 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 97 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= 98 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 99 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 100 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= 101 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 102 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 103 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 104 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 107 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 108 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 109 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 110 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 111 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 112 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 113 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= 114 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 115 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 116 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 117 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 118 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 119 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 120 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 121 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 122 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 123 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 124 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 125 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 126 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 127 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 128 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 129 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 130 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 131 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 132 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 133 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 134 | -------------------------------------------------------------------------------- /internal/files/files.go: -------------------------------------------------------------------------------- 1 | package files 2 | 3 | import ( 4 | "fmt" 5 | "github.com/zjc17/pprof-web/pkg/random" 6 | "os" 7 | "path" 8 | ) 9 | 10 | const ( 11 | fileIDLength = 8 12 | ) 13 | 14 | func GenerateFileID() string { 15 | return random.GenerateRandomDigitalWithUpperCaseLetterCode(fileIDLength) 16 | } 17 | 18 | // GetFilePathByFileID generate file path 19 | // TODO consider the file conflict 20 | func GetFilePathByFileID(fileID string) string { 21 | return path.Join(os.TempDir(), fmt.Sprintf("pprof-web-%s", fileID)) 22 | } 23 | -------------------------------------------------------------------------------- /internal/files/files_test.go: -------------------------------------------------------------------------------- 1 | package files 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestGenerateFileID(t *testing.T) { 9 | fileID := GenerateFileID() 10 | assert.True(t, len(fileID) == fileIDLength) 11 | } 12 | -------------------------------------------------------------------------------- /internal/pprof/flags.go: -------------------------------------------------------------------------------- 1 | package pprof 2 | 3 | import ( 4 | "flag" 5 | "strings" 6 | ) 7 | 8 | // Flags Mostly copied from https://github.com/google/pprof/blob/master/internal/driver/flags.go 9 | type Flags struct { 10 | Args []string 11 | s flag.FlagSet 12 | usage []string 13 | } 14 | 15 | // Bool implements the plugin.FlagSet interface. 16 | func (p *Flags) Bool(o string, d bool, c string) *bool { 17 | return p.s.Bool(o, d, c) 18 | } 19 | 20 | // Int implements the plugin.FlagSet interface. 21 | func (p *Flags) Int(o string, d int, c string) *int { 22 | return p.s.Int(o, d, c) 23 | } 24 | 25 | // Float64 implements the plugin.FlagSet interface. 26 | func (p *Flags) Float64(o string, d float64, c string) *float64 { 27 | return p.s.Float64(o, d, c) 28 | } 29 | 30 | // String implements the plugin.FlagSet interface. 31 | func (p *Flags) String(o, d, c string) *string { 32 | return p.s.String(o, d, c) 33 | } 34 | 35 | // BoolVar implements the plugin.FlagSet interface. 36 | func (p *Flags) BoolVar(b *bool, o string, d bool, c string) { 37 | p.s.BoolVar(b, o, d, c) 38 | } 39 | 40 | // IntVar implements the plugin.FlagSet interface. 41 | func (p *Flags) IntVar(i *int, o string, d int, c string) { 42 | p.s.IntVar(i, o, d, c) 43 | } 44 | 45 | // Float64Var implements the plugin.FlagSet interface. 46 | // the value of the flag. 47 | func (p *Flags) Float64Var(f *float64, o string, d float64, c string) { 48 | p.s.Float64Var(f, o, d, c) 49 | } 50 | 51 | // StringVar implements the plugin.FlagSet interface. 52 | func (p *Flags) StringVar(s *string, o, d, c string) { 53 | p.s.StringVar(s, o, d, c) 54 | } 55 | 56 | // StringList implements the plugin.FlagSet interface. 57 | func (p *Flags) StringList(o, d, c string) *[]*string { 58 | return &[]*string{p.s.String(o, d, c)} 59 | } 60 | 61 | // AddExtraUsage implements the plugin.FlagSet interface. 62 | func (p *Flags) AddExtraUsage(eu string) { 63 | p.usage = append(p.usage, eu) 64 | } 65 | 66 | // ExtraUsage implements the plugin.FlagSet interface. 67 | func (p *Flags) ExtraUsage() string { 68 | return strings.Join(p.usage, "\n") 69 | } 70 | 71 | // Parse implements the plugin.FlagSet interface. 72 | func (p *Flags) Parse(usage func()) []string { 73 | p.s.Usage = usage 74 | _ = p.s.Parse(p.Args) 75 | args := p.s.Args() 76 | if len(args) == 0 { 77 | usage() 78 | } 79 | return args 80 | } 81 | -------------------------------------------------------------------------------- /internal/server/assets.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import _ "embed" 4 | 5 | //go:embed assets/index.html 6 | var PageDocument string 7 | -------------------------------------------------------------------------------- /internal/server/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PProf Web Interface 5 | 7 | 8 | 9 | 10 | 11 | 12 |
14 |

PProf Web Interface

15 |
16 | 24 | 25 |
26 | Upload file 27 |
28 |

Upload a file to explore it using the Pprof web interface.

29 |

See the documentation/source code.

30 |
31 | 59 | 60 | -------------------------------------------------------------------------------- /internal/server/pprof.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/google/pprof/driver" 5 | "github.com/zjc17/pprof-web/internal/pprof" 6 | "net/http" 7 | "path" 8 | ) 9 | 10 | // startPProfServer start the pprof web handler without browser 11 | func startPProfServer(filePath string) (mux *http.ServeMux, err error) { 12 | mux = http.NewServeMux() 13 | 14 | options := &driver.Options{ 15 | Flagset: &pprof.Flags{ 16 | Args: []string{"-http=localhost:0", "-no_browser", filePath}, 17 | }, 18 | HTTPServer: pprofHttpServer(mux), 19 | } 20 | 21 | if err = driver.PProf(options); err != nil { 22 | return 23 | } 24 | 25 | return 26 | } 27 | 28 | // pprofHttpServer wrap http server for pprof profile manager 29 | func pprofHttpServer(mux *http.ServeMux) func(*driver.HTTPServerArgs) error { 30 | return func(args *driver.HTTPServerArgs) error { 31 | for pattern, handler := range args.Handlers { 32 | //if pattern == "/" { 33 | // mux.Handle(pprofWebPath, handler) 34 | //} else { 35 | // mux.Handle(path.Join(pprofWebPath, pattern), handler) 36 | //} 37 | var joinedPattern string 38 | if pattern == "/" { 39 | joinedPattern = pprofWebPath 40 | } else { 41 | joinedPattern = path.Join(pprofWebPath, pattern) 42 | } 43 | mux.Handle(joinedPattern, handler) 44 | } 45 | return nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /internal/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-contrib/gzip" 6 | "github.com/gin-gonic/gin" 7 | "github.com/zjc17/pprof-web/internal/files" 8 | "log" 9 | "net/http" 10 | "net/http/pprof" 11 | ) 12 | 13 | const ( 14 | pprofWebPath = "/pprof/" 15 | // maxUploadSize 32 MiB 16 | maxUploadSize = 32 << 20 17 | ) 18 | 19 | type ( 20 | // LaunchParams for gin server 21 | LaunchParams struct { 22 | Port uint16 23 | } 24 | ) 25 | 26 | func DefaultLaunchParam() *LaunchParams { 27 | return &LaunchParams{ 28 | Port: 8080, 29 | } 30 | } 31 | 32 | func Launch(params *LaunchParams) error { 33 | gin.SetMode(gin.ReleaseMode) 34 | 35 | router := gin.Default() 36 | router.Use(gzip.Gzip(gzip.DefaultCompression)) 37 | 38 | router.GET("/", func(c *gin.Context) { 39 | c.Data(http.StatusOK, "text/html", []byte(PageDocument)) 40 | }) 41 | 42 | router.POST("/submit", func(c *gin.Context) { 43 | // check upload size 44 | if err := c.Request.ParseMultipartForm(maxUploadSize); err != nil { 45 | c.Data(http.StatusBadRequest, "text/plain; charset=UTF-8", []byte("file too large")) 46 | return 47 | } 48 | // parse file form 49 | fileHeader, err := c.FormFile("file") 50 | if err != nil { 51 | log.Printf("get file header error: %v", err) 52 | c.Status(http.StatusBadRequest) 53 | return 54 | } 55 | // store file into tmp path 56 | fileID := files.GenerateFileID() 57 | filePath := files.GetFilePathByFileID(fileID) 58 | if err := c.SaveUploadedFile(fileHeader, filePath); err != nil { 59 | log.Printf("save file error: %v", err) 60 | c.Status(http.StatusInternalServerError) 61 | return 62 | } 63 | // use pprof to analyze 64 | c.Redirect(http.StatusTemporaryRedirect, pprofWebPath+"?file_id="+fileID) 65 | }) 66 | router.Any(pprofWebPath+"*pprof-path", func(c *gin.Context) { 67 | fileID := c.Query("file_id") 68 | filePath := files.GetFilePathByFileID(fileID) 69 | if fileID == "" { 70 | c.Redirect(http.StatusTemporaryRedirect, "/") 71 | return 72 | } 73 | mux, err := startPProfServer(filePath) 74 | if err != nil { 75 | log.Printf("start pprof server error: %v", err) 76 | c.Status(http.StatusInternalServerError) 77 | return 78 | } 79 | mux.ServeHTTP(c.Writer, c.Request) 80 | }) 81 | RegisterDebugRouter(router) 82 | return router.Run(fmt.Sprintf(":%d", params.Port)) 83 | } 84 | 85 | func RegisterDebugRouter(router *gin.Engine) { 86 | wrapHandler := func(handler func(w http.ResponseWriter, r *http.Request)) gin.HandlerFunc { 87 | return func(c *gin.Context) { 88 | handler(c.Writer, c.Request) 89 | } 90 | } 91 | router.Any("/debug/pprof/", wrapHandler(pprof.Index)) 92 | router.Any("/debug/pprof/cmdline", wrapHandler(pprof.Cmdline)) 93 | router.Any("/debug/pprof/profile", wrapHandler(pprof.Profile)) 94 | router.Any("/debug/pprof/symbol", wrapHandler(pprof.Symbol)) 95 | router.Any("/debug/pprof/trace", wrapHandler(pprof.Trace)) 96 | } 97 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // Version is the current version of the pprof web tool. 4 | // inject by -ldflags="-X github.com/zjc17/pprof-web/internal/version.Version=1.0" 5 | var Version = "0.1" 6 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/zjc17/pprof-web/internal/server" 6 | "github.com/zjc17/pprof-web/internal/version" 7 | "log" 8 | ) 9 | 10 | func main() { 11 | fmt.Printf("pprof web %s\n\n", version.Version) 12 | 13 | launchParam := server.DefaultLaunchParam() 14 | if err := server.Launch(launchParam); err != nil { 15 | log.Fatal(err) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/random/random.go: -------------------------------------------------------------------------------- 1 | package random 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | func GenerateRandomDigitalWithUpperCaseLetterCode(length int) string { 9 | const charset = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 10 | return generateRandomCode(charset, length) 11 | } 12 | 13 | func generateRandomCode(charset string, length int) string { 14 | random := rand.New(rand.NewSource(time.Now().UnixNano())) 15 | b := make([]byte, length) 16 | for i := range b { 17 | b[i] = charset[random.Intn(len(charset))] 18 | } 19 | return string(b) 20 | } 21 | --------------------------------------------------------------------------------