Repository: prometheus/common (go)

Issue:
OpenMetrics: _total suffix repeated multiple times
### Description

Today we faced the problem with counter export in openmetrics format: counter names keep being appended by "_total" suffices, one time for every new labelset.

This is how it looks in grafana metric browser after being collected by prometheus

<img width="1154" alt="Screenshot" src="https://github.com/prometheus/common/assets/11293374/4fcc1f3b-83d0-4c5f-86aa-3a05da0886c6">

### Debug

The problem seems to be around the line
https://github.com/vesari/common/blob/6a86956d41af916f0c048f4988d93994bb865b9e/expfmt/openmetrics_create.go#L255
which modifies metric name inside the loop,

and was introduced in [this commit](https://github.com/prometheus/common/pull/544/commits/6a86956d41af916f0c048f4988d93994bb865b9e).

### Affected versions

github.com/prometheus/common v0.50.0

Pull request:
Correct logic in sample naming for counters, add new test
This PR solves the bug causing the `_total` suffix to be repeated multiple times in the sample metric name, and adds a new corresponding test case. Fixes #605.

Patch:
diff --git a/expfmt/openmetrics_create.go b/expfmt/openmetrics_create.go
index 432843d..353c5e9 100644
--- a/expfmt/openmetrics_create.go
+++ b/expfmt/openmetrics_create.go
@@ -248,12 +248,12 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
 	var createdTsBytesWritten int
 
 	// Finally the samples, one line for each.
+	if metricType == dto.MetricType_COUNTER && strings.HasSuffix(name, "_total") {
+		compliantName = compliantName + "_total"
+	}
 	for _, metric := range in.Metric {
 		switch metricType {
 		case dto.MetricType_COUNTER:
-			if strings.HasSuffix(name, "_total") {
-				compliantName = compliantName + "_total"
-			}
 			if metric.Counter == nil {
 				return written, fmt.Errorf(
 					"expected counter in metric %s %s", compliantName, metric,


Test patch:
diff --git a/expfmt/openmetrics_create_test.go b/expfmt/openmetrics_create_test.go
index 4a68eff..58b284e 100644
--- a/expfmt/openmetrics_create_test.go
+++ b/expfmt/openmetrics_create_test.go
@@ -694,6 +694,55 @@ request_duration_microseconds_count 2693
 			options: []EncoderOption{WithUnit()},
 			out: `# HELP name doc string
 # TYPE name counter
+`,
+		},
+		// 18: Counter, timestamp given, unit opted in, _total suffix.
+		{
+			in: &dto.MetricFamily{
+				Name: proto.String("some_measure_total"),
+				Help: proto.String("some testing measurement"),
+				Type: dto.MetricType_COUNTER.Enum(),
+				Unit: proto.String("seconds"),
+				Metric: []*dto.Metric{
+					{
+						Label: []*dto.LabelPair{
+							{
+								Name:  proto.String("labelname"),
+								Value: proto.String("val1"),
+							},
+							{
+								Name:  proto.String("basename"),
+								Value: proto.String("basevalue"),
+							},
+						},
+						Counter: &dto.Counter{
+							Value: proto.Float64(42),
+						},
+					},
+					{
+						Label: []*dto.LabelPair{
+							{
+								Name:  proto.String("labelname"),
+								Value: proto.String("val2"),
+							},
+							{
+								Name:  proto.String("basename"),
+								Value: proto.String("basevalue"),
+							},
+						},
+						Counter: &dto.Counter{
+							Value: proto.Float64(.23),
+						},
+						TimestampMs: proto.Int64(1234567890),
+					},
+				},
+			},
+			options: []EncoderOption{WithUnit()},
+			out: `# HELP some_measure_seconds some testing measurement
+# TYPE some_measure_seconds counter
+# UNIT some_measure_seconds seconds
+some_measure_seconds_total{labelname="val1",basename="basevalue"} 42.0
+some_measure_seconds_total{labelname="val2",basename="basevalue"} 0.23 1.23456789e+06
 `,
 		},
 	}