Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prometheus output format #308

Merged
merged 9 commits into from
Sep 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/ghz/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ var (

isFormatSet = false
format = kingpin.Flag("format", "Output format. One of: summary, csv, json, pretty, html, influx-summary, influx-details. Default is summary.").
Short('O').Default("summary").PlaceHolder(" ").IsSetByUser(&isFormatSet).Enum("summary", "csv", "json", "pretty", "html", "influx-summary", "influx-details")
Short('O').Default("summary").PlaceHolder(" ").IsSetByUser(&isFormatSet).Enum("summary", "csv", "json", "pretty", "html", "influx-summary", "influx-details", "prometheus")

isSkipFirstSet = false
skipFirst = kingpin.Flag("skipFirst", "Skip the first X requests when doing the results tally.").
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ require (
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mfridman/tparse v0.8.3
github.com/pkg/errors v0.9.1
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4
github.com/prometheus/common v0.4.0
github.com/rakyll/statik v0.1.6
github.com/stretchr/testify v1.6.1
go.uber.org/multierr v1.3.0
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mfridman/tparse v0.8.3 h1:DnjEnBXdlUJPo8ShfNPasu7m52iI1ETiST5RvS6b0c4=
github.com/mfridman/tparse v0.8.3/go.mod h1:LzZWLkqcQrOfgvqZn7LOSBzgZwWnqI5NQsfgQVOT1o8=
Expand Down Expand Up @@ -378,9 +379,11 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
Expand Down
203 changes: 203 additions & 0 deletions printer/influx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package printer

import (
"encoding/json"
"fmt"
"strings"
)

func (rp *ReportPrinter) printInfluxLine() error {
measurement := "ghz_run"
tags := rp.getInfluxTags(true)
fields := rp.getInfluxFields()
timestamp := rp.Report.Date.UnixNano()
if timestamp < 0 {
timestamp = 0
}

if _, err := fmt.Fprintf(rp.Out, "%v,%v %v %v", measurement, tags, fields, timestamp); err != nil {
return err
}

return nil
}

func (rp *ReportPrinter) printInfluxDetails() error {
measurement := "ghz_detail"
commonTags := rp.getInfluxTags(false)

for _, v := range rp.Report.Details {
values := make([]string, 3)
values[0] = fmt.Sprintf("latency=%v", v.Latency.Nanoseconds())
values[1] = fmt.Sprintf(`error="%v"`, cleanInfluxString(v.Error))
values[2] = fmt.Sprintf(`status="%v"`, v.Status)

tags := commonTags

if v.Error != "" {
tags = tags + ",hasError=true"
} else {
tags = tags + ",hasError=false"
}

timestamp := v.Timestamp.UnixNano()

fields := strings.Join(values, ",")

if _, err := fmt.Fprintf(rp.Out, "%v,%v %v %v\n", measurement, tags, fields, timestamp); err != nil {
return err
}
}
return nil
}

func (rp *ReportPrinter) getInfluxTags(addErrors bool) string {
s := make([]string, 0, 10)

if rp.Report.Name != "" {
s = append(s, fmt.Sprintf(`name="%v"`, cleanInfluxString(strings.TrimSpace(rp.Report.Name))))
}

options := rp.Report.Options

if options.Proto != "" {
s = append(s, fmt.Sprintf(`proto="%v"`, options.Proto))
} else if options.Protoset != "" {
s = append(s, fmt.Sprintf(`Protoset="%v"`, options.Protoset))
}

s = append(s, fmt.Sprintf(`call="%v"`, options.Call))
s = append(s, fmt.Sprintf(`host="%v"`, options.Host))
s = append(s, fmt.Sprintf("n=%v", options.Total))

if options.CSchedule == "const" {
s = append(s, fmt.Sprintf("c=%v", options.Concurrency))
} else {
s = append(s, fmt.Sprintf("concurrency-schedule=%v", options.CSchedule))
s = append(s, fmt.Sprintf("concurrency-start=%v", options.CStart))
s = append(s, fmt.Sprintf("concurrency-end=%v", options.CEnd))
s = append(s, fmt.Sprintf("concurrency-step=%v", options.CStep))
s = append(s, fmt.Sprintf("concurrency-step-duration=%v", options.CStepDuration))
s = append(s, fmt.Sprintf("concurrency-max-duration=%v", options.CMaxDuration))
}

if options.LoadSchedule == "const" {
s = append(s, fmt.Sprintf("rps=%v", options.RPS))
} else {
s = append(s, fmt.Sprintf("load-schedule=%v", options.LoadSchedule))
s = append(s, fmt.Sprintf("load-start=%v", options.LoadStart))
s = append(s, fmt.Sprintf("load-end=%v", options.LoadEnd))
s = append(s, fmt.Sprintf("load-step=%v", options.LoadStep))
s = append(s, fmt.Sprintf("load-step-duration=%v", options.LoadStepDuration))
s = append(s, fmt.Sprintf("load-max-duration=%v", options.LoadMaxDuration))
}

s = append(s, fmt.Sprintf("z=%v", options.Duration.Nanoseconds()))
s = append(s, fmt.Sprintf("timeout=%v", options.Timeout.Seconds()))
s = append(s, fmt.Sprintf("dial_timeout=%v", options.DialTimeout.Seconds()))
s = append(s, fmt.Sprintf("keepalive=%v", options.KeepaliveTime.Seconds()))

dataStr := `""`
dataBytes, err := json.Marshal(options.Data)
if err == nil && len(dataBytes) > 0 {
dataBytes, err = json.Marshal(string(dataBytes))
if err == nil {
dataStr = string(dataBytes)
}
}

dataStr = cleanInfluxString(dataStr)

s = append(s, fmt.Sprintf("data=%s", dataStr))

mdStr := `""`
if options.Metadata != nil {
mdBytes, err := json.Marshal(options.Metadata)
if err == nil {
mdBytes, err = json.Marshal(string(mdBytes))
if err == nil {
mdStr = string(mdBytes)
}
}

mdStr = cleanInfluxString(mdStr)
}

s = append(s, fmt.Sprintf("metadata=%s", mdStr))

callTagsStr := `""`
if len(rp.Report.Tags) > 0 {
callTagsBytes, err := json.Marshal(rp.Report.Tags)
if err == nil {
callTagsBytes, err = json.Marshal(string(callTagsBytes))
if err == nil {
callTagsStr = string(callTagsBytes)
}
}

callTagsStr = cleanInfluxString(callTagsStr)
}

s = append(s, fmt.Sprintf("tags=%s", callTagsStr))

if addErrors {
errCount := 0
if len(rp.Report.ErrorDist) > 0 {
for _, v := range rp.Report.ErrorDist {
errCount += v
}
}

s = append(s, fmt.Sprintf("errors=%v", errCount))

hasErrors := false
if errCount > 0 {
hasErrors = true
}

s = append(s, fmt.Sprintf("has_errors=%v", hasErrors))
}

return strings.Join(s, ",")
}

func (rp *ReportPrinter) getInfluxFields() string {
s := make([]string, 0, 5)

s = append(s, fmt.Sprintf("count=%v", rp.Report.Count))
s = append(s, fmt.Sprintf("total=%v", rp.Report.Total.Nanoseconds()))
s = append(s, fmt.Sprintf("average=%v", rp.Report.Average.Nanoseconds()))
s = append(s, fmt.Sprintf("fastest=%v", rp.Report.Fastest.Nanoseconds()))
s = append(s, fmt.Sprintf("slowest=%v", rp.Report.Slowest.Nanoseconds()))
s = append(s, fmt.Sprintf("rps=%4.2f", rp.Report.Rps))

if len(rp.Report.LatencyDistribution) > 0 {
for _, v := range rp.Report.LatencyDistribution {
if v.Percentage == 50 {
s = append(s, fmt.Sprintf("median=%v", v.Latency.Nanoseconds()))
}

if v.Percentage == 95 {
s = append(s, fmt.Sprintf("p95=%v", v.Latency.Nanoseconds()))
}
}
}

errCount := 0
if len(rp.Report.ErrorDist) > 0 {
for _, v := range rp.Report.ErrorDist {
errCount += v
}
}

s = append(s, fmt.Sprintf("errors=%v", errCount))

return strings.Join(s, ",")
}

func cleanInfluxString(input string) string {
input = strings.Replace(input, " ", "\\ ", -1)
input = strings.Replace(input, ",", "\\,", -1)
input = strings.Replace(input, "=", "\\=", -1)
return input
}
9 changes: 6 additions & 3 deletions printer/printer_test.go → printer/influx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestPrinter_getInfluxLine(t *testing.T) {
func TestPrinter_printInfluxLine(t *testing.T) {
date := time.Now()
unixTimeNow := date.UnixNano()

Expand Down Expand Up @@ -119,8 +119,11 @@ func TestPrinter_getInfluxLine(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := ReportPrinter{Report: &tt.report}
actual := p.getInfluxLine()
buf := bytes.NewBufferString("")
p := ReportPrinter{Report: &tt.report, Out: buf}
err := p.printInfluxLine()
assert.NoError(t, err)
actual := buf.String()
assert.Equal(t, tt.expected, actual)
})
}
Expand Down
Loading