@@ 30,8 30,8 @@ set the query parameters as appropriate:
- **query**: required. Prometheus query to execute.
- **title**: chart title
- **stacked**: set to create an area chart instead of a line chart
-- **since**: [time.ParseDuration][1] to set distance in the past to start
- charting from
+- **since**, **until**: [time.ParseDuration][1] to set distance in the past to
+ start charting from or until
- **width**, **height**: adjust chart dimensions in inches
- **step**: number of seconds between data points
- **min**, **max**: Y axis limits
@@ 3,6 3,7 @@ module git.sr.ht/~sircmpwn/chartsrv
go 1.15
require (
+ github.com/dustin/go-humanize v1.0.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible
gonum.org/v1/plot v0.8.0
)
@@ 5,6 5,8 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjj
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
@@ 13,6 13,7 @@ import (
"strings"
"time"
+ "github.com/dustin/go-humanize"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"gonum.org/v1/plot"
@@ 154,6 155,10 @@ func main() {
d, _ := time.ParseDuration(s[0])
start = time.Now().Add(-d)
}
+ if u, ok := args["until"]; ok {
+ d, _ := time.ParseDuration(u[0])
+ end = time.Now().Add(-d)
+ }
width := 12*vg.Inch
height := 6*vg.Inch
@@ 166,6 171,12 @@ func main() {
height = vg.Length(h)*vg.Inch
}
+ // Undocumented option
+ var legend string
+ if l, ok := args["legend"]; ok {
+ legend = l[0]
+ }
+
// Set step so that there's approximately 25 data points per inch
step := int(end.Sub(start).Seconds() / (25 * float64(width / vg.Inch)))
if s, ok := args["step"]; ok {
@@ 194,6 205,8 @@ func main() {
m, _ := strconv.ParseFloat(ms[0], 64)
p.Y.Max = m
}
+
+ p.Y.Tick.Marker = humanTicks{}
if ms, ok := args["min"]; ok {
m, _ := strconv.ParseFloat(ms[0], 64)
p.Y.Min = m
@@ 238,7 251,11 @@ func main() {
nextColor = 0
}
plotters[i] = l
- p.Legend.Add(res.Metric, l)
+ if legend != "" {
+ p.Legend.Add(legend, l)
+ } else {
+ p.Legend.Add(res.Metric, l)
+ }
}
for i := len(plotters) - 1; i >= 0; i-- {
p.Add(plotters[i])
@@ 287,3 304,17 @@ func (dt dateTicks) Ticks(min, max float64) []plot.Tick {
}
return tks
}
+
+type humanTicks struct{}
+
+func (ht humanTicks) Ticks(min, max float64) []plot.Tick {
+ tks := plot.DefaultTicks{}.Ticks(min, max)
+ for i, t := range tks {
+ if t.Label == "" { // Skip minor ticks, they are fine.
+ continue
+ }
+ d, _ := strconv.ParseFloat(t.Label, 64)
+ tks[i].Label = humanize.SI(d, "")
+ }
+ return tks
+}