From 4af12a41299375546a278ff00a2e41d5d960a1ef Mon Sep 17 00:00:00 2001 From: gudvinr Date: Mon, 18 Aug 2025 23:10:18 +0300 Subject: [PATCH] refactor(metric): use time.Duration for refresh duration --- internal/config/config_test.go | 55 ++++++++++++++++++++++++++++++++++ internal/config/options.go | 10 +++---- internal/config/parser.go | 2 +- internal/metric/metric.go | 6 ++-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 55058fe2..9a9208a7 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -2230,3 +2230,58 @@ func TestCustomPollingLimitPerHost(t *testing.T) { t.Fatalf(`Unexpected custom PollingLimitPerHost value, got %v instead of %v`, result, expected) } } + +func TestMetricsRefreshInterval(t *testing.T) { + os.Clearenv() + os.Setenv("METRICS_REFRESH_INTERVAL", "33") + + parser := NewParser() + opts, err := parser.ParseEnvironmentVariables() + if err != nil { + t.Fatalf(`Parsing failure: %v`, err) + } + + expected := 33 * time.Second + result := opts.MetricsRefreshInterval() + + if result != expected { + t.Fatalf(`Unexpected METRICS_REFRESH_INTERVAL value, got %d instead of %d`, result, expected) + } + + sorted := opts.SortedOptions(false) + i := slices.IndexFunc(sorted, func(opt *option) bool { + return opt.Key == "METRICS_REFRESH_INTERVAL" + }) + + expectedSerialized := 33 + if got := sorted[i].Value; got != expectedSerialized { + t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized) + } +} + +func TestDefaultMetricsRefreshInterval(t *testing.T) { + os.Clearenv() + + parser := NewParser() + opts, err := parser.ParseEnvironmentVariables() + if err != nil { + t.Fatalf(`Parsing failure: %v`, err) + } + + expected := defaultMetricsRefreshInterval + result := opts.MetricsRefreshInterval() + + if result != expected { + t.Fatalf(`Unexpected METRICS_REFRESH_INTERVAL value, got %d instead of %d`, result, expected) + } + + sorted := opts.SortedOptions(false) + i := slices.IndexFunc(sorted, func(opt *option) bool { + return opt.Key == "METRICS_REFRESH_INTERVAL" + }) + + expectedSerialized := int(defaultMetricsRefreshInterval / time.Second) + if got := sorted[i].Value; got != expectedSerialized { + t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized) + } +} diff --git a/internal/config/options.go b/internal/config/options.go index 32b1b466..b2c6eced 100644 --- a/internal/config/options.go +++ b/internal/config/options.go @@ -83,7 +83,7 @@ const ( defaultMaintenanceMode = false defaultMaintenanceMessage = "Miniflux is currently under maintenance" defaultMetricsCollector = false - defaultMetricsRefreshInterval = 60 + defaultMetricsRefreshInterval = 60 * time.Second defaultMetricsAllowedNetworks = "127.0.0.1/8" defaultMetricsUsername = "" defaultMetricsPassword = "" @@ -176,7 +176,7 @@ type options struct { maintenanceMode bool maintenanceMessage string metricsCollector bool - metricsRefreshInterval int + metricsRefreshInterval time.Duration metricsAllowedNetworks []string metricsUsername string metricsPassword string @@ -639,8 +639,8 @@ func (o *options) HasMetricsCollector() bool { return o.metricsCollector } -// MetricsRefreshInterval returns the refresh interval in seconds. -func (o *options) MetricsRefreshInterval() int { +// MetricsRefreshInterval returns the refresh interval. +func (o *options) MetricsRefreshInterval() time.Duration { return o.metricsRefreshInterval } @@ -759,7 +759,7 @@ func (o *options) SortedOptions(redactSecret bool) []*option { "METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","), "METRICS_COLLECTOR": o.metricsCollector, "METRICS_PASSWORD": redactSecretValue(o.metricsPassword, redactSecret), - "METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval, + "METRICS_REFRESH_INTERVAL": int(o.metricsRefreshInterval.Seconds()), "METRICS_USERNAME": o.metricsUsername, "OAUTH2_CLIENT_ID": o.oauth2ClientID, "OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret), diff --git a/internal/config/parser.go b/internal/config/parser.go index d3ffd602..a0e3165b 100644 --- a/internal/config/parser.go +++ b/internal/config/parser.go @@ -231,7 +231,7 @@ func (p *parser) parseLines(lines []string) (err error) { case "METRICS_COLLECTOR": p.opts.metricsCollector = parseBool(value, defaultMetricsCollector) case "METRICS_REFRESH_INTERVAL": - p.opts.metricsRefreshInterval = parseInt(value, defaultMetricsRefreshInterval) + p.opts.metricsRefreshInterval = parseInterval(value, time.Second, defaultMetricsRefreshInterval) case "METRICS_ALLOWED_NETWORKS": p.opts.metricsAllowedNetworks = parseStringList(value, []string{defaultMetricsAllowedNetworks}) case "METRICS_USERNAME": diff --git a/internal/metric/metric.go b/internal/metric/metric.go index f362841d..537ce8b2 100644 --- a/internal/metric/metric.go +++ b/internal/metric/metric.go @@ -138,11 +138,11 @@ var ( // collector represents a metric collector. type collector struct { store *storage.Storage - refreshInterval int + refreshInterval time.Duration } // NewCollector initializes a new metric collector. -func NewCollector(store *storage.Storage, refreshInterval int) *collector { +func NewCollector(store *storage.Storage, refreshInterval time.Duration) *collector { prometheus.MustRegister(BackgroundFeedRefreshDuration) prometheus.MustRegister(ScraperRequestDuration) prometheus.MustRegister(ArchiveEntriesDuration) @@ -163,7 +163,7 @@ func NewCollector(store *storage.Storage, refreshInterval int) *collector { // GatherStorageMetrics polls the database to fetch metrics. func (c *collector) GatherStorageMetrics() { - for range time.Tick(time.Duration(c.refreshInterval) * time.Second) { + for range time.Tick(c.refreshInterval) { slog.Debug("Collecting metrics from the database") usersGauge.Set(float64(c.store.CountUsers()))