Add functions for regex replacement, sorting and humanizing.

Change-Id: I471c7a8087cd5432b51afce811b591b11583a0c3
This commit is contained in:
Brian Brazil 2014-06-05 14:07:54 +01:00 committed by Bjoern Rabenstein
parent d085de5a69
commit 9b74324d9e
2 changed files with 89 additions and 0 deletions

View file

@ -17,6 +17,9 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"math"
"regexp"
"sort"
"text/template" "text/template"
clientmodel "github.com/prometheus/client_golang/model" clientmodel "github.com/prometheus/client_golang/model"
@ -34,6 +37,23 @@ type sample struct {
} }
type queryResult []*sample type queryResult []*sample
type queryResultByLabelSorter struct {
results queryResult
by string
}
func (q queryResultByLabelSorter) Len() int {
return len(q.results)
}
func (q queryResultByLabelSorter) Less(i, j int) bool {
return q.results[i].Labels[q.by] < q.results[j].Labels[q.by]
}
func (q queryResultByLabelSorter) Swap(i, j int) {
q.results[i], q.results[j] = q.results[j], q.results[i]
}
// Expand a template, using the given data, time and storage. // Expand a template, using the given data, time and storage.
func Expand(text string, name string, data interface{}, timestamp clientmodel.Timestamp, storage metric.PreloadingPersistence) (result string, resultErr error) { func Expand(text string, name string, data interface{}, timestamp clientmodel.Timestamp, storage metric.PreloadingPersistence) (result string, resultErr error) {
@ -68,6 +88,55 @@ func Expand(text string, name string, data interface{}, timestamp clientmodel.Ti
"strvalue": func(s *sample) string { "strvalue": func(s *sample) string {
return s.Labels["__value__"] return s.Labels["__value__"]
}, },
"reReplaceAll": func(pattern, repl, text string) string {
re := regexp.MustCompile(pattern)
return re.ReplaceAllString(text, repl)
},
"sortByLabel": func(label string, v queryResult) queryResult {
sorter := queryResultByLabelSorter{v[:], label}
sort.Stable(sorter)
return v
},
"humanize": func(v float64) string {
if v == 0 {
return fmt.Sprintf("%.4g ", v)
}
if math.Abs(v) >= 1 {
prefix := ""
for _, p := range []string{"k", "M", "G", "T", "P", "E", "Z", "Y"} {
if math.Abs(v) < 1000 {
break
}
prefix = p
v /= 1000
}
return fmt.Sprintf("%.4g %s", v, prefix)
} else {
prefix := ""
for _, p := range []string{"m", "u", "n", "p", "f", "a", "z", "y"} {
if math.Abs(v) >= 1 {
break
}
prefix = p
v *= 1000
}
return fmt.Sprintf("%.4g %s", v, prefix)
}
},
"humanize1024": func(v float64) string {
if math.Abs(v) <= 1 {
return fmt.Sprintf("%.4g ", v)
}
prefix := ""
for _, p := range []string{"ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"} {
if math.Abs(v) < 1024 {
break
}
prefix = p
v /= 1024
}
return fmt.Sprintf("%.4g %s", v, prefix)
},
} }
var buffer bytes.Buffer var buffer bytes.Buffer

View file

@ -69,6 +69,26 @@ func TestTemplateExpansion(t *testing.T) {
text: "{{ (query \"missing\").banana }}", text: "{{ (query \"missing\").banana }}",
shouldFail: true, shouldFail: true,
}, },
{
// Regex replacement.
text: "{{ reReplaceAll \"(a)b\" \"x$1\" \"ab\" }}",
output: "xa",
},
{
// Sorting.
text: "{{ range query \"metric\" | sortByLabel \"instance\" }}{{.Labels.instance}} {{end}}",
output: "a b ",
},
{
// Humanize.
text: "{{ 0.0 | humanize }}:{{ 1.0 | humanize }}:{{ 1234567.0 | humanize }}:{{ .12 | humanize }}",
output: "0 :1 :1.235 M:120 m",
},
{
// Humanize1024.
text: "{{ 0.0 | humanize1024 }}:{{ 1.0 | humanize1024 }}:{{ 1048576.0 | humanize1024 }}:{{ .12 | humanize1024}}",
output: "0 :1 :1 Mi:0.12 ",
},
} }
time := clientmodel.Timestamp(0) time := clientmodel.Timestamp(0)