mirror of https://github.com/knative/caching.git
170 lines
3.8 KiB
Go
170 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"time"
|
|
|
|
vegeta "github.com/tsenart/vegeta/lib"
|
|
)
|
|
|
|
const reportUsage = `Usage: vegeta report [options] [<file>...]
|
|
|
|
Outputs a report of attack results.
|
|
|
|
Arguments:
|
|
<file> A file with vegeta attack results encoded with one of
|
|
the supported encodings (gob | json | csv) [default: stdin]
|
|
|
|
Options:
|
|
--type Which report type to generate (text | json | hist[buckets] | hdrplot).
|
|
[default: text]
|
|
|
|
--every Write the report to --output at every given interval (e.g 100ms)
|
|
The default of 0 means the report will only be written after
|
|
all results have been processed. [default: 0]
|
|
|
|
--output Output file [default: stdout]
|
|
|
|
Examples:
|
|
echo "GET http://:80" | vegeta attack -rate=10/s > results.gob
|
|
echo "GET http://:80" | vegeta attack -rate=100/s | vegeta encode > results.json
|
|
vegeta report results.*
|
|
`
|
|
|
|
func reportCmd() command {
|
|
fs := flag.NewFlagSet("vegeta report", flag.ExitOnError)
|
|
typ := fs.String("type", "text", "Report type to generate [text, json, hist[buckets], hdrplot]")
|
|
every := fs.Duration("every", 0, "Report interval")
|
|
output := fs.String("output", "stdout", "Output file")
|
|
buckets := fs.String("buckets", "", "Histogram buckets, e.g.: \"[0,1ms,10ms]\"")
|
|
|
|
fs.Usage = func() {
|
|
fmt.Fprintln(os.Stderr, reportUsage)
|
|
}
|
|
|
|
return command{fs, func(args []string) error {
|
|
fs.Parse(args)
|
|
files := fs.Args()
|
|
if len(files) == 0 {
|
|
files = append(files, "stdin")
|
|
}
|
|
return report(files, *typ, *output, *every, *buckets)
|
|
}}
|
|
}
|
|
|
|
func report(files []string, typ, output string, every time.Duration, bucketsStr string) error {
|
|
if len(typ) < 4 {
|
|
return fmt.Errorf("invalid report type: %s", typ)
|
|
}
|
|
|
|
dec, mc, err := decoder(files)
|
|
defer mc.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out, err := file(output, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
var (
|
|
rep vegeta.Reporter
|
|
report vegeta.Report
|
|
)
|
|
|
|
switch typ {
|
|
case "plot":
|
|
return fmt.Errorf("The plot reporter has been deprecated and succeeded by the vegeta plot command")
|
|
case "text":
|
|
var m vegeta.Metrics
|
|
rep, report = vegeta.NewTextReporter(&m), &m
|
|
case "json":
|
|
var m vegeta.Metrics
|
|
if bucketsStr != "" {
|
|
m.Histogram = &vegeta.Histogram{}
|
|
if err := m.Histogram.Buckets.UnmarshalText([]byte(bucketsStr)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
rep, report = vegeta.NewJSONReporter(&m), &m
|
|
case "hdrplot":
|
|
var m vegeta.Metrics
|
|
rep, report = vegeta.NewHDRHistogramPlotReporter(&m), &m
|
|
default:
|
|
switch {
|
|
case strings.HasPrefix(typ, "hist"):
|
|
var hist vegeta.Histogram
|
|
if bucketsStr == "" { // Old way
|
|
if len(typ) < 6 {
|
|
return fmt.Errorf("bad buckets: '%s'", typ[4:])
|
|
}
|
|
bucketsStr = typ[4:]
|
|
}
|
|
if err := hist.Buckets.UnmarshalText([]byte(bucketsStr)); err != nil {
|
|
return err
|
|
}
|
|
rep, report = vegeta.NewHistogramReporter(&hist), &hist
|
|
default:
|
|
return fmt.Errorf("unknown report type: %q", typ)
|
|
}
|
|
}
|
|
|
|
sigch := make(chan os.Signal, 1)
|
|
signal.Notify(sigch, os.Interrupt)
|
|
|
|
var ticks <-chan time.Time
|
|
if every > 0 {
|
|
ticker := time.NewTicker(every)
|
|
defer ticker.Stop()
|
|
ticks = ticker.C
|
|
}
|
|
|
|
rc, _ := report.(vegeta.Closer)
|
|
decode:
|
|
for {
|
|
select {
|
|
case <-sigch:
|
|
break decode
|
|
case <-ticks:
|
|
if err = clear(out); err != nil {
|
|
return err
|
|
} else if err = writeReport(rep, rc, out); err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
var r vegeta.Result
|
|
if err = dec.Decode(&r); err != nil {
|
|
if err == io.EOF {
|
|
break decode
|
|
}
|
|
return err
|
|
}
|
|
|
|
report.Add(&r)
|
|
}
|
|
}
|
|
|
|
return writeReport(rep, rc, out)
|
|
}
|
|
|
|
func writeReport(r vegeta.Reporter, rc vegeta.Closer, out io.Writer) error {
|
|
if rc != nil {
|
|
rc.Close()
|
|
}
|
|
return r.Report(out)
|
|
}
|
|
|
|
func clear(out io.Writer) error {
|
|
if f, ok := out.(*os.File); ok && f == os.Stdout {
|
|
return clearScreen()
|
|
}
|
|
return nil
|
|
}
|