Compare commits

...

10 Commits

Author SHA1 Message Date
BoHung Chiu 036a6dfe8f change tcp to unix socket 2023-04-20 21:58:18 +08:00
dependabot[bot] c48d821994 build(deps): bump github.com/valyala/fasthttp from 1.38.0 to 1.44.0
Bumps [github.com/valyala/fasthttp](https://github.com/valyala/fasthttp) from 1.38.0 to 1.44.0.
- [Release notes](https://github.com/valyala/fasthttp/releases)
- [Commits](https://github.com/valyala/fasthttp/compare/v1.38.0...v1.44.0)

---
updated-dependencies:
- dependency-name: github.com/valyala/fasthttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-10 13:32:46 +08:00
Florian Loch ee2b6e0864 fix: improve help strings of cli parameters 2023-03-05 16:46:20 +08:00
Florian Loch dfde9d518b feat: default to POST instead of GET when body is given 2023-03-05 16:46:20 +08:00
duncandu 68cf8809b8 Dynamically set version by goreleaser 2022-07-28 10:07:30 +08:00
duncandu 343b7510cc update version 2022-07-28 09:43:04 +08:00
Nikos Polyzotis 63c454d647 fixed jsonFormat typo 2022-07-28 09:32:42 +08:00
dependabot[bot] e8da3278cd build(deps): bump docker/login-action from 1 to 2
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-22 10:55:25 +08:00
dependabot[bot] c075d5e2d4 build(deps): bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-22 10:55:17 +08:00
dependabot[bot] 33b22c6c5b build(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-22 10:55:09 +08:00
6 changed files with 58 additions and 44 deletions

View File

@ -12,9 +12,9 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: 1.18 go-version: 1.18
- name: Cache Go modules - name: Cache Go modules
@ -30,7 +30,7 @@ jobs:
# go mod tidy # go mod tidy
# go test -v ./... # go test -v ./...
- name: Docker Login - name: Docker Login
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}

View File

@ -99,7 +99,7 @@ A high-performance HTTP benchmarking tool with real-time web UI and terminal dis
Examples: Examples:
plow http://127.0.0.1:8080/ -c 20 -n 100000 plow http://127.0.0.1:8080/ -c 20 -n 100000
plow https://httpbin.org/post -c 20 -d 5m --body @file.jsonFormat -T 'application/jsonFormat' -m POST plow https://httpbin.org/post -c 20 -d 5m --body @file.json -T 'application/json' -m POST
Flags: Flags:
--help Show context-sensitive help. --help Show context-sensitive help.

View File

@ -14,6 +14,7 @@ import (
"time" "time"
_ "embed" _ "embed"
cors "github.com/AdhityaRamadhanus/fasthttpcors" cors "github.com/AdhityaRamadhanus/fasthttpcors"
"github.com/go-echarts/go-echarts/v2/charts" "github.com/go-echarts/go-echarts/v2/charts"
"github.com/go-echarts/go-echarts/v2/components" "github.com/go-echarts/go-echarts/v2/components"
@ -42,7 +43,7 @@ function {{ .ViewID }}_sync() {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: "{{ .APIPath }}{{ .Route }}", url: "{{ .APIPath }}{{ .Route }}",
dataType: "jsonFormat", dataType: "json",
success: function (result) { success: function (result) {
let opt = goecharts_{{ .ViewID }}.getOption(); let opt = goecharts_{{ .ViewID }}.getOption();
let x = opt.xAxis[0].data; let x = opt.xAxis[0].data;
@ -141,8 +142,8 @@ func (c *Charts) newRPSView() components.Charter {
} }
type Metrics struct { type Metrics struct {
Values []interface{} `jsonFormat:"values"` Values []interface{} `json:"values"`
Time string `jsonFormat:"time"` Time string `json:"time"`
} }
type Charts struct { type Charts struct {

8
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/go-echarts/go-echarts/v2 v2.2.4 github.com/go-echarts/go-echarts/v2 v2.2.4
github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-runewidth v0.0.13 github.com/mattn/go-runewidth v0.0.13
github.com/valyala/fasthttp v1.38.0 github.com/valyala/fasthttp v1.44.0
go.uber.org/automaxprocs v1.5.1 go.uber.org/automaxprocs v1.5.1
golang.org/x/time v0.0.0-20220411224347-583f2d630306 golang.org/x/time v0.0.0-20220411224347-583f2d630306
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780 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/BurntSushi/toml v0.3.1 // indirect
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect github.com/andybalholm/brotli v1.0.4 // indirect
github.com/klauspost/compress v1.15.0 // indirect github.com/klauspost/compress v1.15.9 // indirect
github.com/nicksnyder/go-i18n v1.10.1 // indirect github.com/nicksnyder/go-i18n v1.10.1 // indirect
github.com/pelletier/go-toml v1.2.0 // indirect github.com/pelletier/go-toml v1.2.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect

17
go.sum
View File

@ -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/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 h1:SKJpdyNIyD65XjbUZjzg6SwccTNXEgmh+PlaO23g2H0=
github.com/go-echarts/go-echarts/v2 v2.2.4/go.mod h1:6TOomEztzGDVDkOSCFBq3ed7xOYfbOqhaBzD0YV771A= github.com/go-echarts/go-echarts/v2 v2.2.4/go.mod h1:6TOomEztzGDVDkOSCFBq3ed7xOYfbOqhaBzD0YV771A=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -39,22 +39,21 @@ github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 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 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.38.0 h1:yTjSSNjuDi2PPvXY2836bIwLmiTS2T4T9p1coQshpco= github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q=
github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 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 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= 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/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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-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-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-20210630005230-0f9fa26af87c/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-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

62
main.go
View File

@ -2,8 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"golang.org/x/time/rate"
"io/ioutil"
"net" "net"
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
@ -12,6 +10,8 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/time/rate"
"gopkg.in/alecthomas/kingpin.v3-unstable" "gopkg.in/alecthomas/kingpin.v3-unstable"
) )
@ -24,9 +24,13 @@ var (
seconds = kingpin.Flag("seconds", "Use seconds as time unit to print").Bool() seconds = kingpin.Flag("seconds", "Use seconds as time unit to print").Bool()
jsonFormat = kingpin.Flag("json", "Print snapshot result as JSON").Bool() jsonFormat = kingpin.Flag("json", "Print snapshot result as JSON").Bool()
body = kingpin.Flag("body", "HTTP request body, if start the body with @, the rest should be a filename to read").Short('b').String() 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() 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() methodSet = false
method = kingpin.Flag("method", "HTTP method").Action(func(_ *kingpin.ParseElement, _ *kingpin.ParseContext) error {
methodSet = true
return nil
}).Default("GET").Short('m').String()
headers = kingpin.Flag("header", "Custom HTTP headers").Short('H').PlaceHolder("K:V").Strings() headers = kingpin.Flag("header", "Custom HTTP headers").Short('H').PlaceHolder("K:V").Strings()
host = kingpin.Flag("host", "Host header").String() host = kingpin.Flag("host", "Host header").String()
contentType = kingpin.Flag("content", "Content-Type header").Short('T').String() contentType = kingpin.Flag("content", "Content-Type header").Short('T').String()
@ -34,20 +38,23 @@ var (
key = kingpin.Flag("key", "Path to the client's TLS Certificate Private Key").ExistingFile() 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() 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(":18888").String() chartsListenAddr = kingpin.Flag("listen", "Listen addr to serve Web UI").Default("test.sock").String()
timeout = kingpin.Flag("timeout", "Timeout for each http request").PlaceHolder("DURATION").Duration() timeout = kingpin.Flag("timeout", "Timeout for each http request").PlaceHolder("DURATION").Duration()
dialTimeout = kingpin.Flag("dial-timeout", "Timeout for dial addr").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() 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() respReadTimeout = kingpin.Flag("resp-timeout", "Timeout for full response reading").PlaceHolder("DURATION").Duration()
socks5 = kingpin.Flag("socks5", "Socks5 proxy").PlaceHolder("ip:port").String() 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() 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() 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() 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) { func errAndExit(msg string) {
fmt.Fprintln(os.Stderr, "plow: "+msg) fmt.Fprintln(os.Stderr, "plow: "+msg)
os.Exit(1) os.Exit(1)
@ -83,7 +90,7 @@ var CompactUsageTemplate = `{{define "FormatCommand" -}}
Examples: Examples:
plow http://127.0.0.1:8080/ -c 20 -n 100000 plow http://127.0.0.1:8080/ -c 20 -n 100000
plow https://httpbin.org/post -c 20 -d 5m --body @file.jsonFormat -T 'application/jsonFormat' -m POST plow https://httpbin.org/post -c 20 -d 5m --body @file.json -T 'application/json' -m POST
{{if .Context.Flags -}} {{if .Context.Flags -}}
{{T "Flags:"}} {{T "Flags:"}}
@ -171,7 +178,7 @@ func rateFlag(c *kingpin.Clause) (target *rateFlagValue) {
func main() { func main() {
kingpin.UsageTemplate(CompactUsageTemplate). kingpin.UsageTemplate(CompactUsageTemplate).
Version("1.2.0"). Version(version).
Author("six-ddc@github"). Author("six-ddc@github").
Resolver(kingpin.PrefixedEnvarResolver("PLOW_", ";")). Resolver(kingpin.PrefixedEnvarResolver("PLOW_", ";")).
Help = `A high-performance HTTP benchmarking tool with real-time web UI and terminal displaying` Help = `A high-performance HTTP benchmarking tool with real-time web UI and terminal displaying`
@ -193,23 +200,30 @@ func main() {
var err error var err error
var bodyBytes []byte var bodyBytes []byte
var bodyFile string var bodyFile string
if strings.HasPrefix(*body, "@") {
fileName := (*body)[1:] if *body != "" {
if _, err = os.Stat(fileName); err != nil { if strings.HasPrefix(*body, "@") {
errAndExit(err.Error()) fileName := (*body)[1:]
return if _, err = os.Stat(fileName); err != nil {
}
if *stream {
bodyFile = fileName
} else {
bodyBytes, err = ioutil.ReadFile(fileName)
if err != nil {
errAndExit(err.Error()) errAndExit(err.Error())
return 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{ clientOpt := ClientOpt{
@ -255,7 +269,7 @@ func main() {
// charts listener // charts listener
var ln net.Listener var ln net.Listener
if *chartsListenAddr != "" { if *chartsListenAddr != "" {
ln, err = net.Listen("tcp", *chartsListenAddr) ln, err = net.Listen("unix", *chartsListenAddr)
if err != nil { if err != nil {
errAndExit(err.Error()) errAndExit(err.Error())
return return