Skip to content

Commit a43f734

Browse files
committed
Initial version
1 parent 751b69a commit a43f734

File tree

658 files changed

+289495
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

658 files changed

+289495
-1
lines changed

.github/workflows/build.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: build
2+
3+
on:
4+
push:
5+
branches:
6+
- '*'
7+
pull_request:
8+
branches:
9+
- '*'
10+
11+
jobs:
12+
build:
13+
strategy:
14+
matrix:
15+
go-version: [1.17.x]
16+
os: [ubuntu-latest]
17+
runs-on: ${{ matrix.os }}
18+
steps:
19+
- uses: actions/checkout@master
20+
with:
21+
fetch-depth: 1
22+
- name: Install Go
23+
uses: actions/setup-go@v2
24+
with:
25+
go-version: ${{ matrix.go-version }}
26+
- name: Make all
27+
run: make all

.github/workflows/publish.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: publish
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
jobs:
9+
publish:
10+
strategy:
11+
matrix:
12+
go-version: [ 1.15.x ]
13+
os: [ ubuntu-latest ]
14+
runs-on: ${{ matrix.os }}
15+
steps:
16+
- uses: actions/checkout@master
17+
with:
18+
fetch-depth: 1
19+
- name: Install Go
20+
uses: actions/setup-go@v2
21+
with:
22+
go-version: ${{ matrix.go-version }}
23+
- name: Make all
24+
run: make all
25+
- name: Upload release binaries
26+
uses: alexellis/[email protected]
27+
env:
28+
GITHUB_TOKEN: ${{ github.token }}
29+
with:
30+
asset_paths: '["./bin/pprof-exporter*"]'

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*.dll
55
*.so
66
*.dylib
7+
bin
8+
pprof-exporter*
79

810
# Test binary, built with `go test -c`
911
*.test
@@ -13,3 +15,12 @@
1315

1416
# Dependency directories (remove the comment below to include it)
1517
# vendor/
18+
19+
# IDE
20+
.idea
21+
.DS_Store
22+
23+
*.gz
24+
*.pb
25+
*.txt
26+
*.json

LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
Apache License
23
Version 2.0, January 2004
34
http://www.apache.org/licenses/

Makefile

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
GOCMD=GO111MODULE=on go
2+
GOFMT=$(GOCMD) fmt
3+
4+
# Build-time GIT variables
5+
ifeq ($(GIT_COMMIT),)
6+
GIT_COMMIT:=$(shell git rev-parse HEAD)
7+
endif
8+
9+
ifeq ($(GIT_VERSION),)
10+
GIT_VERSION:=$(shell git describe --tags --dirty)
11+
endif
12+
13+
LDFLAGS := "-s -w -X github.com/codeperfio/pprof-exporter/cmd.Version=$(GIT_VERSION) -X github.com/codeperfio/pprof-exporter/cmd.GitCommit=$(GIT_COMMIT)"
14+
export GO111MODULE=on
15+
SOURCE_DIRS = cmd main.go
16+
17+
.PHONY: all
18+
all: dist hash
19+
20+
.PHONY: gofmt
21+
gofmt:
22+
@test -z $(shell gofmt -l -s $(SOURCE_DIRS) ./ | tee /dev/stderr) || (echo "[WARN] Fix formatting issues with 'make fmt'" && exit 1)
23+
24+
fmt:
25+
$(GOFMT) ./...
26+
27+
lint:
28+
$(GOGET) github.com/golangci/golangci-lint/cmd/golangci-lint
29+
golangci-lint run
30+
31+
.PHONY: dist
32+
dist:
33+
mkdir -p bin/
34+
rm -rf bin/pprof-exporter*
35+
CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -mod=vendor -a -ldflags $(LDFLAGS) -installsuffix cgo -o bin/pprof-exporter
36+
CGO_ENABLED=0 GOARCH=amd64 GOOS=darwin go build -mod=vendor -a -ldflags $(LDFLAGS) -installsuffix cgo -o bin/pprof-exporter-darwin
37+
GOARM=6 GOARCH=arm CGO_ENABLED=0 GOOS=linux go build -mod=vendor -a -ldflags $(LDFLAGS) -installsuffix cgo -o bin/pprof-exporter-armhf
38+
GOARCH=arm64 CGO_ENABLED=0 GOOS=linux go build -mod=vendor -a -ldflags $(LDFLAGS) -installsuffix cgo -o bin/pprof-exporter-arm64
39+
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -mod=vendor -a -ldflags $(LDFLAGS) -installsuffix cgo -o bin/pprof-exporter.exe
40+
41+
.PHONY: hash
42+
hash:
43+
rm -rf bin/*.sha256 && ./scripts/hash.sh

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# pprof-exporter
2-
Go's .profile free exporter to codeperf.io
2+
Export and persist Go profiling data locally, or into https://codeperf.io for FREE.
3+
4+
5+
curl -sLS https://raw.githubusercontent.com/codeperfio/pprof-exporter/master/get.sh | sh
6+
sudo install pprof-exporter /usr/local/bin/
7+
8+
pprof-exporter --help

cmd/export.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"encoding/json"
7+
"fmt"
8+
"github.com/google/pprof/driver"
9+
"github.com/spf13/cobra"
10+
"io"
11+
"io/ioutil"
12+
"log"
13+
"net/http"
14+
"os"
15+
"strings"
16+
)
17+
18+
// TextItem holds a single text report entry.
19+
type TextItem struct {
20+
Symbol string `json:"symbol"`
21+
Flat string `json:"flat%"`
22+
Cum string `json:"cum%"`
23+
}
24+
25+
// TextReport holds a list of text items from the report and a list
26+
// of labels that describe the report.
27+
type TextReport struct {
28+
Items []TextItem `json:"data"`
29+
TotalRows int `json:"totalRows"`
30+
TotalPages int `json:"totalPages"`
31+
Labels []string `json:"labels"`
32+
}
33+
34+
func exportLogic() func(cmd *cobra.Command, args []string) {
35+
return func(cmd *cobra.Command, args []string) {
36+
if len(args) != 1 {
37+
log.Fatalf("Exactly one profile file is required")
38+
}
39+
for _, granularity := range []string{"lines", "functions"} {
40+
err, report := generateTextReports(granularity, args[0])
41+
if err == nil {
42+
var w io.Writer
43+
// open output file
44+
if local {
45+
fo, err := os.Create(localFilename)
46+
if err != nil {
47+
panic(err)
48+
}
49+
// close fo on exit and check for its returned error
50+
defer func() {
51+
if err := fo.Close(); err != nil {
52+
panic(err)
53+
}
54+
}()
55+
// make a write buffer
56+
w = bufio.NewWriter(fo)
57+
enc := json.NewEncoder(w)
58+
err = enc.Encode(report)
59+
if err != nil {
60+
log.Fatalf("Unable to export the profile to local json. Error: %v", err)
61+
} else {
62+
log.Printf("Succesfully exported profile to local file %s", localFilename)
63+
}
64+
} else {
65+
postBody, err := json.Marshal(report)
66+
if err != nil {
67+
log.Fatalf("An Error Occured %v", err)
68+
}
69+
responseBody := bytes.NewBuffer(postBody)
70+
endPoint := fmt.Sprintf("%s/v1/gh/%s/%s/commit/%s/bench/%s/cpu/%s", codeperfUrl, gitOrg, gitRepo, gitCommit, bench, granularity)
71+
resp, err := http.Post(endPoint, "application/json", responseBody)
72+
//Handle Error
73+
if err != nil {
74+
log.Fatalf("An Error Occured %v", err)
75+
}
76+
defer resp.Body.Close()
77+
//Read the response body
78+
body, err := ioutil.ReadAll(resp.Body)
79+
if err != nil {
80+
log.Fatalln(err)
81+
}
82+
sb := string(body)
83+
log.Printf(sb)
84+
}
85+
} else {
86+
log.Fatal(err)
87+
}
88+
}
89+
90+
}
91+
}
92+
93+
func generateTextReports(granularity string, input string) (err error, report TextReport) {
94+
f := baseFlags()
95+
96+
// Read the profile from the encoded protobuf
97+
outputTempFile, err := ioutil.TempFile("", "profile_output")
98+
if err != nil {
99+
log.Fatalf("cannot create tempfile: %v", err)
100+
}
101+
defer os.Remove(outputTempFile.Name())
102+
defer outputTempFile.Close()
103+
f.strings["output"] = outputTempFile.Name()
104+
f.bools["text"] = true
105+
f.bools[granularity] = true
106+
f.args = []string{
107+
input,
108+
}
109+
reader := bufio.NewReader(os.Stdin)
110+
options := &driver.Options{
111+
Flagset: f,
112+
UI: &UI{r: reader},
113+
}
114+
115+
if err = driver.PProf(options); err != nil {
116+
log.Fatalf("cannot read pprof profile from %s. Error: %v", input, err)
117+
return
118+
}
119+
120+
file, err := os.Open(outputTempFile.Name())
121+
if err != nil {
122+
log.Fatal(err)
123+
}
124+
defer file.Close()
125+
r := bufio.NewReader(file)
126+
benchTypeStr, _, _ := r.ReadLine()
127+
benchDurationStr, _, _ := r.ReadLine()
128+
benchNodesDetails, _, _ := r.ReadLine()
129+
benchNodesDropDetails, _, e := r.ReadLine()
130+
report.Labels = append(report.Labels, string(benchTypeStr))
131+
report.Labels = append(report.Labels, string(benchDurationStr))
132+
report.Labels = append(report.Labels, string(benchNodesDetails))
133+
report.Labels = append(report.Labels, string(benchNodesDropDetails))
134+
// ignore dropped
135+
r.ReadLine()
136+
// ignore header
137+
r.ReadLine()
138+
var b []byte
139+
for e == nil {
140+
b, _, e = r.ReadLine()
141+
s := strings.TrimSpace(string(b))
142+
// ignore flat
143+
ns := strings.SplitN(s, " ", 2)
144+
if len(ns) < 2 {
145+
continue
146+
}
147+
s = strings.TrimSpace(ns[1])
148+
// read flat%
149+
ns = strings.SplitN(s, " ", 2)
150+
flatPercent := ns[0]
151+
s = strings.TrimSpace(ns[1])
152+
// ignore sum
153+
ns = strings.SplitN(s, " ", 2)
154+
s = strings.TrimSpace(ns[1])
155+
// ignore cum
156+
ns = strings.SplitN(s, " ", 2)
157+
s = strings.TrimSpace(ns[1])
158+
// read cum%
159+
ns = strings.SplitN(s, " ", 2)
160+
cumPercent := ns[0]
161+
symbol := strings.TrimSpace(ns[1])
162+
report.Items = append(report.Items, TextItem{
163+
Symbol: symbol,
164+
Flat: flatPercent,
165+
Cum: cumPercent,
166+
})
167+
}
168+
report.TotalPages = 1
169+
report.TotalRows = len(report.Items)
170+
return
171+
}

0 commit comments

Comments
 (0)