diff --git a/examples/gocollector/main.go b/examples/gocollector/main.go index 93f8c22..9116314 100644 --- a/examples/gocollector/main.go +++ b/examples/gocollector/main.go @@ -22,6 +22,7 @@ import ( "fmt" "log" "net/http" + "regexp" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" @@ -39,7 +40,7 @@ func main() { // Add Go module build info. reg.MustRegister(collectors.NewBuildInfoCollector()) reg.MustRegister(collectors.NewGoCollector( - collectors.WithGoCollections(collectors.GoRuntimeMemStatsCollection | collectors.GoRuntimeMetricsCollection), + collectors.WithGoCollectorRuntimeMetrics(collectors.GoRuntimeMetricsRule{Matcher: regexp.MustCompile("/.*")}), )) // Expose the registered metrics via HTTP. diff --git a/prometheus/counter.go b/prometheus/counter.go index de30de6..3668a16 100644 --- a/prometheus/counter.go +++ b/prometheus/counter.go @@ -140,12 +140,13 @@ func (c *counter) get() float64 { } func (c *counter) Write(out *dto.Metric) error { - val := c.get() - + // Read the Exemplar first and the value second. This is to avoid a race condition + // where users see an exemplar for a not-yet-existing observation. var exemplar *dto.Exemplar if e := c.exemplar.Load(); e != nil { exemplar = e.(*dto.Exemplar) } + val := c.get() return populateMetric(CounterValue, val, c.labelPairs, exemplar, out) } diff --git a/prometheus/histogram.go b/prometheus/histogram.go index 6665328..309534f 100644 --- a/prometheus/histogram.go +++ b/prometheus/histogram.go @@ -1170,7 +1170,7 @@ func (h *constHistogram) Write(out *dto.Metric) error { // to send it to Prometheus in the Collect method. // // buckets is a map of upper bounds to cumulative counts, excluding the +Inf -// bucket. +// bucket. The +Inf bucket is implicit, and its value is equal to the provided count. // // NewConstHistogram returns an error if the length of labelValues is not // consistent with the variable labels in Desc or if Desc is invalid. diff --git a/prometheus/metric.go b/prometheus/metric.go index f0941f6..b5119c5 100644 --- a/prometheus/metric.go +++ b/prometheus/metric.go @@ -187,7 +187,7 @@ func (m *withExemplarsMetric) Write(pb *dto.Metric) error { } else { // 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. b := &dto.Bucket{ - CumulativeCount: proto.Uint64(pb.Histogram.Bucket[len(pb.Histogram.GetBucket())-1].GetCumulativeCount()), + CumulativeCount: proto.Uint64(pb.Histogram.GetSampleCount()), UpperBound: proto.Float64(math.Inf(1)), Exemplar: e, } diff --git a/prometheus/metric_test.go b/prometheus/metric_test.go index 2d69b08..dd7d843 100644 --- a/prometheus/metric_test.go +++ b/prometheus/metric_test.go @@ -79,10 +79,14 @@ func TestWithExemplarsMetric(t *testing.T) { } } - infBucket := metric.GetHistogram().Bucket[len(metric.GetHistogram().Bucket)-1].GetUpperBound() + infBucket := metric.GetHistogram().Bucket[len(metric.GetHistogram().Bucket)-1] - if infBucket != math.Inf(1) { - t.Errorf("want %v, got %v", math.Inf(1), infBucket) + if want, got := math.Inf(1), infBucket.GetUpperBound(); want != got { + t.Errorf("want %v, got %v", want, got) + } + + if want, got := uint64(4711), infBucket.GetCumulativeCount(); want != got { + t.Errorf("want %v, got %v", want, got) } }) } diff --git a/prometheus/promauto/auto.go b/prometheus/promauto/auto.go index f8d50d1..a9c3108 100644 --- a/prometheus/promauto/auto.go +++ b/prometheus/promauto/auto.go @@ -14,13 +14,13 @@ // Package promauto provides alternative constructors for the fundamental // Prometheus metric types and their …Vec and …Func variants. The difference to // their counterparts in the prometheus package is that the promauto -// constructors return Collectors that are already registered with a -// registry. There are two sets of constructors. The constructors in the first -// set are top-level functions, while the constructors in the other set are -// methods of the Factory type. The top-level function return Collectors -// registered with the global registry (prometheus.DefaultRegisterer), while the -// methods return Collectors registered with the registry the Factory was -// constructed with. All constructors panic if the registration fails. +// constructors register the Collectors with a registry before returning them. +// There are two sets of constructors. The constructors in the first set are +// top-level functions, while the constructors in the other set are methods of +// the Factory type. The top-level function return Collectors registered with +// the global registry (prometheus.DefaultRegisterer), while the methods return +// Collectors registered with the registry the Factory was constructed with. All +// constructors panic if the registration fails. // // The following example is a complete program to create a histogram of normally // distributed random numbers from the math/rand package: