Compare commits
No commits in common. "036a6dfe8f23ef214a1819640ff4346deacef6bc" and "cf2feb0344086f573e87e1275a9a71888a5f7e3a" have entirely different histories.
036a6dfe8f
...
cf2feb0344
|
@ -12,9 +12,9 @@ jobs:
|
|||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
- name: Cache Go modules
|
||||
|
@ -30,7 +30,7 @@ jobs:
|
|||
# go mod tidy
|
||||
# go test -v ./...
|
||||
- name: Docker Login
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
|
|
|
@ -99,7 +99,7 @@ A high-performance HTTP benchmarking tool with real-time web UI and terminal dis
|
|||
Examples:
|
||||
|
||||
plow http://127.0.0.1:8080/ -c 20 -n 100000
|
||||
plow https://httpbin.org/post -c 20 -d 5m --body @file.json -T 'application/json' -m POST
|
||||
plow https://httpbin.org/post -c 20 -d 5m --body @file.jsonFormat -T 'application/jsonFormat' -m POST
|
||||
|
||||
Flags:
|
||||
--help Show context-sensitive help.
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"time"
|
||||
|
||||
_ "embed"
|
||||
|
||||
cors "github.com/AdhityaRamadhanus/fasthttpcors"
|
||||
"github.com/go-echarts/go-echarts/v2/charts"
|
||||
"github.com/go-echarts/go-echarts/v2/components"
|
||||
|
@ -43,7 +42,7 @@ function {{ .ViewID }}_sync() {
|
|||
$.ajax({
|
||||
type: "GET",
|
||||
url: "{{ .APIPath }}{{ .Route }}",
|
||||
dataType: "json",
|
||||
dataType: "jsonFormat",
|
||||
success: function (result) {
|
||||
let opt = goecharts_{{ .ViewID }}.getOption();
|
||||
let x = opt.xAxis[0].data;
|
||||
|
@ -142,8 +141,8 @@ func (c *Charts) newRPSView() components.Charter {
|
|||
}
|
||||
|
||||
type Metrics struct {
|
||||
Values []interface{} `json:"values"`
|
||||
Time string `json:"time"`
|
||||
Values []interface{} `jsonFormat:"values"`
|
||||
Time string `jsonFormat:"time"`
|
||||
}
|
||||
|
||||
type Charts struct {
|
||||
|
|
8
go.mod
8
go.mod
|
@ -8,7 +8,7 @@ require (
|
|||
github.com/go-echarts/go-echarts/v2 v2.2.4
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/mattn/go-runewidth v0.0.13
|
||||
github.com/valyala/fasthttp v1.44.0
|
||||
github.com/valyala/fasthttp v1.38.0
|
||||
go.uber.org/automaxprocs v1.5.1
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
||||
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780
|
||||
|
@ -18,13 +18,13 @@ require (
|
|||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/klauspost/compress v1.15.0 // indirect
|
||||
github.com/nicksnyder/go-i18n v1.10.1 // indirect
|
||||
github.com/pelletier/go-toml v1.2.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
17
go.sum
17
go.sum
|
@ -13,8 +13,8 @@ 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/go-echarts/go-echarts/v2 v2.2.4 h1:SKJpdyNIyD65XjbUZjzg6SwccTNXEgmh+PlaO23g2H0=
|
||||
github.com/go-echarts/go-echarts/v2 v2.2.4/go.mod h1:6TOomEztzGDVDkOSCFBq3ed7xOYfbOqhaBzD0YV771A=
|
||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
|
||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
@ -39,21 +39,22 @@ github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q=
|
||||
github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
|
||||
github.com/valyala/fasthttp v1.38.0 h1:yTjSSNjuDi2PPvXY2836bIwLmiTS2T4T9p1coQshpco=
|
||||
github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
|
||||
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
62
main.go
62
main.go
|
@ -2,6 +2,8 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/time/rate"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
|
@ -10,8 +12,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
|
@ -24,13 +24,9 @@ var (
|
|||
seconds = kingpin.Flag("seconds", "Use seconds as time unit to print").Bool()
|
||||
jsonFormat = kingpin.Flag("json", "Print snapshot result as JSON").Bool()
|
||||
|
||||
body = kingpin.Flag("body", "HTTP request body, if body starts with '@' the rest will be considered a file's path from which to read the actual body content").Short('b').String()
|
||||
stream = kingpin.Flag("stream", "Specify whether to stream file specified by '--body @file' using chunked encoding or to read into memory").Default("false").Bool()
|
||||
methodSet = false
|
||||
method = kingpin.Flag("method", "HTTP method").Action(func(_ *kingpin.ParseElement, _ *kingpin.ParseContext) error {
|
||||
methodSet = true
|
||||
return nil
|
||||
}).Default("GET").Short('m').String()
|
||||
body = kingpin.Flag("body", "HTTP request body, if start the body with @, the rest should be a filename to read").Short('b').String()
|
||||
stream = kingpin.Flag("stream", "Specify whether to stream file specified by '--body @file' using chunked encoding or to read into memory").Default("false").Bool()
|
||||
method = kingpin.Flag("method", "HTTP method").Default("GET").Short('m').String()
|
||||
headers = kingpin.Flag("header", "Custom HTTP headers").Short('H').PlaceHolder("K:V").Strings()
|
||||
host = kingpin.Flag("host", "Host header").String()
|
||||
contentType = kingpin.Flag("content", "Content-Type header").Short('T').String()
|
||||
|
@ -38,23 +34,20 @@ var (
|
|||
key = kingpin.Flag("key", "Path to the client's TLS Certificate Private Key").ExistingFile()
|
||||
insecure = kingpin.Flag("insecure", "Controls whether a client verifies the server's certificate chain and host name").Short('k').Bool()
|
||||
|
||||
chartsListenAddr = kingpin.Flag("listen", "Listen addr to serve Web UI").Default("test.sock").String()
|
||||
chartsListenAddr = kingpin.Flag("listen", "Listen addr to serve Web UI").Default(":18888").String()
|
||||
timeout = kingpin.Flag("timeout", "Timeout for each http request").PlaceHolder("DURATION").Duration()
|
||||
dialTimeout = kingpin.Flag("dial-timeout", "Timeout for dial addr").PlaceHolder("DURATION").Duration()
|
||||
reqWriteTimeout = kingpin.Flag("req-timeout", "Timeout for full request writing").PlaceHolder("DURATION").Duration()
|
||||
respReadTimeout = kingpin.Flag("resp-timeout", "Timeout for full response reading").PlaceHolder("DURATION").Duration()
|
||||
socks5 = kingpin.Flag("socks5", "Socks5 proxy").PlaceHolder("ip:port").String()
|
||||
|
||||
autoOpenBrowser = kingpin.Flag("auto-open-browser", "Specify whether auto open browser to show web charts").Bool()
|
||||
autoOpenBrowser = kingpin.Flag("auto-open-browser", "Specify whether auto open browser to show Web charts").Bool()
|
||||
clean = kingpin.Flag("clean", "Clean the histogram bar once its finished. Default is true").Default("true").NegatableBool()
|
||||
summary = kingpin.Flag("summary", "Only print the summary without realtime reports").Default("false").Bool()
|
||||
pprofAddr = kingpin.Flag("pprof", "Enable pprof at special address").Hidden().String()
|
||||
url = kingpin.Arg("url", "Request url").Required().String()
|
||||
url = kingpin.Arg("url", "request url").Required().String()
|
||||
)
|
||||
|
||||
// dynamically set by GoReleaser
|
||||
var version = "dev"
|
||||
|
||||
func errAndExit(msg string) {
|
||||
fmt.Fprintln(os.Stderr, "plow: "+msg)
|
||||
os.Exit(1)
|
||||
|
@ -90,7 +83,7 @@ var CompactUsageTemplate = `{{define "FormatCommand" -}}
|
|||
Examples:
|
||||
|
||||
plow http://127.0.0.1:8080/ -c 20 -n 100000
|
||||
plow https://httpbin.org/post -c 20 -d 5m --body @file.json -T 'application/json' -m POST
|
||||
plow https://httpbin.org/post -c 20 -d 5m --body @file.jsonFormat -T 'application/jsonFormat' -m POST
|
||||
|
||||
{{if .Context.Flags -}}
|
||||
{{T "Flags:"}}
|
||||
|
@ -178,7 +171,7 @@ func rateFlag(c *kingpin.Clause) (target *rateFlagValue) {
|
|||
|
||||
func main() {
|
||||
kingpin.UsageTemplate(CompactUsageTemplate).
|
||||
Version(version).
|
||||
Version("1.2.0").
|
||||
Author("six-ddc@github").
|
||||
Resolver(kingpin.PrefixedEnvarResolver("PLOW_", ";")).
|
||||
Help = `A high-performance HTTP benchmarking tool with real-time web UI and terminal displaying`
|
||||
|
@ -200,30 +193,23 @@ func main() {
|
|||
var err error
|
||||
var bodyBytes []byte
|
||||
var bodyFile string
|
||||
|
||||
if *body != "" {
|
||||
if strings.HasPrefix(*body, "@") {
|
||||
fileName := (*body)[1:]
|
||||
if _, err = os.Stat(fileName); err != nil {
|
||||
if strings.HasPrefix(*body, "@") {
|
||||
fileName := (*body)[1:]
|
||||
if _, err = os.Stat(fileName); err != nil {
|
||||
errAndExit(err.Error())
|
||||
return
|
||||
}
|
||||
if *stream {
|
||||
bodyFile = fileName
|
||||
} else {
|
||||
bodyBytes, err = ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
errAndExit(err.Error())
|
||||
return
|
||||
}
|
||||
if *stream {
|
||||
bodyFile = fileName
|
||||
} else {
|
||||
bodyBytes, err = os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
errAndExit(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bodyBytes = []byte(*body)
|
||||
}
|
||||
|
||||
if !methodSet {
|
||||
*method = "POST"
|
||||
}
|
||||
} else if *body != "" {
|
||||
bodyBytes = []byte(*body)
|
||||
}
|
||||
|
||||
clientOpt := ClientOpt{
|
||||
|
@ -269,7 +255,7 @@ func main() {
|
|||
// charts listener
|
||||
var ln net.Listener
|
||||
if *chartsListenAddr != "" {
|
||||
ln, err = net.Listen("unix", *chartsListenAddr)
|
||||
ln, err = net.Listen("tcp", *chartsListenAddr)
|
||||
if err != nil {
|
||||
errAndExit(err.Error())
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue