mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 18:44:54 +08:00

The /api/ds/query and /api/tsdb/query endpoints extract the intervalMs field from each query in the request, but it currently seems to be ignored, at least for queries to a Prometheus datasource. This changes GetIntervalFrom function to check for the presence of intervalMs in the query model if interval is missing.
231 lines
5.9 KiB
Go
231 lines
5.9 KiB
Go
package interval
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/plugins"
|
|
)
|
|
|
|
var (
|
|
defaultRes int64 = 1500
|
|
defaultMinInterval = time.Millisecond * 1
|
|
year = time.Hour * 24 * 365
|
|
day = time.Hour * 24
|
|
)
|
|
|
|
type Interval struct {
|
|
Text string
|
|
Value time.Duration
|
|
}
|
|
|
|
type intervalCalculator struct {
|
|
minInterval time.Duration
|
|
}
|
|
|
|
type Calculator interface {
|
|
Calculate(timeRange plugins.DataTimeRange, minInterval time.Duration) Interval
|
|
}
|
|
|
|
type CalculatorOptions struct {
|
|
MinInterval time.Duration
|
|
}
|
|
|
|
func NewCalculator(opts ...CalculatorOptions) *intervalCalculator {
|
|
calc := &intervalCalculator{}
|
|
|
|
for _, o := range opts {
|
|
if o.MinInterval == 0 {
|
|
calc.minInterval = defaultMinInterval
|
|
} else {
|
|
calc.minInterval = o.MinInterval
|
|
}
|
|
}
|
|
|
|
return calc
|
|
}
|
|
|
|
func (i *Interval) Milliseconds() int64 {
|
|
return i.Value.Nanoseconds() / int64(time.Millisecond)
|
|
}
|
|
|
|
func (ic *intervalCalculator) Calculate(timerange plugins.DataTimeRange, minInterval time.Duration) Interval {
|
|
to := timerange.MustGetTo().UnixNano()
|
|
from := timerange.MustGetFrom().UnixNano()
|
|
interval := time.Duration((to - from) / defaultRes)
|
|
|
|
if interval < minInterval {
|
|
return Interval{Text: FormatDuration(minInterval), Value: minInterval}
|
|
}
|
|
|
|
rounded := roundInterval(interval)
|
|
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
|
}
|
|
|
|
func GetIntervalFrom(dsInfo *models.DataSource, queryModel *simplejson.Json, defaultInterval time.Duration) (time.Duration, error) {
|
|
interval := queryModel.Get("interval").MustString("")
|
|
|
|
// intervalMs field appears in the v2 plugins API and should be preferred
|
|
// if 'interval' isn't present.
|
|
if interval == "" {
|
|
intervalMS := queryModel.Get("intervalMs").MustInt(0)
|
|
if intervalMS != 0 {
|
|
return time.Duration(intervalMS) * time.Millisecond, nil
|
|
}
|
|
}
|
|
|
|
if interval == "" && dsInfo != nil && dsInfo.JsonData != nil {
|
|
dsInterval := dsInfo.JsonData.Get("timeInterval").MustString("")
|
|
if dsInterval != "" {
|
|
interval = dsInterval
|
|
}
|
|
}
|
|
|
|
if interval == "" {
|
|
return defaultInterval, nil
|
|
}
|
|
|
|
interval = strings.Replace(strings.Replace(interval, "<", "", 1), ">", "", 1)
|
|
isPureNum, err := regexp.MatchString(`^\d+$`, interval)
|
|
if err != nil {
|
|
return time.Duration(0), err
|
|
}
|
|
if isPureNum {
|
|
interval += "s"
|
|
}
|
|
parsedInterval, err := time.ParseDuration(interval)
|
|
if err != nil {
|
|
return time.Duration(0), err
|
|
}
|
|
|
|
return parsedInterval, nil
|
|
}
|
|
|
|
// FormatDuration converts a duration into the kbn format e.g. 1m 2h or 3d
|
|
func FormatDuration(inter time.Duration) string {
|
|
if inter >= year {
|
|
return fmt.Sprintf("%dy", inter/year)
|
|
}
|
|
|
|
if inter >= day {
|
|
return fmt.Sprintf("%dd", inter/day)
|
|
}
|
|
|
|
if inter >= time.Hour {
|
|
return fmt.Sprintf("%dh", inter/time.Hour)
|
|
}
|
|
|
|
if inter >= time.Minute {
|
|
return fmt.Sprintf("%dm", inter/time.Minute)
|
|
}
|
|
|
|
if inter >= time.Second {
|
|
return fmt.Sprintf("%ds", inter/time.Second)
|
|
}
|
|
|
|
if inter >= time.Millisecond {
|
|
return fmt.Sprintf("%dms", inter/time.Millisecond)
|
|
}
|
|
|
|
return "1ms"
|
|
}
|
|
|
|
//nolint: gocyclo
|
|
func roundInterval(interval time.Duration) time.Duration {
|
|
switch {
|
|
// 0.015s
|
|
case interval <= 15*time.Millisecond:
|
|
return time.Millisecond * 10 // 0.01s
|
|
// 0.035s
|
|
case interval <= 35*time.Millisecond:
|
|
return time.Millisecond * 20 // 0.02s
|
|
// 0.075s
|
|
case interval <= 75*time.Millisecond:
|
|
return time.Millisecond * 50 // 0.05s
|
|
// 0.15s
|
|
case interval <= 150*time.Millisecond:
|
|
return time.Millisecond * 100 // 0.1s
|
|
// 0.35s
|
|
case interval <= 350*time.Millisecond:
|
|
return time.Millisecond * 200 // 0.2s
|
|
// 0.75s
|
|
case interval <= 750*time.Millisecond:
|
|
return time.Millisecond * 500 // 0.5s
|
|
// 1.5s
|
|
case interval <= 1500*time.Millisecond:
|
|
return time.Millisecond * 1000 // 1s
|
|
// 3.5s
|
|
case interval <= 3500*time.Millisecond:
|
|
return time.Millisecond * 2000 // 2s
|
|
// 7.5s
|
|
case interval <= 7500*time.Millisecond:
|
|
return time.Millisecond * 5000 // 5s
|
|
// 12.5s
|
|
case interval <= 12500*time.Millisecond:
|
|
return time.Millisecond * 10000 // 10s
|
|
// 17.5s
|
|
case interval <= 17500*time.Millisecond:
|
|
return time.Millisecond * 15000 // 15s
|
|
// 25s
|
|
case interval <= 25000*time.Millisecond:
|
|
return time.Millisecond * 20000 // 20s
|
|
// 45s
|
|
case interval <= 45000*time.Millisecond:
|
|
return time.Millisecond * 30000 // 30s
|
|
// 1.5m
|
|
case interval <= 90000*time.Millisecond:
|
|
return time.Millisecond * 60000 // 1m
|
|
// 3.5m
|
|
case interval <= 210000*time.Millisecond:
|
|
return time.Millisecond * 120000 // 2m
|
|
// 7.5m
|
|
case interval <= 450000*time.Millisecond:
|
|
return time.Millisecond * 300000 // 5m
|
|
// 12.5m
|
|
case interval <= 750000*time.Millisecond:
|
|
return time.Millisecond * 600000 // 10m
|
|
// 12.5m
|
|
case interval <= 1050000*time.Millisecond:
|
|
return time.Millisecond * 900000 // 15m
|
|
// 25m
|
|
case interval <= 1500000*time.Millisecond:
|
|
return time.Millisecond * 1200000 // 20m
|
|
// 45m
|
|
case interval <= 2700000*time.Millisecond:
|
|
return time.Millisecond * 1800000 // 30m
|
|
// 1.5h
|
|
case interval <= 5400000*time.Millisecond:
|
|
return time.Millisecond * 3600000 // 1h
|
|
// 2.5h
|
|
case interval <= 9000000*time.Millisecond:
|
|
return time.Millisecond * 7200000 // 2h
|
|
// 4.5h
|
|
case interval <= 16200000*time.Millisecond:
|
|
return time.Millisecond * 10800000 // 3h
|
|
// 9h
|
|
case interval <= 32400000*time.Millisecond:
|
|
return time.Millisecond * 21600000 // 6h
|
|
// 24h
|
|
case interval <= 86400000*time.Millisecond:
|
|
return time.Millisecond * 43200000 // 12h
|
|
// 48h
|
|
case interval <= 172800000*time.Millisecond:
|
|
return time.Millisecond * 86400000 // 24h
|
|
// 1w
|
|
case interval <= 604800000*time.Millisecond:
|
|
return time.Millisecond * 86400000 // 24h
|
|
// 3w
|
|
case interval <= 1814400000*time.Millisecond:
|
|
return time.Millisecond * 604800000 // 1w
|
|
// 2y
|
|
case interval < 3628800000*time.Millisecond:
|
|
return time.Millisecond * 2592000000 // 30d
|
|
default:
|
|
return time.Millisecond * 31536000000 // 1y
|
|
}
|
|
}
|