make plot generation create images, separate out some functionality

This commit is contained in:
Julius Park
2026-03-13 15:08:35 -04:00
parent 52e2849149
commit 2c88cb7a19
3 changed files with 55 additions and 38 deletions
+43 -35
View File
@@ -8,56 +8,64 @@ import (
"path/filepath"
"time"
"github.com/go-echarts/go-echarts/v2/charts"
"github.com/go-echarts/go-echarts/v2/opts"
"github.com/vicanso/go-charts/v2"
)
type LatencySnapshot struct {
t time.Time
latency time.Duration
}
type LatencyResult struct {
snapshots []LatencySnapshot
}
func (lr *LatencyResult) PlotLatency(outputFile string) error {
line := charts.NewLine()
xvals := make([]string, 0, len(lr.snapshots))
yvals := make([]opts.LineData, 0, len(lr.snapshots))
start := lr.snapshots[0].t
for _, s := range lr.snapshots {
elapsedMs := float64(s.t.Sub(start).Seconds())
xvals = append(xvals, fmt.Sprintf("%f", elapsedMs))
yvals = append(yvals, opts.LineData{
Value: float64(s.latency.Microseconds()) / 1000.0, // ms
})
func (lr *LatencyResult) GeneratePlot(plotPath string) error {
bytes, err := lr.PlotLatency()
if err != nil {
return err
}
line.SetGlobalOptions(
charts.WithTitleOpts(opts.Title{
Title: "Latency Over Time",
}),
charts.WithYAxisOpts(opts.YAxis{
Name: "Latency (ms)",
}),
charts.WithXAxisOpts(opts.XAxis{
Name: "Time",
}),
)
line.SetXAxis(xvals).
AddSeries("Latency", yvals)
f, err := os.Create(outputFile)
// save to file
f, err := os.Create(plotPath)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(bytes)
return err
}
return line.Render(f)
func (lr *LatencyResult) PlotLatency() ([]byte, error) {
if len(lr.snapshots) == 0 {
return nil, fmt.Errorf("no snapshots available")
}
xvals := make([]string, 0, len(lr.snapshots))
yvals := make([]float64, 0, len(lr.snapshots))
start := lr.snapshots[0].t
for _, s := range lr.snapshots {
elapsed := s.t.Sub(start).Seconds()
xvals = append(xvals, fmt.Sprintf("%.2f", elapsed))
latencyMs := float64(s.latency.Microseconds()) / 1000.0
yvals = append(yvals, latencyMs)
}
p, err := charts.LineRender(
[][]float64{yvals},
charts.TitleTextOptionFunc("Latency Over Time"),
charts.XAxisDataOptionFunc(xvals),
charts.LegendLabelsOptionFunc([]string{"Latency"}),
charts.HeightOptionFunc(500),
charts.WidthOptionFunc(1000),
)
if err != nil {
return nil, err
}
return p.Bytes()
}
type avgResult struct {
@@ -185,11 +193,11 @@ func do(config LoadTestConfig) error {
log.Printf("️ final average scheduling time per event: %s", finalScheduledResult.avg)
if config.PlotDir != "" {
log.Printf("️ exporting scheduling/duration snapshot data")
err := finalScheduledResult.latencyResult.PlotLatency(filepath.Join(config.PlotDir, "scheduling_latency.html"))
err := finalScheduledResult.latencyResult.GeneratePlot(filepath.Join(config.PlotDir, "scheduling_plot.png"))
if err != nil {
return err
}
err = finalDurationResult.latencyResult.PlotLatency(filepath.Join(config.PlotDir, "duration_latency.html"))
err = finalDurationResult.latencyResult.GeneratePlot(filepath.Join(config.PlotDir, "duration_plot.png"))
if err != nil {
return err
}
+4 -1
View File
@@ -19,7 +19,6 @@ require (
github.com/fatih/color v1.18.0
github.com/getkin/kin-openapi v0.133.0
github.com/go-co-op/gocron/v2 v2.19.1
github.com/go-echarts/go-echarts/v2 v2.7.0
github.com/google/go-github/v57 v57.0.0
github.com/gorilla/securecookie v1.1.2
github.com/gorilla/sessions v1.3.0
@@ -48,6 +47,7 @@ require (
github.com/testcontainers/testcontainers-go/modules/rabbitmq v0.41.0
github.com/tink-crypto/tink-go v0.0.0-20230613075026-d6de17e3f164
github.com/tink-crypto/tink-go-gcpkms v0.0.0-20230602082706-31d0d09ccc8d
github.com/vicanso/go-charts/v2 v2.6.10
github.com/wneessen/go-mail v0.7.2
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.67.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0
@@ -126,6 +126,7 @@ require (
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
@@ -187,6 +188,7 @@ require (
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/wcharczuk/go-chart/v2 v2.1.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/woodsbury/decimal128 v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
@@ -197,6 +199,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
golang.org/x/term v0.40.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
+8 -2
View File
@@ -151,8 +151,6 @@ github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE=
github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw=
github.com/go-co-op/gocron/v2 v2.19.1 h1:B4iLeA0NB/2iO3EKQ7NfKn5KsQgZfjb2fkvoZJU3yBI=
github.com/go-co-op/gocron/v2 v2.19.1/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
github.com/go-echarts/go-echarts/v2 v2.7.0 h1:PQqs3jpTEroMKgxEALPKBNFTO2Ms9By11gVOKh8+stI=
github.com/go-echarts/go-echarts/v2 v2.7.0/go.mod h1:Z+spPygZRIEyqod69r0WMnkN5RV3MwhYDtw601w3G8w=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
@@ -192,6 +190,8 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo=
@@ -467,6 +467,10 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/vicanso/go-charts/v2 v2.6.10 h1:Nb2YBekEbUBPbvohnUO1oYMy31v75brUPk6n/fq+JXw=
github.com/vicanso/go-charts/v2 v2.6.10/go.mod h1:Ii2KDI3udTG1wPtiTnntzjlUBJVJTqNscMzh3oYHzUk=
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8=
@@ -526,6 +530,8 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=