From c1d27805d6c75f30dcf97e1f632ed653cbefb0dc Mon Sep 17 00:00:00 2001 From: Chris McDonnell Date: Wed, 18 Jun 2025 15:20:45 -0400 Subject: [PATCH] feat(prometheus): Add minimum range interval based on scrape interval Inspired by how Grafana does `$__rate_interval`, this adds the feature that the minimum range passed to Prometheus will be 4x the configured scrape interval. This allows users of 1 minutes scrape intervals to see metrics on the 30 minute and 1 hour time range, which is currently impossible. For details of Grafana's implementation: https://grafana.com/blog/2020/09/28/new-in-grafana-7.2-__rate_interval-for-prometheus-rate-queries-that-just-work/ Signed-off-by: Chris McDonnell --- internal/config/analytics.go | 12 +++++++----- internal/server/analytics/prometheus/client.go | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/config/analytics.go b/internal/config/analytics.go index dbac10b3ee..8afd1aaef6 100644 --- a/internal/config/analytics.go +++ b/internal/config/analytics.go @@ -60,9 +60,10 @@ func (c *ClickhouseConfig) Options() (*clickhouse.Options, error) { // PrometheusConfig defines the connection details for connecting Flipt to Prometheus. type PrometheusConfig struct { - Enabled bool `json:"enabled,omitempty" mapstructure:"enabled" yaml:"enabled,omitempty"` - URL string `json:"-" mapstructure:"url" yaml:"-"` - Headers map[string]string `json:"-" mapstructure:"headers" yaml:"-"` + Enabled bool `json:"enabled,omitempty" mapstructure:"enabled" yaml:"enabled,omitempty"` + ScrapeIntervalSeconds int `json:"scrapeIntervalSeconds,omitempty" mapstructure:"scrapeIntervalSeconds" yaml:"scrapeIntervalSeconds,omitempty"` + URL string `json:"-" mapstructure:"url" yaml:"-"` + Headers map[string]string `json:"-" mapstructure:"headers" yaml:"-"` } //nolint:unparam @@ -74,8 +75,9 @@ func (a *AnalyticsConfig) setDefaults(v *viper.Viper) error { "url": "", }, "prometheus": map[string]any{ - "enabled": "false", - "url": "", + "enabled": "false", + "scrapeIntervalSeconds": "15", + "url": "", }, }, "buffer": map[string]any{ diff --git a/internal/server/analytics/prometheus/client.go b/internal/server/analytics/prometheus/client.go index 63fca688f9..8848106bdb 100644 --- a/internal/server/analytics/prometheus/client.go +++ b/internal/server/analytics/prometheus/client.go @@ -21,8 +21,9 @@ type prometheusClient interface { } type client struct { - promClient prometheusClient - logger *zap.Logger + promClient prometheusClient + minStepMinutes int + logger *zap.Logger } func New(logger *zap.Logger, cfg *config.Config) (*client, error) { @@ -39,15 +40,21 @@ func New(logger *zap.Logger, cfg *config.Config) (*client, error) { return nil, err } promClient := promapi.NewAPI(apiClient) - return &client{promClient: promClient, logger: logger}, nil + return &client{ + promClient: promClient, + logger: logger, + minStepMinutes: cfg.Analytics.Storage.Prometheus.ScrapeIntervalSeconds * 4 / 60, + }, nil } func (c *client) GetFlagEvaluationsCount(ctx context.Context, req *panalytics.FlagEvaluationsCountRequest) ([]string, []float32, error) { + stepMinutes := max(req.StepMinutes, c.minStepMinutes) query := fmt.Sprintf( - `sum(increase(flipt_evaluations_requests_total{namespace="%s", flag="%s"}[%dm])) or vector(0)`, + `sum(increase(flipt_evaluations_requests_total{namespace="%s", flag="%s"}[%dm]) / %d) or vector(0)`, req.NamespaceKey, req.FlagKey, - req.StepMinutes, + stepMinutes, + stepMinutes, ) r := promapi.Range{ Start: req.From.UTC(),