internal/benchrunner/runners/pipeline/format.go (98 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
package pipeline
import (
"encoding/json"
"encoding/xml"
"fmt"
"strings"
"time"
"github.com/jedib0t/go-pretty/table"
"github.com/jedib0t/go-pretty/text"
)
const (
// ReportFormatHuman reports benchmark results in a human-readable format
ReportFormatHuman Format = "human"
// ReportFormatJSON reports benchmark results in the json format
ReportFormatJSON Format = "json"
// ReportFormatXUnit reports benchmark results in the xUnit format
ReportFormatXUnit Format = "xUnit"
)
// Format represents a benchmark report format
type Format string
// FormatResult delegates formatting of benchmark results to the registered benchmark report formatter.
func formatResult(name Format, result *BenchmarkResult) (report []byte, err error) {
switch name {
case ReportFormatHuman:
return reportHumanFormat(result), nil
case ReportFormatJSON:
return reportJSONFormat(result)
case ReportFormatXUnit:
return reportXUnitFormat(result)
}
return nil, fmt.Errorf("unknown format: %s", name)
}
func reportHumanFormat(b *BenchmarkResult) []byte {
var report strings.Builder
if len(b.Parameters) > 0 {
report.WriteString(renderBenchmarkTable("parameters", b.Parameters) + "\n")
}
for _, t := range b.Tests {
report.WriteString(renderBenchmarkTable(t.Name, t.Results) + "\n")
}
return []byte(report.String())
}
func renderBenchmarkTable(title string, values []BenchmarkValue) string {
t := table.NewWriter()
t.SetStyle(table.StyleRounded)
t.SetTitle(title)
t.SetColumnConfigs([]table.ColumnConfig{
{
Number: 2,
Align: text.AlignRight,
},
})
for _, r := range values {
t.AppendRow(table.Row{r.Name, r.String()})
}
return t.Render()
}
func reportJSONFormat(b *BenchmarkResult) ([]byte, error) {
// Filter out detailed benchmarks. These add too much information for the
// aggregated nature of the reports, creating a lot of noise in Jenkins.
var benchmarks []BenchmarkTest
for _, t := range b.Tests {
if !t.Detailed {
benchmarks = append(benchmarks, t)
}
}
b.Tests = benchmarks
out, err := json.MarshalIndent(b, "", " ")
if err != nil {
return nil, fmt.Errorf("unable to format benchmark results as json: %w", err)
}
return out, nil
}
func reportXUnitFormat(b *BenchmarkResult) ([]byte, error) {
// Filter out detailed benchmarks. These add too much information for the
// aggregated nature of xUnit reports, creating a lot of noise in Jenkins.
var benchmarks []BenchmarkTest
for _, t := range b.Tests {
if !t.Detailed {
benchmarks = append(benchmarks, t)
}
}
b.Tests = benchmarks
out, err := xml.MarshalIndent(b, "", " ")
if err != nil {
return nil, fmt.Errorf("unable to format benchmark results as xUnit: %w", err)
}
return out, nil
}
func filenameByFormat(pkg string, format Format) string {
var ext string
switch format {
default:
fallthrough
case ReportFormatJSON:
ext = "json"
case ReportFormatXUnit:
ext = "xml"
}
fileName := fmt.Sprintf(
"%s_%d.%s",
pkg,
time.Now().UnixNano(),
ext,
)
return fileName
}