diff --git a/go.mod b/go.mod index 02682d777..6080ac733 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ require ( cloud.google.com/go v0.49.0 // indirect cloud.google.com/go/storage v1.4.0 github.com/VictoriaMetrics/fastcache v1.5.2 - github.com/VictoriaMetrics/metrics v1.8.2 + github.com/VictoriaMetrics/metrics v1.8.3 github.com/aws/aws-sdk-go v1.25.37 github.com/cespare/xxhash/v2 v2.1.1 github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect diff --git a/go.sum b/go.sum index 737f90910..9e0a59315 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/VictoriaMetrics/fastcache v1.5.2 h1:Erd8iIuBAL9kke8JzM4+WxkKuFkHh3ktwLanJvDgR44= github.com/VictoriaMetrics/fastcache v1.5.2/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= -github.com/VictoriaMetrics/metrics v1.8.2 h1:Oa+u0XlcofYfPDAPTgKObyangxbp+vVGkjSwARtObFQ= -github.com/VictoriaMetrics/metrics v1.8.2/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= +github.com/VictoriaMetrics/metrics v1.8.3 h1:5eVP1tVjnSao/YVMIQiWrQkEJ6nzQq7IANbNniVu4cI= +github.com/VictoriaMetrics/metrics v1.8.3/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/aws/aws-sdk-go v1.25.37 h1:gBtB/F3dophWpsUQKN/Kni+JzYEH2mGHF4hWNtfED1w= diff --git a/vendor/github.com/VictoriaMetrics/metrics/README.md b/vendor/github.com/VictoriaMetrics/metrics/README.md index 0dcb2dff5..6cb230507 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/README.md +++ b/vendor/github.com/VictoriaMetrics/metrics/README.md @@ -14,6 +14,7 @@ * Easy to use. See the [API docs](http://godoc.org/github.com/VictoriaMetrics/metrics). * Fast. * Allows exporting distinct metric sets via distinct endpoints. See [Set](http://godoc.org/github.com/VictoriaMetrics/metrics#Set). +* Supports [easy-to-use histograms](http://godoc.org/github.com/VictoriaMetrics/metrics#Histogram), which just work without any tuning. ### Limitations @@ -39,6 +40,9 @@ var ( queueSize = metrics.NewGauge(`queue_size{queue="foobar",topic="baz"}`, func() float64 { return float64(foobarQueue.Len()) }) + + // Register histogram with a single label. + responseSize = metrics.NewHistogram(`response_size{path="/foo/bar"}`) ) // ... @@ -50,6 +54,9 @@ func requestHandler() { processRequest() // Update requestDuration summary. requestDuration.UpdateDuration(startTime) + + // Update responseSize histogram. + responseSize.Update(responseSize) } // Expose the registered metrics at `/metrics` path. @@ -86,3 +93,11 @@ exposed from your application. Just use [GetOrCreateCounter](http://godoc.org/github.com/VictoriaMetrics/metrics#GetOrCreateCounter) instead of `CounterVec.With`. See [this example](https://godoc.org/github.com/VictoriaMetrics/metrics#example-Counter--Vec) for details. + + +#### Why [Histogram](http://godoc.org/github.com/VictoriaMetrics/metrics#Histogram) buckets contain `vmrange` labels instead of `le` labels like in Prometheus histograms? + +Buckets with `vmrange` labels occupy less disk space comparing to Promethes-style buckets with `le` labels, +because `vmrange` buckets don't include counters for the previous ranges. [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) provides `prometheus_buckets` +function, which converts `vmrange` buckets to Prometheus-style buckets with `le` labels. This is useful for building heatmaps in Grafana. +Additionally, its' `histogram_quantile` function transparently handles histogram buckets with `vmrange` labels. diff --git a/vendor/github.com/VictoriaMetrics/metrics/histogram.go b/vendor/github.com/VictoriaMetrics/metrics/histogram.go index 423abde54..0ee440092 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/histogram.go +++ b/vendor/github.com/VictoriaMetrics/metrics/histogram.go @@ -37,14 +37,16 @@ import ( // - and - start and end values for the given bucket // - - the number of hits to the given bucket during Update* calls. // -// Only non-zero buckets are exposed. +// Histogram buckets can be converted to Prometheus-like buckets with `le` labels +// with `prometheus_buckets(_bucket)` function in VictoriaMetrics: // -// Histogram buckets can be converted to Prometheus-like buckets in VictoriaMetrics -// with `prometheus_buckets(_bucket)`: -// -// prometheus_buckets(rate(request_duration_bucket[5m])) +// prometheus_buckets(request_duration_bucket) // // Histogram cannot be used for negative values. +// +// Time series produced by the Histogram have better compression ratio comparing to +// Prometheus histogram buckets with `le` labels, since they don't include counters +// for all the previous buckets. type Histogram struct { buckets [bucketsCount]uint64 @@ -89,6 +91,10 @@ func GetOrCreateHistogram(name string) *Histogram { // // v cannot be negative. func (h *Histogram) Update(v float64) { + if math.IsNaN(v) || v < 0 { + // Skip NaNs and negative values. + return + } idx := getBucketIdx(v) if idx >= uint(len(h.buckets)) { panic(fmt.Errorf("BUG: idx cannot exceed %d; got %d", len(h.buckets), idx)) @@ -106,13 +112,60 @@ func (h *Histogram) UpdateDuration(startTime time.Time) { h.Update(d) } +// VisitNonZeroBuckets calls f for all buckets with non-zero counters. +func (h *Histogram) VisitNonZeroBuckets(f func(vmrange string, count uint64)) { + for i, v := range h.buckets[:] { + if v == 0 { + continue + } + vmrange := getRangeForBucketIdx(uint(i)) + f(vmrange, v) + } +} + +func getRangeForBucketIdx(idx uint) string { + bucketRangesOnce.Do(initBucketRanges) + return bucketRanges[idx] +} + +func initBucketRanges() { + start := "0" + for i := 0; i < bucketsCount; i++ { + end := getRangeEndFromBucketIdx(uint(i)) + bucketRanges[i] = start + "..." + end + start = end + } +} + +var ( + bucketRanges [bucketsCount]string + bucketRangesOnce sync.Once +) + +func getTagForBucketIdx(idx uint) string { + bucketTagsOnce.Do(initBucketTags) + return bucketTags[idx] +} + +func initBucketTags() { + for i := 0; i < bucketsCount; i++ { + vmrange := getRangeForBucketIdx(uint(i)) + bucketTags[i] = fmt.Sprintf(`vmrange=%q`, vmrange) + } +} + +var ( + bucketTags [bucketsCount]string + bucketTagsOnce sync.Once +) + func (h *Histogram) marshalTo(prefix string, w io.Writer) { count := atomic.LoadUint64(&h.count) if count == 0 { return } for i := range h.buckets[:] { - h.marshalBucket(prefix, w, i) + h.marshalBucket(prefix, w, uint(i)) } // Marshal `_sum` and `_count` metrics. name, filters := splitMetricName(prefix) @@ -127,17 +180,12 @@ func (h *Histogram) marshalTo(prefix string, w io.Writer) { fmt.Fprintf(w, "%s_count%s %d\n", name, filters, count) } -func (h *Histogram) marshalBucket(prefix string, w io.Writer, idx int) { +func (h *Histogram) marshalBucket(prefix string, w io.Writer, idx uint) { v := h.buckets[idx] if v == 0 { return } - start := "0" - if idx > 0 { - start = getRangeEndFromBucketIdx(uint(idx - 1)) - } - end := getRangeEndFromBucketIdx(uint(idx)) - tag := fmt.Sprintf(`vmrange="%s...%s"`, start, end) + tag := getTagForBucketIdx(idx) prefix = addTag(prefix, tag) name, filters := splitMetricName(prefix) fmt.Fprintf(w, "%s_bucket%s %d\n", name, filters, v) diff --git a/vendor/modules.txt b/vendor/modules.txt index 5d8381ed1..f34c52720 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -12,7 +12,7 @@ cloud.google.com/go/storage github.com/BurntSushi/toml # github.com/VictoriaMetrics/fastcache v1.5.2 github.com/VictoriaMetrics/fastcache -# github.com/VictoriaMetrics/metrics v1.8.2 +# github.com/VictoriaMetrics/metrics v1.8.3 github.com/VictoriaMetrics/metrics # github.com/aws/aws-sdk-go v1.25.37 github.com/aws/aws-sdk-go/aws