mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-06 22:27:17 +02:00
Add template functions to support various use cases. (#16619)
Presumably, this will help with Loki alerts, but the added functionality is also generally useful. For one, this enables `parseDuration` to also accept negative duration (as that's something that is also used in PromQL by now). This also adds a function `now` to return the evaluation time of the template (as seconds since epoch AKA Unix time) and a function `toDuration` (akin to `toTime`), which creates a Go `time.Duration` from a duration in seconds. --------- Signed-off-by: Dmitry Ponomaryov <me@halje.ru> Signed-off-by: Dmitry Ponomaryov <iamhalje@gmail.com>
This commit is contained in:
parent
846acc10bb
commit
b18272a572
@ -57,6 +57,8 @@ If functions are used in a pipeline, the pipeline value is passed as the last ar
|
|||||||
| humanizePercentage | number or string | string | Converts a ratio value to a fraction of 100. |
|
| humanizePercentage | number or string | string | Converts a ratio value to a fraction of 100. |
|
||||||
| humanizeTimestamp | number or string | string | Converts a Unix timestamp in seconds to a more readable format. |
|
| humanizeTimestamp | number or string | string | Converts a Unix timestamp in seconds to a more readable format. |
|
||||||
| toTime | number or string | *time.Time | Converts a Unix timestamp in seconds to a time.Time. |
|
| toTime | number or string | *time.Time | Converts a Unix timestamp in seconds to a time.Time. |
|
||||||
|
| toDuration | number or string | *time.Duration | Converts a duration in seconds to a time.Duration. |
|
||||||
|
| now | none | float64 | Returns the Unix timestamp in seconds at the time of the template evaluation. |
|
||||||
|
|
||||||
Humanizing functions are intended to produce reasonable output for consumption
|
Humanizing functions are intended to produce reasonable output for consumption
|
||||||
by humans, and are not guaranteed to return the same results between Prometheus
|
by humans, and are not guaranteed to return the same results between Prometheus
|
||||||
|
@ -263,6 +263,17 @@ func NewTemplateExpander(
|
|||||||
|
|
||||||
return floatToTime(v)
|
return floatToTime(v)
|
||||||
},
|
},
|
||||||
|
"toDuration": func(i interface{}) (*time.Duration, error) {
|
||||||
|
v, err := common_templates.ConvertToFloat(i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d := time.Duration(v * float64(time.Second))
|
||||||
|
return &d, nil
|
||||||
|
},
|
||||||
|
"now": func() float64 {
|
||||||
|
return float64(timestamp) / 1000.0
|
||||||
|
},
|
||||||
"pathPrefix": func() string {
|
"pathPrefix": func() string {
|
||||||
return externalURL.Path
|
return externalURL.Path
|
||||||
},
|
},
|
||||||
@ -270,7 +281,7 @@ func NewTemplateExpander(
|
|||||||
return externalURL.String()
|
return externalURL.String()
|
||||||
},
|
},
|
||||||
"parseDuration": func(d string) (float64, error) {
|
"parseDuration": func(d string) (float64, error) {
|
||||||
v, err := model.ParseDuration(d)
|
v, err := model.ParseDurationAllowNegative(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
@ -467,6 +468,31 @@ func TestTemplateExpansion(t *testing.T) {
|
|||||||
text: `{{ ("1435065584.128" | toTime).Format "2006" }}`,
|
text: `{{ ("1435065584.128" | toTime).Format "2006" }}`,
|
||||||
output: "2015",
|
output: "2015",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// toDuration - input as float64 seconds, returns *time.Duration.
|
||||||
|
text: `{{ (1800 | toDuration).String }}`,
|
||||||
|
output: "30m0s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// toDuration - input as string seconds, returns *time.Duration.
|
||||||
|
text: `{{ ("1800" | toDuration).String }}`,
|
||||||
|
output: "30m0s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// now - returns fixed timestamp as float64 seconds.
|
||||||
|
text: `{{ now }}`,
|
||||||
|
output: "1.353755652e+09",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// now - returns fixed timestamp converted to formatted time string.
|
||||||
|
text: `{{ (now | toTime).Format "Mon Jan 2 15:04:05 2006" }}`,
|
||||||
|
output: "Sat Nov 24 11:14:12 2012",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// returns Unix milliseconds timestamp for 30 minutes ago.
|
||||||
|
text: `{{ ("-30m" | parseDuration | toDuration | (now | toTime).Add).UnixMilli }}`,
|
||||||
|
output: "1353753852000",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Title.
|
// Title.
|
||||||
text: "{{ \"aa bb CC\" | title }}",
|
text: "{{ \"aa bb CC\" | title }}",
|
||||||
@ -514,10 +540,15 @@ func TestTemplateExpansion(t *testing.T) {
|
|||||||
output: "http://testhost:9090/path/prefix",
|
output: "http://testhost:9090/path/prefix",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// parseDuration (using printf to ensure the return is a string).
|
// parseDuration with positive duration (using printf to ensure the return is a string).
|
||||||
text: "{{ printf \"%0.2f\" (parseDuration \"1h2m10ms\") }}",
|
text: "{{ printf \"%0.2f\" (parseDuration \"1h2m10ms\") }}",
|
||||||
output: "3720.01",
|
output: "3720.01",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// parseDuration with negative duration (using printf to ensure the return is a string).
|
||||||
|
text: "{{ printf \"%0.2f\" (parseDuration \"-1h2m10ms\") }}",
|
||||||
|
output: "-3720.01",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Simple hostname.
|
// Simple hostname.
|
||||||
text: "{{ \"foo.example.com\" | stripDomain }}",
|
text: "{{ \"foo.example.com\" | stripDomain }}",
|
||||||
@ -579,7 +610,7 @@ func testTemplateExpansion(t *testing.T, scenarios []scenario) {
|
|||||||
}
|
}
|
||||||
var result string
|
var result string
|
||||||
var err error
|
var err error
|
||||||
expander := NewTemplateExpander(context.Background(), s.text, "test", s.input, 0, queryFunc, extURL, s.options)
|
expander := NewTemplateExpander(context.Background(), s.text, "test", s.input, model.Time(1353755652000), queryFunc, extURL, s.options)
|
||||||
if s.html {
|
if s.html {
|
||||||
result, err = expander.ExpandHTML(nil)
|
result, err = expander.ExpandHTML(nil)
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user