diff --git a/prometheus/testutil/promlint/promlint_test.go b/prometheus/testutil/promlint/promlint_test.go index c60507c..b3d6d1a 100644 --- a/prometheus/testutil/promlint/promlint_test.go +++ b/prometheus/testutil/promlint/promlint_test.go @@ -499,6 +499,63 @@ x_bytes 10 runTests(t, tests) } +func TestLintGauge(t *testing.T) { + tests := []test{ + { + name: "counter with _timestamp_seconds suffix", + in: ` +# HELP _timestamp_seconds Test metric. +# TYPE _timestamp_seconds counter +_timestamp_seconds 10 +`, + problems: []promlint.Problem{ + { + Metric: "_timestamp_seconds", + Text: `counter metrics should have "_total" suffix`, + }, + { + Metric: "_timestamp_seconds", + Text: `non-gauge metrics should not have "_timestamp_seconds" suffix`, + }, + }, + }, + { + name: "gauge with _timestamp_seconds suffix", + in: ` +# HELP _timestamp_seconds Test metric. +# TYPE _timestamp_seconds gauge +_timestamp_seconds 10 +`, + }, + { + name: "counter without _timestamp_seconds suffix", + in: ` +# HELP _total Test metric. +# TYPE _total counter +_total 10 +`, + }, + { + name: "untyped with _timestamp_seconds suffix", + in: ` +# HELP _timestamp_seconds Test metric. +# TYPE _timestamp_seconds untyped +_timestamp_seconds 10 +`, + }, + { + name: "untyped without _timestamp_seconds suffix", + in: ` +# HELP _seconds Test metric. +# TYPE _seconds untyped +_seconds 10 +`, + }, + } + + runTests(t, tests) +} + func TestLintHistogramSummaryReserved(t *testing.T) { tests := []test{ { diff --git a/prometheus/testutil/promlint/validation.go b/prometheus/testutil/promlint/validation.go index e144159..ecc2b28 100644 --- a/prometheus/testutil/promlint/validation.go +++ b/prometheus/testutil/promlint/validation.go @@ -25,6 +25,7 @@ var defaultValidations = []Validation{ validations.LintHelp, validations.LintMetricUnits, validations.LintCounter, + validations.LintGauge, validations.LintHistogramSummaryReserved, validations.LintMetricTypeInName, validations.LintReservedChars, diff --git a/prometheus/testutil/promlint/validations/gauge_validations.go b/prometheus/testutil/promlint/validations/gauge_validations.go new file mode 100644 index 0000000..adc11f8 --- /dev/null +++ b/prometheus/testutil/promlint/validations/gauge_validations.go @@ -0,0 +1,37 @@ +// Copyright 2024 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package validations + +import ( + "errors" + "strings" + + dto "github.com/prometheus/client_model/go" +) + +// LintGauge detects issues specific to gauges, as well as patterns that should +// only be used with gauges. +func LintGauge(mf *dto.MetricFamily) []error { + var problems []error + + isGauge := mf.GetType() == dto.MetricType_GAUGE + isUntyped := mf.GetType() == dto.MetricType_UNTYPED + hasTimestampSecondsSuffix := strings.HasSuffix(mf.GetName(), "_timestamp_seconds") + + if !isUntyped && !isGauge && hasTimestampSecondsSuffix { + problems = append(problems, errors.New(`non-gauge metrics should not have "_timestamp_seconds" suffix`)) + } + + return problems +}