Skip to content

Commit 53e51c4

Browse files
authored
Merge pull request #1157 from prometheus/cut-1.13.1
Bugfixes + Cut 1.13.1 + documenting release process.
2 parents 64435fc + 79ca0eb commit 53e51c4

9 files changed

+54
-9
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## Unreleased
22

3+
## 1.13.1 / 2022-11-01
4+
5+
* [BUGFIX] Fix race condition with Exemplar in Counter. #1146
6+
* [BUGFIX] Fix `CumulativeCount` value of `+Inf` bucket created from exemplar. #1148
7+
* [BUGFIX] Fix double-counting bug in `promhttp.InstrumentRoundTripperCounter`. #1118
8+
39
## 1.13.0 / 2022-08-05
410

511
* [CHANGE] Minimum required Go version is now 1.17 (we also test client_golang against new 1.19 version).

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,24 @@ See the [contributing guidelines](CONTRIBUTING.md) and the
6969
[Community section](http://prometheus.io/community/) of the homepage.
7070

7171
`clint_golang` community is also present on the CNCF Slack `#prometheus-client_golang`.
72+
73+
### For Maintainers: Release Process
74+
75+
To cut a minor version:
76+
77+
1. Create a new branch `release-<major>.<minor>` on top of the `main` commit you want to cut the version from and push it.
78+
2. Create a new branch on top of the release branch, e.g. `<yourname>/cut-<major>.<minor>.<patch>`,
79+
3. Change the `VERSION` file.
80+
4. Update `CHANGELOG` (only user-impacting changes to mention).
81+
5. Create PR, and get it reviewed.
82+
6. Once merged, create a release with the `release-<major>.<minor>` tag on GitHub with the `<version> / <date>` title.
83+
7. Announce on the prometheus-announce mailing list, slack and Twitter.
84+
8. Merge the release branch back to the `main` using the "merge without squashing" approach (!).
85+
86+
> NOTE: In case of merge conflicts, you can checkout the release branch in a new branch, e.g. <yourname>/resolve-conflicts`, fix the merge problems there, and then do a PR into main from the new branch. In that way, you still get all the commits in the release branch back into `main`, but leave the release branch alone.
87+
88+
To cut the patch version:
89+
90+
1. Create a branch on top of the release branch you want to use.
91+
2. Cherry-pick the fixes from the `main` branch (or add new commits) to fix critical bugs for that patch release.
92+
3. Follow steps 3-8 as above.

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.13.0
1+
1.13.1

prometheus/counter.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,13 @@ func (c *counter) get() float64 {
140140
}
141141

142142
func (c *counter) Write(out *dto.Metric) error {
143-
val := c.get()
144-
143+
// Read the Exemplar first and the value second. This is to avoid a race condition
144+
// where users see an exemplar for a not-yet-existing observation.
145145
var exemplar *dto.Exemplar
146146
if e := c.exemplar.Load(); e != nil {
147147
exemplar = e.(*dto.Exemplar)
148148
}
149+
val := c.get()
149150

150151
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out)
151152
}

prometheus/histogram.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ func (h *constHistogram) Write(out *dto.Metric) error {
613613
// to send it to Prometheus in the Collect method.
614614
//
615615
// buckets is a map of upper bounds to cumulative counts, excluding the +Inf
616-
// bucket.
616+
// bucket. The +Inf bucket is implicit, and its value is equal to the provided count.
617617
//
618618
// NewConstHistogram returns an error if the length of labelValues is not
619619
// consistent with the variable labels in Desc or if Desc is invalid.

prometheus/metric.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func (m *withExemplarsMetric) Write(pb *dto.Metric) error {
187187
} else {
188188
// The +Inf bucket should be explicitly added if there is an exemplar for it, similar to non-const histogram logic in https://github.com/prometheus/client_golang/blob/main/prometheus/histogram.go#L357-L365.
189189
b := &dto.Bucket{
190-
CumulativeCount: proto.Uint64(pb.Histogram.Bucket[len(pb.Histogram.GetBucket())-1].GetCumulativeCount()),
190+
CumulativeCount: proto.Uint64(pb.Histogram.GetSampleCount()),
191191
UpperBound: proto.Float64(math.Inf(1)),
192192
Exemplar: e,
193193
}

prometheus/metric_test.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ func TestWithExemplarsMetric(t *testing.T) {
7979
}
8080
}
8181

82-
infBucket := metric.GetHistogram().Bucket[len(metric.GetHistogram().Bucket)-1].GetUpperBound()
82+
infBucket := metric.GetHistogram().Bucket[len(metric.GetHistogram().Bucket)-1]
8383

84-
if infBucket != math.Inf(1) {
85-
t.Errorf("want %v, got %v", math.Inf(1), infBucket)
84+
if want, got := math.Inf(1), infBucket.GetUpperBound(); want != got {
85+
t.Errorf("want %v, got %v", want, got)
86+
}
87+
88+
if want, got := uint64(4711), infBucket.GetCumulativeCount(); want != got {
89+
t.Errorf("want %v, got %v", want, got)
8690
}
8791
})
8892
}

prometheus/promhttp/instrument_client.go

-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
7878
1,
7979
rtOpts.getExemplarFn(r.Context()),
8080
)
81-
counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
8281
}
8382
return resp, err
8483
}

prometheus/promhttp/instrument_client_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
"github.com/prometheus/client_golang/prometheus"
28+
"github.com/prometheus/client_golang/prometheus/testutil"
2829

2930
dto "github.com/prometheus/client_model/go"
3031
"google.golang.org/protobuf/proto"
@@ -250,6 +251,19 @@ func TestClientMiddlewareAPI_WithRequestContext(t *testing.T) {
250251
t.Errorf("metric family %s must not be empty", mf.GetName())
251252
}
252253
}
254+
255+
// make sure counters aren't double-incremented (see #1117)
256+
expected := `
257+
# HELP client_api_requests_total A counter for requests from the wrapped client.
258+
# TYPE client_api_requests_total counter
259+
client_api_requests_total{code="200",method="get"} 1
260+
`
261+
262+
if err := testutil.GatherAndCompare(reg, strings.NewReader(expected),
263+
"client_api_requests_total",
264+
); err != nil {
265+
t.Fatal(err)
266+
}
253267
}
254268

255269
func TestClientMiddlewareAPIWithRequestContextTimeout(t *testing.T) {

0 commit comments

Comments
 (0)