mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 05:04:05 -08:00
template: adding formatTime function to TemplateExpander (#10993)
Signed-off-by: Jonathan Stevens <jonathanstevens89@gmail.com> Signed-off-by: Jonathan Stevens <jon.stevens@getweave.com> Co-authored-by: Jonathan Stevens <jon.stevens@getweave.com>
This commit is contained in:
parent
97d7e09e0b
commit
ce1bf8b15a
|
@ -51,13 +51,14 @@ If functions are used in a pipeline, the pipeline value is passed as the last ar
|
||||||
|
|
||||||
### Numbers
|
### Numbers
|
||||||
|
|
||||||
| Name | Arguments | Returns | Notes |
|
| Name | Arguments | Returns | Notes |
|
||||||
| ------------------ | -----------------| --------| --------- |
|
|---------------------| -----------------| --------| --------- |
|
||||||
| humanize | number or string | string | Converts a number to a more readable format, using [metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix).
|
| humanize | number or string | string | Converts a number to a more readable format, using [metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix).
|
||||||
| humanize1024 | number or string | string | Like `humanize`, but uses 1024 as the base rather than 1000. |
|
| humanize1024 | number or string | string | Like `humanize`, but uses 1024 as the base rather than 1000. |
|
||||||
| humanizeDuration | number or string | string | Converts a duration in seconds to a more readable format. |
|
| humanizeDuration | number or string | string | Converts a duration in seconds to a more readable format. |
|
||||||
| 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. |
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -45,6 +45,8 @@ var (
|
||||||
Name: "prometheus_template_text_expansions_total",
|
Name: "prometheus_template_text_expansions_total",
|
||||||
Help: "The total number of template text expansions.",
|
Help: "The total number of template text expansions.",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
errNaNOrInf = errors.New("value is NaN or Inf")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -315,15 +317,24 @@ func NewTemplateExpander(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if math.IsNaN(v) || math.IsInf(v, 0) {
|
|
||||||
|
tm, err := floatToTime(v)
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, errNaNOrInf):
|
||||||
return fmt.Sprintf("%.4g", v), nil
|
return fmt.Sprintf("%.4g", v), nil
|
||||||
|
case err != nil:
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
timestamp := v * 1e9
|
|
||||||
if timestamp > math.MaxInt64 || timestamp < math.MinInt64 {
|
return fmt.Sprint(tm), nil
|
||||||
return "", fmt.Errorf("%v cannot be represented as a nanoseconds timestamp since it overflows int64", v)
|
},
|
||||||
|
"toTime": func(i interface{}) (*time.Time, error) {
|
||||||
|
v, err := convertToFloat(i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
t := model.TimeFromUnixNano(int64(timestamp)).Time().UTC()
|
|
||||||
return fmt.Sprint(t), nil
|
return floatToTime(v)
|
||||||
},
|
},
|
||||||
"pathPrefix": func() string {
|
"pathPrefix": func() string {
|
||||||
return externalURL.Path
|
return externalURL.Path
|
||||||
|
@ -446,3 +457,15 @@ func (te Expander) ParseTest() error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func floatToTime(v float64) (*time.Time, error) {
|
||||||
|
if math.IsNaN(v) || math.IsInf(v, 0) {
|
||||||
|
return nil, errNaNOrInf
|
||||||
|
}
|
||||||
|
timestamp := v * 1e9
|
||||||
|
if timestamp > math.MaxInt64 || timestamp < math.MinInt64 {
|
||||||
|
return nil, fmt.Errorf("%v cannot be represented as a nanoseconds timestamp since it overflows int64", v)
|
||||||
|
}
|
||||||
|
t := model.TimeFromUnixNano(int64(timestamp)).Time().UTC()
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -429,6 +430,16 @@ func TestTemplateExpansion(t *testing.T) {
|
||||||
text: `{{ "1435065584.128" | humanizeTimestamp }}`,
|
text: `{{ "1435065584.128" | humanizeTimestamp }}`,
|
||||||
output: "2015-06-23 13:19:44.128 +0000 UTC",
|
output: "2015-06-23 13:19:44.128 +0000 UTC",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// ToTime - model.SampleValue input - float64.
|
||||||
|
text: `{{ (1435065584.128 | toTime).Format "2006" }}`,
|
||||||
|
output: "2015",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ToTime - model.SampleValue input - string.
|
||||||
|
text: `{{ ("1435065584.128" | toTime).Format "2006" }}`,
|
||||||
|
output: "2015",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Title.
|
// Title.
|
||||||
text: "{{ \"aa bb CC\" | title }}",
|
text: "{{ \"aa bb CC\" | title }}",
|
||||||
|
@ -560,3 +571,55 @@ func testTemplateExpansion(t *testing.T, scenarios []scenario) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_floatToTime(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
v float64
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *time.Time
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"happy path",
|
||||||
|
args{
|
||||||
|
v: 1657155181,
|
||||||
|
},
|
||||||
|
func() *time.Time {
|
||||||
|
tm := time.Date(2022, 7, 7, 0, 53, 1, 0, time.UTC)
|
||||||
|
return &tm
|
||||||
|
}(),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"more than math.MaxInt64",
|
||||||
|
args{
|
||||||
|
v: 1.79769313486231570814527423731704356798070e+300,
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"less than math.MinInt64",
|
||||||
|
args{
|
||||||
|
v: -1.79769313486231570814527423731704356798070e+300,
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := floatToTime(tt.args.v)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("floatToTime() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("floatToTime() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue