mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Clean up intervalv2 functions (#82074)
* clean up intervalv2 functions * use roundInterval from grafana-plugin-sdk-go * use from grafana-plugin-sdk-go * have intervalv2 in publicdashboards and remove tsdb/intervalv2 * legacydata cleanup * remove unused variables * Update pkg/tsdb/legacydata/interval/interval.go Co-authored-by: Arati R. <33031346+suntala@users.noreply.github.com> --------- Co-authored-by: Arati R. <33031346+suntala@users.noreply.github.com>
This commit is contained in:
parent
3d73cd5c8e
commit
b0dfeb1911
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -142,7 +142,6 @@
|
|||||||
/pkg/tests/apis/ @grafana/grafana-app-platform-squad
|
/pkg/tests/apis/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/tests/api/correlations/ @grafana/explore-squad
|
/pkg/tests/api/correlations/ @grafana/explore-squad
|
||||||
/pkg/tsdb/grafanads/ @grafana/backend-platform
|
/pkg/tsdb/grafanads/ @grafana/backend-platform
|
||||||
/pkg/tsdb/intervalv2/ @grafana/backend-platform
|
|
||||||
/pkg/tsdb/legacydata/ @grafana/backend-platform
|
/pkg/tsdb/legacydata/ @grafana/backend-platform
|
||||||
/pkg/tsdb/opentsdb/ @grafana/backend-platform
|
/pkg/tsdb/opentsdb/ @grafana/backend-platform
|
||||||
/pkg/tsdb/sqleng/ @grafana/partner-datasources @grafana/oss-big-tent
|
/pkg/tsdb/sqleng/ @grafana/partner-datasources @grafana/oss-big-tent
|
||||||
|
@ -15,10 +15,11 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/validations"
|
"github.com/grafana/grafana/pkg/services/validations"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DefaultRes int64 = 1500
|
||||||
|
|
||||||
func TestQueryInterval(t *testing.T) {
|
func TestQueryInterval(t *testing.T) {
|
||||||
t.Run("When evaluating query condition, regarding the interval value", func(t *testing.T) {
|
t.Run("When evaluating query condition, regarding the interval value", func(t *testing.T) {
|
||||||
t.Run("Can handle interval-calculation with no panel-min-interval and no datasource-min-interval", func(t *testing.T) {
|
t.Run("Can handle interval-calculation with no panel-min-interval and no datasource-min-interval", func(t *testing.T) {
|
||||||
@ -34,7 +35,7 @@ func TestQueryInterval(t *testing.T) {
|
|||||||
// 5minutes timerange = 300000milliseconds; default-resolution is 1500pixels,
|
// 5minutes timerange = 300000milliseconds; default-resolution is 1500pixels,
|
||||||
// so we should have 300000/1500 = 200milliseconds here
|
// so we should have 300000/1500 = 200milliseconds here
|
||||||
require.Equal(t, int64(200), query.IntervalMS)
|
require.Equal(t, int64(200), query.IntervalMS)
|
||||||
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
|
require.Equal(t, DefaultRes, query.MaxDataPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
||||||
@ -50,7 +51,7 @@ func TestQueryInterval(t *testing.T) {
|
|||||||
|
|
||||||
verifier := func(query legacydata.DataSubQuery) {
|
verifier := func(query legacydata.DataSubQuery) {
|
||||||
require.Equal(t, int64(123000), query.IntervalMS)
|
require.Equal(t, int64(123000), query.IntervalMS)
|
||||||
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
|
require.Equal(t, DefaultRes, query.MaxDataPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
||||||
@ -69,7 +70,7 @@ func TestQueryInterval(t *testing.T) {
|
|||||||
|
|
||||||
verifier := func(query legacydata.DataSubQuery) {
|
verifier := func(query legacydata.DataSubQuery) {
|
||||||
require.Equal(t, int64(71000), query.IntervalMS)
|
require.Equal(t, int64(71000), query.IntervalMS)
|
||||||
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
|
require.Equal(t, DefaultRes, query.MaxDataPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
||||||
@ -90,7 +91,7 @@ func TestQueryInterval(t *testing.T) {
|
|||||||
// when both panel-min-interval and datasource-min-interval exists,
|
// when both panel-min-interval and datasource-min-interval exists,
|
||||||
// panel-min-interval is used
|
// panel-min-interval is used
|
||||||
require.Equal(t, int64(19000), query.IntervalMS)
|
require.Equal(t, int64(19000), query.IntervalMS)
|
||||||
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
|
require.Equal(t, DefaultRes, query.MaxDataPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
||||||
@ -109,7 +110,7 @@ func TestQueryInterval(t *testing.T) {
|
|||||||
// no min-interval exists, the default-min-interval will be used,
|
// no min-interval exists, the default-min-interval will be used,
|
||||||
// and for such a short time-range this will cause the value to be 1millisecond.
|
// and for such a short time-range this will cause the value to be 1millisecond.
|
||||||
require.Equal(t, int64(1), query.IntervalMS)
|
require.Equal(t, int64(1), query.IntervalMS)
|
||||||
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
|
require.Equal(t, DefaultRes, query.MaxDataPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
package intervalv2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultRes int64 = 1500
|
||||||
|
defaultMinInterval = time.Millisecond * 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type Interval struct {
|
||||||
|
Text string
|
||||||
|
Value time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type intervalCalculator struct {
|
||||||
|
minInterval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type Calculator interface {
|
||||||
|
Calculate(timerange backend.TimeRange, minInterval time.Duration, maxDataPoints int64) Interval
|
||||||
|
CalculateSafeInterval(timerange backend.TimeRange, resolution int64) 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 backend.TimeRange, minInterval time.Duration, maxDataPoints int64) Interval {
|
||||||
|
to := timerange.To.UnixNano()
|
||||||
|
from := timerange.From.UnixNano()
|
||||||
|
resolution := maxDataPoints
|
||||||
|
if resolution == 0 {
|
||||||
|
resolution = DefaultRes
|
||||||
|
}
|
||||||
|
|
||||||
|
calculatedInterval := time.Duration((to - from) / resolution)
|
||||||
|
|
||||||
|
if calculatedInterval < minInterval {
|
||||||
|
return Interval{Text: gtime.FormatInterval(minInterval), Value: minInterval}
|
||||||
|
}
|
||||||
|
|
||||||
|
rounded := gtime.RoundInterval(calculatedInterval)
|
||||||
|
|
||||||
|
return Interval{Text: gtime.FormatInterval(rounded), Value: rounded}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ic *intervalCalculator) CalculateSafeInterval(timerange backend.TimeRange, safeRes int64) Interval {
|
||||||
|
to := timerange.To.UnixNano()
|
||||||
|
from := timerange.From.UnixNano()
|
||||||
|
safeInterval := time.Duration((to - from) / safeRes)
|
||||||
|
|
||||||
|
rounded := gtime.RoundInterval(safeInterval)
|
||||||
|
return Interval{Text: gtime.FormatInterval(rounded), Value: rounded}
|
||||||
|
}
|
@ -6,8 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIntervalCalculator_Calculate(t *testing.T) {
|
func TestIntervalCalculator_Calculate(t *testing.T) {
|
||||||
@ -63,70 +61,3 @@ func TestIntervalCalculator_CalculateSafeInterval(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRoundInterval(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
interval time.Duration
|
|
||||||
expected time.Duration
|
|
||||||
}{
|
|
||||||
{"10ms", time.Millisecond * 10, time.Millisecond * 1},
|
|
||||||
{"15ms", time.Millisecond * 15, time.Millisecond * 10},
|
|
||||||
{"30ms", time.Millisecond * 30, time.Millisecond * 20},
|
|
||||||
{"45ms", time.Millisecond * 45, time.Millisecond * 50},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
assert.Equal(t, tc.expected, roundInterval(tc.interval))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatDuration(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
duration time.Duration
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{"61s", time.Second * 61, "1m"},
|
|
||||||
{"30ms", time.Millisecond * 30, "30ms"},
|
|
||||||
{"23h", time.Hour * 23, "23h"},
|
|
||||||
{"24h", time.Hour * 24, "1d"},
|
|
||||||
{"367d", time.Hour * 24 * 367, "1y"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
assert.Equal(t, tc.expected, FormatDuration(tc.duration))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetIntervalFrom(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
dsInfo *datasources.DataSource
|
|
||||||
queryInterval string
|
|
||||||
queryIntervalMs int64
|
|
||||||
defaultInterval time.Duration
|
|
||||||
expected time.Duration
|
|
||||||
}{
|
|
||||||
{"45s", nil, "45s", 0, time.Second * 15, time.Second * 45},
|
|
||||||
{"45", nil, "45", 0, time.Second * 15, time.Second * 45},
|
|
||||||
{"2m", nil, "2m", 0, time.Second * 15, time.Minute * 2},
|
|
||||||
{"1d", nil, "1d", 0, time.Second * 15, time.Hour * 24},
|
|
||||||
{"intervalMs", nil, "", 45000, time.Second * 15, time.Second * 45},
|
|
||||||
{"intervalMs sub-seconds", nil, "", 45200, time.Second * 15, time.Millisecond * 45200},
|
|
||||||
{"defaultInterval when interval empty", nil, "", 0, time.Second * 15, time.Second * 15},
|
|
||||||
{"defaultInterval when intervalMs 0", nil, "", 0, time.Second * 15, time.Second * 15},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
actual, err := GetIntervalFrom(tc.queryInterval, "", tc.queryIntervalMs, tc.defaultInterval)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, tc.expected, actual)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,12 +23,12 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/internal"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2"
|
||||||
"github.com/grafana/grafana/pkg/services/query"
|
"github.com/grafana/grafana/pkg/services/query"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||||
@ -16,11 +17,11 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/services/query"
|
"github.com/grafana/grafana/pkg/services/query"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -25,12 +25,12 @@ import (
|
|||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
"github.com/grafana/grafana/pkg/util/errutil"
|
||||||
)
|
)
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
|
||||||
azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time"
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ func (m *kqlMacroEngine) evaluateMacro(name string, defaultTimeField string, arg
|
|||||||
if dsInterval, ok = dsInfo.JSONData["interval"].(string); !ok {
|
if dsInterval, ok = dsInfo.JSONData["interval"].(string); !ok {
|
||||||
dsInterval = ""
|
dsInterval = ""
|
||||||
}
|
}
|
||||||
it, err = azTime.GetIntervalFrom(dsInterval, queryInterval.Interval, queryInterval.IntervalMs, defaultInterval)
|
it, err = gtime.GetIntervalFrom(dsInterval, queryInterval.Interval, queryInterval.IntervalMs, defaultInterval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
it = defaultInterval
|
it = defaultInterval
|
||||||
}
|
}
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
// Copied from https://github.com/grafana/grafana/blob/main/pkg/tsdb/intervalv2/intervalv2.go
|
|
||||||
// We're copying this to not block ourselves from decoupling until the conversation here is resolved
|
|
||||||
// https://raintank-corp.slack.com/archives/C05QFJUHUQ6/p1700064431005089
|
|
||||||
package time
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
year = time.Hour * 24 * 365
|
|
||||||
day = time.Hour * 24
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetIntervalFrom returns the minimum interval.
|
|
||||||
// dsInterval is the string representation of data source min interval, if configured.
|
|
||||||
// queryInterval is the string representation of query interval (min interval), e.g. "10ms" or "10s".
|
|
||||||
// queryIntervalMS is a pre-calculated numeric representation of the query interval in milliseconds.
|
|
||||||
func GetIntervalFrom(dsInterval, queryInterval string, queryIntervalMS int64, defaultInterval time.Duration) (time.Duration, error) {
|
|
||||||
// Apparently we are setting default value of queryInterval to 0s now
|
|
||||||
interval := queryInterval
|
|
||||||
if interval == "0s" {
|
|
||||||
interval = ""
|
|
||||||
}
|
|
||||||
if interval == "" {
|
|
||||||
if queryIntervalMS != 0 {
|
|
||||||
return time.Duration(queryIntervalMS) * time.Millisecond, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if interval == "" && dsInterval != "" {
|
|
||||||
interval = dsInterval
|
|
||||||
}
|
|
||||||
if interval == "" {
|
|
||||||
return defaultInterval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedInterval, err := ParseIntervalStringToTimeDuration(interval)
|
|
||||||
if err != nil {
|
|
||||||
return time.Duration(0), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedInterval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseIntervalStringToTimeDuration(interval string) (time.Duration, error) {
|
|
||||||
formattedInterval := strings.Replace(strings.Replace(interval, "<", "", 1), ">", "", 1)
|
|
||||||
isPureNum, err := regexp.MatchString(`^\d+$`, formattedInterval)
|
|
||||||
if err != nil {
|
|
||||||
return time.Duration(0), err
|
|
||||||
}
|
|
||||||
if isPureNum {
|
|
||||||
formattedInterval += "s"
|
|
||||||
}
|
|
||||||
parsedInterval, err := gtime.ParseDuration(formattedInterval)
|
|
||||||
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"
|
|
||||||
}
|
|
@ -5,6 +5,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TimeGrain handles conversions between
|
// TimeGrain handles conversions between
|
||||||
@ -15,7 +17,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CreateISO8601DurationFromIntervalMS(it int64) (string, error) {
|
func CreateISO8601DurationFromIntervalMS(it int64) (string, error) {
|
||||||
formatted := FormatDuration(time.Duration(it) * time.Millisecond)
|
formatted := gtime.FormatInterval(time.Duration(it) * time.Millisecond)
|
||||||
|
|
||||||
if strings.Contains(formatted, "ms") {
|
if strings.Contains(formatted, "ms") {
|
||||||
return "PT1M", nil
|
return "PT1M", nil
|
||||||
|
@ -4,9 +4,6 @@
|
|||||||
package time
|
package time
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
@ -16,8 +13,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
DefaultRes int64 = 1500
|
DefaultRes int64 = 1500
|
||||||
defaultMinInterval = time.Millisecond * 1
|
defaultMinInterval = time.Millisecond * 1
|
||||||
year = time.Hour * 24 * 365
|
|
||||||
day = time.Hour * 24
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Interval struct {
|
type Interval struct {
|
||||||
@ -52,10 +47,6 @@ func NewCalculator(opts ...CalculatorOptions) *intervalCalculator {
|
|||||||
return calc
|
return calc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Interval) Milliseconds() int64 {
|
|
||||||
return i.Value.Nanoseconds() / int64(time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ic *intervalCalculator) Calculate(timerange backend.TimeRange, minInterval time.Duration, maxDataPoints int64) Interval {
|
func (ic *intervalCalculator) Calculate(timerange backend.TimeRange, minInterval time.Duration, maxDataPoints int64) Interval {
|
||||||
to := timerange.To.UnixNano()
|
to := timerange.To.UnixNano()
|
||||||
from := timerange.From.UnixNano()
|
from := timerange.From.UnixNano()
|
||||||
@ -67,12 +58,12 @@ func (ic *intervalCalculator) Calculate(timerange backend.TimeRange, minInterval
|
|||||||
calculatedInterval := time.Duration((to - from) / resolution)
|
calculatedInterval := time.Duration((to - from) / resolution)
|
||||||
|
|
||||||
if calculatedInterval < minInterval {
|
if calculatedInterval < minInterval {
|
||||||
return Interval{Text: FormatDuration(minInterval), Value: minInterval}
|
return Interval{Text: gtime.FormatInterval(minInterval), Value: minInterval}
|
||||||
}
|
}
|
||||||
|
|
||||||
rounded := roundInterval(calculatedInterval)
|
rounded := gtime.RoundInterval(calculatedInterval)
|
||||||
|
|
||||||
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
return Interval{Text: gtime.FormatInterval(rounded), Value: rounded}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *intervalCalculator) CalculateSafeInterval(timerange backend.TimeRange, safeRes int64) Interval {
|
func (ic *intervalCalculator) CalculateSafeInterval(timerange backend.TimeRange, safeRes int64) Interval {
|
||||||
@ -80,179 +71,6 @@ func (ic *intervalCalculator) CalculateSafeInterval(timerange backend.TimeRange,
|
|||||||
from := timerange.From.UnixNano()
|
from := timerange.From.UnixNano()
|
||||||
safeInterval := time.Duration((to - from) / safeRes)
|
safeInterval := time.Duration((to - from) / safeRes)
|
||||||
|
|
||||||
rounded := roundInterval(safeInterval)
|
rounded := gtime.RoundInterval(safeInterval)
|
||||||
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
return Interval{Text: gtime.FormatInterval(rounded), Value: rounded}
|
||||||
}
|
|
||||||
|
|
||||||
// GetIntervalFrom returns the minimum interval.
|
|
||||||
// dsInterval is the string representation of data source min interval, if configured.
|
|
||||||
// queryInterval is the string representation of query interval (min interval), e.g. "10ms" or "10s".
|
|
||||||
// queryIntervalMS is a pre-calculated numeric representation of the query interval in milliseconds.
|
|
||||||
func GetIntervalFrom(dsInterval, queryInterval string, queryIntervalMS int64, defaultInterval time.Duration) (time.Duration, error) {
|
|
||||||
// Apparently we are setting default value of queryInterval to 0s now
|
|
||||||
interval := queryInterval
|
|
||||||
if interval == "0s" {
|
|
||||||
interval = ""
|
|
||||||
}
|
|
||||||
if interval == "" {
|
|
||||||
if queryIntervalMS != 0 {
|
|
||||||
return time.Duration(queryIntervalMS) * time.Millisecond, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if interval == "" && dsInterval != "" {
|
|
||||||
interval = dsInterval
|
|
||||||
}
|
|
||||||
if interval == "" {
|
|
||||||
return defaultInterval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedInterval, err := ParseIntervalStringToTimeDuration(interval)
|
|
||||||
if err != nil {
|
|
||||||
return time.Duration(0), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedInterval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseIntervalStringToTimeDuration(interval string) (time.Duration, error) {
|
|
||||||
formattedInterval := strings.Replace(strings.Replace(interval, "<", "", 1), ">", "", 1)
|
|
||||||
isPureNum, err := regexp.MatchString(`^\d+$`, formattedInterval)
|
|
||||||
if err != nil {
|
|
||||||
return time.Duration(0), err
|
|
||||||
}
|
|
||||||
if isPureNum {
|
|
||||||
formattedInterval += "s"
|
|
||||||
}
|
|
||||||
parsedInterval, err := gtime.ParseDuration(formattedInterval)
|
|
||||||
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.01s
|
|
||||||
case interval <= 10*time.Millisecond:
|
|
||||||
return time.Millisecond * 1 // 0.001s
|
|
||||||
// 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
|
|
||||||
// 17.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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
gcmTime "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring/time"
|
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addInterval(period string, field *data.Field) error {
|
func addInterval(period string, field *data.Field) error {
|
||||||
period = strings.TrimPrefix(period, "+")
|
period = strings.TrimPrefix(period, "+")
|
||||||
p, err := gcmTime.ParseIntervalStringToTimeDuration(period)
|
p, err := gtime.ParseIntervalStringToTimeDuration(period)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// $__interval_ms is the exact value in milliseconds
|
// $__interval_ms is the exact value in milliseconds
|
||||||
@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
func interpolateInterval(flux string, interval time.Duration) string {
|
func interpolateInterval(flux string, interval time.Duration) string {
|
||||||
intervalMs := int64(interval / time.Millisecond)
|
intervalMs := int64(interval / time.Millisecond)
|
||||||
intervalText := intervalv2.FormatDuration(interval)
|
intervalText := gtime.FormatInterval(interval)
|
||||||
|
|
||||||
flux = strings.ReplaceAll(flux, "$__interval_ms", strconv.FormatInt(intervalMs, 10))
|
flux = strings.ReplaceAll(flux, "$__interval_ms", strconv.FormatInt(intervalMs, 10))
|
||||||
flux = strings.ReplaceAll(flux, "$__interval", intervalText)
|
flux = strings.ReplaceAll(flux, "$__interval", intervalText)
|
||||||
|
@ -8,8 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -36,7 +35,7 @@ func (query *Query) Build(queryContext *backend.QueryDataRequest) (string, error
|
|||||||
res += query.renderTz()
|
res += query.renderTz()
|
||||||
}
|
}
|
||||||
|
|
||||||
intervalText := intervalv2.FormatDuration(query.Interval)
|
intervalText := gtime.FormatInterval(query.Interval)
|
||||||
intervalMs := int64(query.Interval / time.Millisecond)
|
intervalMs := int64(query.Interval / time.Millisecond)
|
||||||
|
|
||||||
res = strings.ReplaceAll(res, "$timeFilter", query.renderTimeFilter(queryContext))
|
res = strings.ReplaceAll(res, "$timeFilter", query.renderTimeFilter(queryContext))
|
||||||
|
@ -1,228 +0,0 @@
|
|||||||
package intervalv2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultRes int64 = 1500
|
|
||||||
defaultMinInterval = time.Millisecond * 1
|
|
||||||
)
|
|
||||||
|
|
||||||
type Interval struct {
|
|
||||||
Text string
|
|
||||||
Value time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type intervalCalculator struct {
|
|
||||||
minInterval time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type Calculator interface {
|
|
||||||
Calculate(timerange backend.TimeRange, minInterval time.Duration, maxDataPoints int64) Interval
|
|
||||||
CalculateSafeInterval(timerange backend.TimeRange, resolution int64) 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 backend.TimeRange, minInterval time.Duration, maxDataPoints int64) Interval {
|
|
||||||
to := timerange.To.UnixNano()
|
|
||||||
from := timerange.From.UnixNano()
|
|
||||||
resolution := maxDataPoints
|
|
||||||
if resolution == 0 {
|
|
||||||
resolution = DefaultRes
|
|
||||||
}
|
|
||||||
|
|
||||||
calculatedInterval := time.Duration((to - from) / resolution)
|
|
||||||
|
|
||||||
if calculatedInterval < minInterval {
|
|
||||||
return Interval{Text: FormatDuration(minInterval), Value: minInterval}
|
|
||||||
}
|
|
||||||
|
|
||||||
rounded := roundInterval(calculatedInterval)
|
|
||||||
|
|
||||||
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ic *intervalCalculator) CalculateSafeInterval(timerange backend.TimeRange, safeRes int64) Interval {
|
|
||||||
to := timerange.To.UnixNano()
|
|
||||||
from := timerange.From.UnixNano()
|
|
||||||
safeInterval := time.Duration((to - from) / safeRes)
|
|
||||||
|
|
||||||
rounded := roundInterval(safeInterval)
|
|
||||||
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIntervalFrom returns the minimum interval.
|
|
||||||
// dsInterval is the string representation of data source min interval, if configured.
|
|
||||||
// queryInterval is the string representation of query interval (min interval), e.g. "10ms" or "10s".
|
|
||||||
// queryIntervalMS is a pre-calculated numeric representation of the query interval in milliseconds.
|
|
||||||
func GetIntervalFrom(dsInterval, queryInterval string, queryIntervalMS int64, defaultInterval time.Duration) (time.Duration, error) {
|
|
||||||
// Apparently we are setting default value of queryInterval to 0s now
|
|
||||||
interval := queryInterval
|
|
||||||
if interval == "0s" {
|
|
||||||
interval = ""
|
|
||||||
}
|
|
||||||
if interval == "" {
|
|
||||||
if queryIntervalMS != 0 {
|
|
||||||
return time.Duration(queryIntervalMS) * time.Millisecond, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if interval == "" && dsInterval != "" {
|
|
||||||
interval = dsInterval
|
|
||||||
}
|
|
||||||
if interval == "" {
|
|
||||||
return defaultInterval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedInterval, err := ParseIntervalStringToTimeDuration(interval)
|
|
||||||
if err != nil {
|
|
||||||
return time.Duration(0), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedInterval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseIntervalStringToTimeDuration(interval string) (time.Duration, error) {
|
|
||||||
formattedInterval := strings.Replace(strings.Replace(interval, "<", "", 1), ">", "", 1)
|
|
||||||
isPureNum, err := regexp.MatchString(`^\d+$`, formattedInterval)
|
|
||||||
if err != nil {
|
|
||||||
return time.Duration(0), err
|
|
||||||
}
|
|
||||||
if isPureNum {
|
|
||||||
formattedInterval += "s"
|
|
||||||
}
|
|
||||||
parsedInterval, err := gtime.ParseDuration(formattedInterval)
|
|
||||||
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 {
|
|
||||||
return gtime.FormatInterval(inter)
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:gocyclo
|
|
||||||
func roundInterval(interval time.Duration) time.Duration {
|
|
||||||
switch {
|
|
||||||
// 0.01s
|
|
||||||
case interval <= 10*time.Millisecond:
|
|
||||||
return time.Millisecond * 1 // 0.001s
|
|
||||||
// 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
|
|
||||||
// 17.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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package interval
|
package interval
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -16,8 +15,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
DefaultRes int64 = 1500
|
DefaultRes int64 = 1500
|
||||||
defaultMinInterval = time.Millisecond * 1
|
defaultMinInterval = time.Millisecond * 1
|
||||||
year = time.Hour * 24 * 365
|
|
||||||
day = time.Hour * 24
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Interval struct {
|
type Interval struct {
|
||||||
@ -62,11 +59,11 @@ func (ic *intervalCalculator) Calculate(timerange legacydata.DataTimeRange, minI
|
|||||||
calculatedInterval := time.Duration((to - from) / DefaultRes)
|
calculatedInterval := time.Duration((to - from) / DefaultRes)
|
||||||
|
|
||||||
if calculatedInterval < minInterval {
|
if calculatedInterval < minInterval {
|
||||||
return Interval{Text: FormatDuration(minInterval), Value: minInterval}
|
return Interval{Text: gtime.FormatInterval(minInterval), Value: minInterval}
|
||||||
}
|
}
|
||||||
|
|
||||||
rounded := roundInterval(calculatedInterval)
|
rounded := roundInterval(calculatedInterval)
|
||||||
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
return Interval{Text: gtime.FormatInterval(rounded), Value: rounded}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *intervalCalculator) CalculateSafeInterval(timerange legacydata.DataTimeRange, safeRes int64) Interval {
|
func (ic *intervalCalculator) CalculateSafeInterval(timerange legacydata.DataTimeRange, safeRes int64) Interval {
|
||||||
@ -75,7 +72,7 @@ func (ic *intervalCalculator) CalculateSafeInterval(timerange legacydata.DataTim
|
|||||||
safeInterval := time.Duration((to - from) / safeRes)
|
safeInterval := time.Duration((to - from) / safeRes)
|
||||||
|
|
||||||
rounded := roundInterval(safeInterval)
|
rounded := roundInterval(safeInterval)
|
||||||
return Interval{Text: FormatDuration(rounded), Value: rounded}
|
return Interval{Text: gtime.FormatInterval(rounded), Value: rounded}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIntervalFrom(dsInfo *datasources.DataSource, queryModel *simplejson.Json, defaultInterval time.Duration) (time.Duration, error) {
|
func GetIntervalFrom(dsInfo *datasources.DataSource, queryModel *simplejson.Json, defaultInterval time.Duration) (time.Duration, error) {
|
||||||
@ -117,126 +114,11 @@ func GetIntervalFrom(dsInfo *datasources.DataSource, queryModel *simplejson.Json
|
|||||||
return parsedInterval, nil
|
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
|
//nolint:gocyclo
|
||||||
func roundInterval(interval time.Duration) time.Duration {
|
func roundInterval(interval time.Duration) time.Duration {
|
||||||
switch {
|
|
||||||
// 0.015s
|
// 0.015s
|
||||||
case interval <= 15*time.Millisecond:
|
if interval <= 15*time.Millisecond {
|
||||||
return time.Millisecond * 10 // 0.01s
|
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
|
|
||||||
}
|
}
|
||||||
|
return gtime.RoundInterval(interval)
|
||||||
}
|
}
|
||||||
|
@ -74,26 +74,6 @@ func TestRoundInterval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFormatDuration(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
duration time.Duration
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{"61s", time.Second * 61, "1m"},
|
|
||||||
{"30ms", time.Millisecond * 30, "30ms"},
|
|
||||||
{"23h", time.Hour * 23, "23h"},
|
|
||||||
{"24h", time.Hour * 24, "1d"},
|
|
||||||
{"367d", time.Hour * 24 * 367, "1y"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
assert.Equal(t, tc.expected, FormatDuration(tc.duration))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetIntervalFrom(t *testing.T) {
|
func TestGetIntervalFrom(t *testing.T) {
|
||||||
dsJSON, err := simplejson.NewJson([]byte(`{"timeInterval": "60s"}`))
|
dsJSON, err := simplejson.NewJson([]byte(`{"timeInterval": "60s"}`))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
|
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func interpolateVariables(expr string, interval time.Duration, timeRange time.Duration, queryType dataquery.LokiQueryType, step time.Duration) string {
|
func interpolateVariables(expr string, interval time.Duration, timeRange time.Duration, queryType dataquery.LokiQueryType, step time.Duration) string {
|
||||||
intervalText := intervalv2.FormatDuration(interval)
|
intervalText := gtime.FormatInterval(interval)
|
||||||
stepText := intervalv2.FormatDuration(step)
|
stepText := gtime.FormatInterval(step)
|
||||||
intervalMsText := strconv.FormatInt(int64(interval/time.Millisecond), 10)
|
intervalMsText := strconv.FormatInt(int64(interval/time.Millisecond), 10)
|
||||||
|
|
||||||
rangeMs := timeRange.Milliseconds()
|
rangeMs := timeRange.Milliseconds()
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// round the duration to the nearest millisecond larger-or-equal-to the duration
|
// round the duration to the nearest millisecond larger-or-equal-to the duration
|
||||||
@ -31,7 +31,7 @@ func calculateStep(interval time.Duration, timeRange time.Duration, resolution i
|
|||||||
return ceilMs(chosenStep), nil
|
return ceilMs(chosenStep), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
step, err := intervalv2.ParseIntervalStringToTimeDuration(*queryStep)
|
step, err := gtime.ParseIntervalStringToTimeDuration(*queryStep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return step, err
|
return step, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user