forked from mirror/client_golang
Merge pull request #9 from prometheus/refactor/user-experience/standardized-directories
Rearrange file and package per convention.
This commit is contained in:
commit
4c1c13d109
|
@ -1,8 +1,4 @@
|
|||
language: go
|
||||
|
||||
before_script:
|
||||
- go get -v github.com/prometheus/client_golang
|
||||
|
||||
script:
|
||||
- go build -a -v github.com/prometheus/client_golang/...
|
||||
- go test -v github.com/prometheus/client_golang/...
|
||||
- make -f Makefile.TRAVIS
|
||||
|
|
4
LICENSE
4
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2012, Matt T. Proud
|
||||
Copyright (c) 2013, Prometheus Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -19,4 +19,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
16
Makefile
16
Makefile
|
@ -16,17 +16,20 @@ MAKE_ARTIFACTS = search_index
|
|||
all: test
|
||||
|
||||
build:
|
||||
go build ./...
|
||||
$(MAKE) -C prometheus build
|
||||
$(MAKE) -C examples build
|
||||
|
||||
test: build
|
||||
go test ./... $(GO_TEST_FLAGS)
|
||||
$(MAKE) -C prometheus test
|
||||
$(MAKE) -C examples test
|
||||
|
||||
advice: test
|
||||
$(MAKE) -C prometheus advice
|
||||
$(MAKE) -C examples advice
|
||||
|
||||
format:
|
||||
find . -iname '*.go' -exec gofmt -w -s=true '{}' ';'
|
||||
|
||||
advice:
|
||||
go tool vet .
|
||||
|
||||
search_index:
|
||||
godoc -index -write_index -index_files='search_index'
|
||||
|
||||
|
@ -34,6 +37,9 @@ documentation: search_index
|
|||
godoc -http=:6060 -index -index_files='search_index'
|
||||
|
||||
clean:
|
||||
$(MAKE) -C examples clean
|
||||
rm -f $(MAKE_ARTIFACTS)
|
||||
find . -iname '*~' -exec rm -f '{}' ';'
|
||||
find . -iname '*#' -exec rm -f '{}' ';'
|
||||
|
||||
.PHONY: advice build clean documentation format test
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
PROMETHEUS_TARGET := "${GOPATH}/src/github.com/prometheus"
|
||||
|
||||
all: test
|
||||
|
||||
preparation:
|
||||
mkdir -vp $(PROMETHEUS_TARGET)
|
||||
ln -sf "$(PWD)" $(PROMETHEUS_TARGET)
|
||||
|
||||
dependencies:
|
||||
go get github.com/matttproud/gocheck
|
||||
|
||||
test: dependencies preparation
|
||||
$(MAKE) test
|
||||
|
||||
.PHONY: dependencies preparation test
|
3
TODO
3
TODO
|
@ -1,5 +1,2 @@
|
|||
- Validate repository for Go code fluency and idiomatic adherence.
|
||||
- Decouple HTTP report handler from our project and incorporate into this
|
||||
repository.
|
||||
- Implement labeled metric support.
|
||||
- Evaluate using atomic types versus locks.
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
// registry.go provides a container for centralized exposition of metrics to
|
||||
// their prospective consumers.
|
||||
//
|
||||
// registry.Register("human_readable_metric_name", "metric docstring", map[string]string{"baseLabel": "baseLabelValue"}, metric)
|
||||
package registry
|
|
@ -0,0 +1,40 @@
|
|||
Please try to observe the following rules when naming metrics:
|
||||
|
||||
- Use underbars "_" to separate words.
|
||||
|
||||
- Have the metric name start from generality and work toward specificity
|
||||
toward the end. For example, when working with multiple caching subsystems,
|
||||
consider using the following structure "cache" + "user_credentials" →
|
||||
"cache_user_credentials" and "cache" + "value_transformations" →
|
||||
"cache_value_transformations".
|
||||
|
||||
- Have whatever is being measured follow the system and subsystem names cited
|
||||
supra. For instance, with "insertions", "deletions", "evictions",
|
||||
"replacements" of the above cache, they should be named as
|
||||
"cache_user_credentials_insertions" and "cache_user_credentials_deletions"
|
||||
and "cache_user_credentials_deletions" and
|
||||
"cache_user_credentials_evictions".
|
||||
|
||||
- If what is being measured has a standardized unit around it, consider
|
||||
providing a unit for it.
|
||||
|
||||
- Consider adding an additional suffix that designates what the value
|
||||
represents such as a "total" or "size"---e.g.,
|
||||
"cache_user_credentials_size_kb" or
|
||||
"cache_user_credentials_insertions_total".
|
||||
|
||||
- Give heed to how future-proof the names are. Things may depend on these
|
||||
names; and as your service evolves, the calculated values may take on
|
||||
different meanings, which can be difficult to reflect if deployed code
|
||||
depends on antique names.
|
||||
|
||||
Further considerations:
|
||||
|
||||
- The Registry's exposition mechanism is not backed by authorization and
|
||||
authentication. This is something that will need to be addressed for
|
||||
production services that are directly exposed to the outside world.
|
||||
|
||||
- Engage in as little in-process processing of values as possible. The job
|
||||
of processing and aggregation of these values belongs in a separate
|
||||
post-processing job. The same goes for archiving. I will need to evaluate
|
||||
hooks into something like OpenTSBD.
|
|
@ -1,8 +0,0 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
// A repository of various Prometheus client documentation and advice.
|
||||
package documentation
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
// Please try to observe the following rules when naming metrics:
|
||||
//
|
||||
// - Use underbars "_" to separate words.
|
||||
//
|
||||
// - Have the metric name start from generality and work toward specificity
|
||||
// toward the end. For example, when working with multiple caching subsystems,
|
||||
// consider using the following structure "cache" + "user_credentials" →
|
||||
// "cache_user_credentials" and "cache" + "value_transformations" →
|
||||
// "cache_value_transformations".
|
||||
//
|
||||
// - Have whatever is being measured follow the system and subsystem names cited
|
||||
// supra. For instance, with "insertions", "deletions", "evictions",
|
||||
// "replacements" of the above cache, they should be named as
|
||||
// "cache_user_credentials_insertions" and "cache_user_credentials_deletions"
|
||||
// and "cache_user_credentials_deletions" and
|
||||
// "cache_user_credentials_evictions".
|
||||
//
|
||||
// - If what is being measured has a standardized unit around it, consider
|
||||
// providing a unit for it.
|
||||
//
|
||||
// - Consider adding an additional suffix that designates what the value
|
||||
// represents such as a "total" or "size"---e.g.,
|
||||
// "cache_user_credentials_size_kb" or
|
||||
// "cache_user_credentials_insertions_total".
|
||||
//
|
||||
// - Give heed to how future-proof the names are. Things may depend on these
|
||||
// names; and as your service evolves, the calculated values may take on
|
||||
// different meanings, which can be difficult to reflect if deployed code
|
||||
// depends on antique names.
|
||||
//
|
||||
// Further considerations:
|
||||
//
|
||||
// - The Registry's exposition mechanism is not backed by authorization and
|
||||
// authentication. This is something that will need to be addressed for
|
||||
// production services that are directly exposed to the outside world.
|
||||
//
|
||||
// - Engage in as little in-process processing of values as possible. The job
|
||||
// of processing and aggregation of these values belongs in a separate
|
||||
// post-processing job. The same goes for archiving. I will need to evaluate
|
||||
// hooks into something like OpenTSBD.
|
||||
|
||||
package documentation
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
all: test
|
||||
|
||||
build:
|
||||
$(MAKE) -C delegator build
|
||||
$(MAKE) -C random build
|
||||
$(MAKE) -C simple build
|
||||
|
||||
test: build
|
||||
$(MAKE) -C delegator test
|
||||
$(MAKE) -C random test
|
||||
$(MAKE) -C simple test
|
||||
|
||||
advice: test
|
||||
$(MAKE) -C delegator advice
|
||||
$(MAKE) -C random advice
|
||||
$(MAKE) -C simple advice
|
||||
|
||||
clean:
|
||||
$(MAKE) -C delegator clean
|
||||
$(MAKE) -C random clean
|
||||
$(MAKE) -C simple clean
|
||||
|
||||
.PHONY: advice build clean test
|
|
@ -0,0 +1 @@
|
|||
delegator
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
MAKE_ARTIFACTS = delegator
|
||||
|
||||
all: test
|
||||
|
||||
build: delegator
|
||||
|
||||
delegator:
|
||||
go build .
|
||||
|
||||
test: build
|
||||
go test . $(GO_TEST_FLAGS)
|
||||
|
||||
advice:
|
||||
go tool vet .
|
||||
|
||||
clean:
|
||||
rm -f $(MAKE_ARTIFACTS)
|
||||
|
||||
.PHONY: advice build clean test
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
@ -10,8 +10,8 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/prometheus/client_golang"
|
||||
"github.com/prometheus/client_golang/exp"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/exp"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -48,7 +48,7 @@ func main() {
|
|||
exp.HandleFunc("/hello", helloHandler)
|
||||
exp.HandleFunc("/goodbye", goodbyeHandler)
|
||||
exp.HandleFunc("/teapot", teapotHandler)
|
||||
exp.Handle(registry.ExpositionResource, registry.DefaultHandler)
|
||||
exp.Handle(prometheus.ExpositionResource, prometheus.DefaultHandler)
|
||||
|
||||
http.ListenAndServe(*listeningAddress, exp.DefaultCoarseMux)
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
// Various Prometheus client examples.
|
||||
package examples
|
|
@ -0,0 +1 @@
|
|||
random
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
MAKE_ARTIFACTS = random
|
||||
|
||||
all: test
|
||||
|
||||
build: random
|
||||
|
||||
random:
|
||||
go build .
|
||||
|
||||
test: build
|
||||
go test . $(GO_TEST_FLAGS)
|
||||
|
||||
advice:
|
||||
go tool vet .
|
||||
|
||||
clean:
|
||||
rm -f $(MAKE_ARTIFACTS)
|
||||
|
||||
.PHONY: advice clean build test
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
@ -13,9 +13,7 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/prometheus/client_golang"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"github.com/prometheus/client_golang/metrics"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
@ -28,27 +26,27 @@ var (
|
|||
|
||||
// Create a histogram to track fictitious interservice RPC latency for three
|
||||
// distinct services.
|
||||
rpcLatency = metrics.NewHistogram(&metrics.HistogramSpecification{
|
||||
rpcLatency = prometheus.NewHistogram(&prometheus.HistogramSpecification{
|
||||
// Four distinct histogram buckets for values:
|
||||
// - equally-sized,
|
||||
// - 0 to 50, 50 to 100, 100 to 150, and 150 to 200.
|
||||
Starts: metrics.EquallySizedBucketsFor(0, 200, 4),
|
||||
Starts: prometheus.EquallySizedBucketsFor(0, 200, 4),
|
||||
// Create histogram buckets using an accumulating bucket, a bucket that
|
||||
// holds sample values subject to an eviction policy:
|
||||
// - 50 elements are allowed per bucket.
|
||||
// - Once 50 have been reached, the bucket empties 10 elements, averages the
|
||||
// evicted elements, and re-appends that back to the bucket.
|
||||
BucketBuilder: metrics.AccumulatingBucketBuilder(metrics.EvictAndReplaceWith(10, maths.Average), 50),
|
||||
BucketBuilder: prometheus.AccumulatingBucketBuilder(prometheus.EvictAndReplaceWith(10, prometheus.AverageReducer), 50),
|
||||
// The histogram reports percentiles 1, 5, 50, 90, and 99.
|
||||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.90, 0.99},
|
||||
})
|
||||
|
||||
rpcCalls = metrics.NewCounter()
|
||||
rpcCalls = prometheus.NewCounter()
|
||||
|
||||
// If for whatever reason you are resistant to the idea of having a static
|
||||
// registry for metrics, which is a really bad idea when using Prometheus-
|
||||
// enabled library code, you can create your own.
|
||||
customRegistry = registry.NewRegistry()
|
||||
customRegistry = prometheus.NewRegistry()
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -69,13 +67,13 @@ func main() {
|
|||
}
|
||||
}()
|
||||
|
||||
http.Handle(registry.ExpositionResource, customRegistry.Handler())
|
||||
http.Handle(prometheus.ExpositionResource, customRegistry.Handler())
|
||||
http.ListenAndServe(*listeningAddress, nil)
|
||||
}
|
||||
|
||||
func init() {
|
||||
customRegistry.Register("rpc_latency_microseconds", "RPC latency.", registry.NilLabels, rpcLatency)
|
||||
customRegistry.Register("rpc_calls_total", "RPC calls.", registry.NilLabels, rpcCalls)
|
||||
customRegistry.Register("rpc_latency_microseconds", "RPC latency.", prometheus.NilLabels, rpcLatency)
|
||||
customRegistry.Register("rpc_calls_total", "RPC calls.", prometheus.NilLabels, rpcCalls)
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
simple
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
MAKE_ARTIFACTS = simple
|
||||
|
||||
all: test
|
||||
|
||||
build: simple
|
||||
|
||||
simple:
|
||||
go build .
|
||||
|
||||
test: build
|
||||
go test . $(GO_TEST_FLAGS)
|
||||
|
||||
advice:
|
||||
go tool vet .
|
||||
|
||||
clean:
|
||||
rm -f $(MAKE_ARTIFACTS)
|
||||
|
||||
.PHONY: advice build clean test
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
@ -10,14 +10,14 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/prometheus/client_golang"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
http.Handle(registry.ExpositionResource, registry.DefaultHandler)
|
||||
http.Handle(prometheus.ExpositionResource, prometheus.DefaultHandler)
|
||||
http.ListenAndServe(*listeningAddress, nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The maths package provides a number of mathematical-related helpers:
|
||||
//
|
||||
// distributions.go provides basic distribution-generating functions that are
|
||||
// used primarily in testing contexts.
|
||||
//
|
||||
// helpers_for_testing.go provides a testing assistents for this package and its
|
||||
// dependents.
|
||||
//
|
||||
// maths_test.go provides a test suite for all tests in the maths package
|
||||
// hierarchy. It employs the gocheck framework for test scaffolding.
|
||||
//
|
||||
// statistics.go provides basic summary statistics functions for the purpose of
|
||||
// metrics aggregation.
|
||||
//
|
||||
// statistics_test.go provides a test complement for the statistics.go module.
|
||||
package maths
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package maths
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type S struct{}
|
||||
|
||||
var _ = Suite(&S{})
|
||||
|
||||
func TestMaths(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// constants.go provides package-level constants for metrics.
|
||||
package metrics
|
||||
|
||||
const (
|
||||
counterTypeValue = "counter"
|
||||
floatBitCount = 64
|
||||
floatFormat = 'f'
|
||||
floatPrecision = 6
|
||||
gaugeTypeValue = "gauge"
|
||||
histogramTypeValue = "histogram"
|
||||
typeKey = "type"
|
||||
valueKey = "value"
|
||||
labelsKey = "labels"
|
||||
)
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The metrics package provides general descriptors for the concept of
|
||||
// exportable metrics.
|
||||
|
||||
// accumulating_bucket.go provides a histogram bucket type that accumulates
|
||||
// elements until a given capacity and enacts a given eviction policy upon
|
||||
// such a condition.
|
||||
|
||||
// accumulating_bucket_test.go provides a test complement for the
|
||||
// accumulating_bucket_go module.
|
||||
|
||||
// eviction.go provides several histogram bucket eviction strategies.
|
||||
|
||||
// eviction_test.go provides a test complement for the eviction.go module.
|
||||
|
||||
// gauge.go provides a scalar metric that one can monitor. It is useful for
|
||||
// certain cases, such as instantaneous temperature.
|
||||
|
||||
// gauge_test.go provides a test complement for the gauge.go module.
|
||||
|
||||
// histogram.go provides a basic histogram metric, which can accumulate scalar
|
||||
// event values or samples. The underlying histogram implementation is designed
|
||||
// to be performant in that it accepts tolerable inaccuracies.
|
||||
|
||||
// histogram_test.go provides a test complement for the histogram.go module.
|
||||
|
||||
// metric.go provides fundamental interface expectations for the various
|
||||
// metrics.
|
||||
|
||||
// metrics_test.go provides a test suite for all tests in the metrics package
|
||||
// hierarchy. It employs the gocheck framework for test scaffolding.
|
||||
|
||||
// tallying_bucket.go provides a histogram bucket type that aggregates tallies
|
||||
// of events that fall into its ranges versus a summary of the values
|
||||
// themselves.
|
||||
|
||||
// tallying_bucket_test.go provides a test complement for the
|
||||
// tallying_bucket.go module.
|
||||
|
||||
// timer.go provides a scalar metric that times how long a given event takes.
|
||||
|
||||
// timer_test.go provides a test complement for the timer.go module.
|
||||
package metrics
|
|
@ -1,179 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
. "github.com/matttproud/gocheck"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
)
|
||||
|
||||
func (s *S) TestEvictOldest(c *C) {
|
||||
q := make(utility.PriorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictOldest(5)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item utility.Item = utility.Item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 5)
|
||||
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 0.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithAverage(c *C) {
|
||||
q := make(utility.PriorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, maths.Average)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item utility.Item = utility.Item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 7.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithMedian(c *C) {
|
||||
q := make(utility.PriorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, maths.Median)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item utility.Item = utility.Item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 7.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithFirstMode(c *C) {
|
||||
q := make(utility.PriorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
e := EvictAndReplaceWith(5, maths.FirstMode)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
heap.Push(&q, &utility.Item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
})
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 9.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithMinimum(c *C) {
|
||||
q := make(utility.PriorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, maths.Minimum)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item utility.Item = utility.Item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithMaximum(c *C) {
|
||||
q := make(utility.PriorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, maths.Maximum)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item utility.Item = utility.Item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), utility.ValueEquals, 9.0)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type S struct{}
|
||||
|
||||
var _ = Suite(&S{})
|
||||
|
||||
func TestMetrics(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// This callback is called upon the completion of the timer—i.e., when it stops.
|
||||
type CompletionCallback func(duration time.Duration)
|
||||
|
||||
// This is meant to capture a function that a StopWatch can call for purposes
|
||||
// of instrumentation.
|
||||
type InstrumentableCall func()
|
||||
|
||||
// StopWatch is the structure that captures instrumentation for durations.
|
||||
|
||||
// N.B.(mtp): A major limitation hereof is that the StopWatch protocol cannot
|
||||
// retain instrumentation if a panic percolates within the context that is
|
||||
// being measured.
|
||||
type StopWatch interface {
|
||||
Stop() time.Duration
|
||||
}
|
||||
|
||||
type stopWatch struct {
|
||||
endTime time.Time
|
||||
onCompletion CompletionCallback
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
// Return a new StopWatch that is ready for instrumentation.
|
||||
func Start(onCompletion CompletionCallback) StopWatch {
|
||||
return &stopWatch{
|
||||
onCompletion: onCompletion,
|
||||
startTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the StopWatch returning the elapsed duration of its lifetime while
|
||||
// firing an optional CompletionCallback in the background.
|
||||
func (s *stopWatch) Stop() time.Duration {
|
||||
s.endTime = time.Now()
|
||||
duration := s.endTime.Sub(s.startTime)
|
||||
|
||||
if s.onCompletion != nil {
|
||||
go s.onCompletion(duration)
|
||||
}
|
||||
|
||||
return duration
|
||||
}
|
||||
|
||||
// Provide a quick way of instrumenting a InstrumentableCall and emitting its
|
||||
// duration.
|
||||
func InstrumentCall(instrumentable InstrumentableCall, onCompletion CompletionCallback) time.Duration {
|
||||
s := Start(onCompletion)
|
||||
instrumentable()
|
||||
return s.Stop()
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *S) TestTimerStart(c *C) {
|
||||
stopWatch, ok := Start(nil).(*stopWatch)
|
||||
if !ok {
|
||||
c.Check(ok, Equals, true)
|
||||
}
|
||||
|
||||
c.Assert(stopWatch, Not(IsNil))
|
||||
c.Assert(stopWatch.startTime, Not(IsNil))
|
||||
}
|
||||
|
||||
func (s *S) TestTimerStop(c *C) {
|
||||
done := make(chan bool)
|
||||
|
||||
var callbackInvoked bool = false
|
||||
var complete CompletionCallback = func(duration time.Duration) {
|
||||
callbackInvoked = true
|
||||
done <- true
|
||||
}
|
||||
|
||||
stopWatch := Start(complete)
|
||||
|
||||
c.Check(callbackInvoked, Equals, false)
|
||||
|
||||
d := stopWatch.Stop()
|
||||
|
||||
<-done
|
||||
|
||||
c.Assert(d, Not(IsNil))
|
||||
c.Check(callbackInvoked, Equals, true)
|
||||
}
|
||||
|
||||
func (s *S) TestInstrumentCall(c *C) {
|
||||
var callbackInvoked bool = false
|
||||
var instrumentableInvoked bool = false
|
||||
done := make(chan bool, 2)
|
||||
|
||||
var complete CompletionCallback = func(duration time.Duration) {
|
||||
callbackInvoked = true
|
||||
done <- true
|
||||
}
|
||||
|
||||
var instrumentable InstrumentableCall = func() {
|
||||
instrumentableInvoked = true
|
||||
done <- true
|
||||
}
|
||||
|
||||
d := InstrumentCall(instrumentable, complete)
|
||||
|
||||
c.Assert(d, Not(IsNil))
|
||||
|
||||
<-done
|
||||
<-done
|
||||
|
||||
c.Check(instrumentableInvoked, Equals, true)
|
||||
c.Check(callbackInvoked, Equals, true)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
command-line-arguments.test
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
all: test
|
||||
|
||||
build:
|
||||
go build ./...
|
||||
|
||||
test: build
|
||||
go test ./... $(GO_TEST_FLAGS)
|
||||
|
||||
advice:
|
||||
go tool vet .
|
||||
|
||||
.PHONY: advice build test
|
|
@ -1,16 +1,15 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
|
@ -18,7 +17,7 @@ import (
|
|||
)
|
||||
|
||||
type AccumulatingBucket struct {
|
||||
elements utility.PriorityQueue
|
||||
elements priorityQueue
|
||||
evictionPolicy EvictionPolicy
|
||||
maximumSize int
|
||||
mutex sync.RWMutex
|
||||
|
@ -31,7 +30,7 @@ type AccumulatingBucket struct {
|
|||
func AccumulatingBucketBuilder(evictionPolicy EvictionPolicy, maximumSize int) BucketBuilder {
|
||||
return func() Bucket {
|
||||
return &AccumulatingBucket{
|
||||
elements: make(utility.PriorityQueue, 0, maximumSize),
|
||||
elements: make(priorityQueue, 0, maximumSize),
|
||||
evictionPolicy: evictionPolicy,
|
||||
maximumSize: maximumSize,
|
||||
}
|
||||
|
@ -47,7 +46,7 @@ func (b *AccumulatingBucket) Add(value float64) {
|
|||
b.observations++
|
||||
size := len(b.elements)
|
||||
|
||||
v := utility.Item{
|
||||
v := item{
|
||||
Priority: -1 * time.Now().UnixNano(),
|
||||
Value: value,
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -51,7 +49,7 @@ func (s *S) TestAccumulatingBucketBuilderWithEvictOldest(c *C) {
|
|||
}
|
||||
|
||||
func (s *S) TestAccumulatingBucketBuilderWithEvictAndReplaceWithAverage(c *C) {
|
||||
var evictAndReplaceWithAverage EvictionPolicy = EvictAndReplaceWith(3, maths.Average)
|
||||
var evictAndReplaceWithAverage EvictionPolicy = EvictAndReplaceWith(3, AverageReducer)
|
||||
|
||||
c.Assert(evictAndReplaceWithAverage, Not(IsNil))
|
||||
|
||||
|
@ -86,7 +84,7 @@ func (s *S) TestAccumulatingBucketBuilderWithEvictAndReplaceWithAverage(c *C) {
|
|||
|
||||
func (s *S) TestAccumulatingBucket(c *C) {
|
||||
var b AccumulatingBucket = AccumulatingBucket{
|
||||
elements: make(utility.PriorityQueue, 0, 10),
|
||||
elements: make(priorityQueue, 0, 10),
|
||||
maximumSize: 5,
|
||||
}
|
||||
|
||||
|
@ -112,13 +110,13 @@ func (s *S) TestAccumulatingBucket(c *C) {
|
|||
|
||||
func (s *S) TestAccumulatingBucketValueForIndex(c *C) {
|
||||
var b AccumulatingBucket = AccumulatingBucket{
|
||||
elements: make(utility.PriorityQueue, 0, 100),
|
||||
elements: make(priorityQueue, 0, 100),
|
||||
maximumSize: 100,
|
||||
evictionPolicy: EvictOldest(50),
|
||||
}
|
||||
|
||||
for i := 0; i <= 100; i++ {
|
||||
c.Assert(b.ValueForIndex(i), maths.IsNaN)
|
||||
c.Assert(b.ValueForIndex(i), IsNaN)
|
||||
}
|
||||
|
||||
// The bucket has only observed one item and contains now one item.
|
|
@ -1,12 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// bucket.go provides fundamental interface expectations for various bucket
|
||||
// types.
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
// The Histogram class and associated types build buckets on their own.
|
||||
type BucketBuilder func() Bucket
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package registry
|
||||
package prometheus
|
||||
|
||||
var (
|
||||
// NilLabels is a nil set of labels merely for end-user convenience.
|
||||
|
@ -14,8 +14,7 @@ var (
|
|||
// interface.
|
||||
DefaultHandler = DefaultRegistry.Handler()
|
||||
|
||||
// This is the default registry with which Metric objects are associated. It
|
||||
// is primarily a read-only object after server instantiation.
|
||||
// This is the default registry with which Metric objects are associated.
|
||||
DefaultRegistry = NewRegistry()
|
||||
)
|
||||
|
||||
|
@ -39,4 +38,14 @@ const (
|
|||
docstringKey = "docstring"
|
||||
metricKey = "metric"
|
||||
nameLabel = "name"
|
||||
|
||||
counterTypeValue = "counter"
|
||||
floatBitCount = 64
|
||||
floatFormat = 'f'
|
||||
floatPrecision = 6
|
||||
gaugeTypeValue = "gauge"
|
||||
histogramTypeValue = "histogram"
|
||||
typeKey = "type"
|
||||
valueKey = "value"
|
||||
labelsKey = "labels"
|
||||
)
|
|
@ -1,33 +1,32 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TODO(matt): Refactor to de-duplicate behaviors.
|
||||
|
||||
type Counter interface {
|
||||
AsMarshallable() map[string]interface{}
|
||||
Metric
|
||||
|
||||
Decrement(labels map[string]string) float64
|
||||
DecrementBy(labels map[string]string, value float64) float64
|
||||
Increment(labels map[string]string) float64
|
||||
IncrementBy(labels map[string]string, value float64) float64
|
||||
ResetAll()
|
||||
Set(labels map[string]string, value float64) float64
|
||||
String() string
|
||||
}
|
||||
|
||||
type counterVector struct {
|
||||
labels map[string]string
|
||||
value float64
|
||||
Labels map[string]string `json:"labels"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
func NewCounter() Counter {
|
||||
|
@ -49,13 +48,13 @@ func (metric *counter) Set(labels map[string]string, value float64) float64 {
|
|||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
signature := utility.LabelsToSignature(labels)
|
||||
signature := labelsToSignature(labels)
|
||||
if original, ok := metric.values[signature]; ok {
|
||||
original.value = value
|
||||
original.Value = value
|
||||
} else {
|
||||
metric.values[signature] = &counterVector{
|
||||
labels: labels,
|
||||
value: value,
|
||||
Labels: labels,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,8 +66,8 @@ func (metric *counter) ResetAll() {
|
|||
defer metric.mutex.Unlock()
|
||||
|
||||
for key, value := range metric.values {
|
||||
for label := range value.labels {
|
||||
delete(value.labels, label)
|
||||
for label := range value.Labels {
|
||||
delete(value.Labels, label)
|
||||
}
|
||||
delete(metric.values, key)
|
||||
}
|
||||
|
@ -91,13 +90,13 @@ func (metric *counter) IncrementBy(labels map[string]string, value float64) floa
|
|||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
signature := utility.LabelsToSignature(labels)
|
||||
signature := labelsToSignature(labels)
|
||||
if original, ok := metric.values[signature]; ok {
|
||||
original.value += value
|
||||
original.Value += value
|
||||
} else {
|
||||
metric.values[signature] = &counterVector{
|
||||
labels: labels,
|
||||
value: value,
|
||||
Labels: labels,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,13 +115,13 @@ func (metric *counter) DecrementBy(labels map[string]string, value float64) floa
|
|||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
signature := utility.LabelsToSignature(labels)
|
||||
signature := labelsToSignature(labels)
|
||||
if original, ok := metric.values[signature]; ok {
|
||||
original.value -= value
|
||||
original.Value -= value
|
||||
} else {
|
||||
metric.values[signature] = &counterVector{
|
||||
labels: labels,
|
||||
value: -1 * value,
|
||||
Labels: labels,
|
||||
Value: -1 * value,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,20 +132,18 @@ func (metric *counter) Decrement(labels map[string]string) float64 {
|
|||
return metric.DecrementBy(labels, 1)
|
||||
}
|
||||
|
||||
func (metric counter) AsMarshallable() map[string]interface{} {
|
||||
func (metric counter) MarshalJSON() ([]byte, error) {
|
||||
metric.mutex.RLock()
|
||||
defer metric.mutex.RUnlock()
|
||||
|
||||
values := make([]map[string]interface{}, 0, len(metric.values))
|
||||
values := make([]*counterVector, 0, len(metric.values))
|
||||
|
||||
for _, value := range metric.values {
|
||||
values = append(values, map[string]interface{}{
|
||||
labelsKey: value.labels,
|
||||
valueKey: value.value,
|
||||
})
|
||||
values = append(values, value)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
return json.Marshal(map[string]interface{}{
|
||||
valueKey: values,
|
||||
typeKey: counterTypeValue,
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/prometheus/client_golang/utility/test"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testCounter(t test.Tester) {
|
||||
func testCounter(t tester) {
|
||||
type input struct {
|
||||
steps []func(g Counter)
|
||||
}
|
||||
|
@ -29,7 +28,7 @@ func testCounter(t test.Tester) {
|
|||
steps: []func(g Counter){},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[]}",
|
||||
value: `{"type":"counter","value":[]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -41,7 +40,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{},\"value\":1}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{},"value":1}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -53,7 +52,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{},\"value\":2}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{},"value":2}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -68,7 +67,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{},\"value\":5}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{},"value":5}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -86,7 +85,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[]}",
|
||||
value: `{"type":"counter","value":[]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -98,7 +97,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":19}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":19}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -113,7 +112,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":24}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":24}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -125,7 +124,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":1}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":1}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -137,7 +136,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":-1}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":-1}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -152,7 +151,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":28}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":28}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -167,7 +166,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":36}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":36}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -182,7 +181,7 @@ func testCounter(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"counter\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":27}]}",
|
||||
value: `{"type":"counter","value":[{"labels":{"handler":"/foo"},"value":27}]}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -194,9 +193,7 @@ func testCounter(t test.Tester) {
|
|||
step(counter)
|
||||
}
|
||||
|
||||
marshallable := counter.AsMarshallable()
|
||||
|
||||
bytes, err := json.Marshal(marshallable)
|
||||
bytes, err := json.Marshal(counter)
|
||||
if err != nil {
|
||||
t.Errorf("%d. could not marshal into JSON %s", i, err)
|
||||
continue
|
|
@ -1,17 +1,17 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package maths
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Go's standard library does not offer a factorial function.
|
||||
func Factorial(of int) int64 {
|
||||
func factorial(of int) int64 {
|
||||
if of <= 0 {
|
||||
return 1
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ func Factorial(of int) int64 {
|
|||
// Calculate the value of a probability density for a given binomial statistic,
|
||||
// where k is the target count of true cases, n is the number of subjects, and
|
||||
// p is the probability.
|
||||
func BinomialPDF(k, n int, p float64) float64 {
|
||||
binomialCoefficient := float64(Factorial(n)) / float64(Factorial(k)*Factorial(n-k))
|
||||
func binomialPDF(k, n int, p float64) float64 {
|
||||
binomialCoefficient := float64(factorial(n)) / float64(factorial(k)*factorial(n-k))
|
||||
intermediate := math.Pow(p, float64(k)) * math.Pow(1-p, float64(n-k))
|
||||
|
||||
return binomialCoefficient * intermediate
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
// Prometheus' client side metric primitives and telemetry exposition framework.
|
||||
//
|
||||
// This package provides both metric primitives and tools for their exposition
|
||||
// to the Prometheus time series collection and computation framework.
|
||||
//
|
||||
// prometheus.Register("human_readable_metric_name", "metric docstring", map[string]string{"baseLabel": "baseLabelValue"}, metric)
|
||||
//
|
||||
// The examples under github.com/prometheus/client_golang/examples should be
|
||||
// consulted.
|
||||
package prometheus
|
|
@ -1,15 +1,13 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -29,17 +27,17 @@ func EvictOldest(count int) EvictionPolicy {
|
|||
|
||||
// This factory produces an EvictionPolicy that applies some standardized
|
||||
// reduction methodology on the to-be-terminated values.
|
||||
func EvictAndReplaceWith(count int, reducer maths.ReductionMethod) EvictionPolicy {
|
||||
func EvictAndReplaceWith(count int, reducer ReductionMethod) EvictionPolicy {
|
||||
return func(h heap.Interface) {
|
||||
oldValues := make([]float64, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
oldValues[i] = heap.Pop(h).(*utility.Item).Value.(float64)
|
||||
oldValues[i] = heap.Pop(h).(*item).Value.(float64)
|
||||
}
|
||||
|
||||
reduced := reducer(oldValues)
|
||||
|
||||
heap.Push(h, &utility.Item{
|
||||
heap.Push(h, &item{
|
||||
Value: reduced,
|
||||
// TODO(mtp): Parameterize the priority generation since these tools are
|
||||
// useful.
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
. "github.com/matttproud/gocheck"
|
||||
)
|
||||
|
||||
func (s *S) TestEvictOldest(c *C) {
|
||||
q := make(priorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictOldest(5)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item item = item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 5)
|
||||
|
||||
c.Check(heap.Pop(&q), ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 0.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithAverage(c *C) {
|
||||
q := make(priorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, AverageReducer)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item item = item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 7.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithMedian(c *C) {
|
||||
q := make(priorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, MedianReducer)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item item = item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 7.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithFirstMode(c *C) {
|
||||
q := make(priorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
e := EvictAndReplaceWith(5, FirstModeReducer)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
heap.Push(&q, &item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
})
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 9.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithMinimum(c *C) {
|
||||
q := make(priorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, MinimumReducer)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item item = item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestEvictAndReplaceWithMaximum(c *C) {
|
||||
q := make(priorityQueue, 0, 10)
|
||||
heap.Init(&q)
|
||||
var e EvictionPolicy = EvictAndReplaceWith(5, MaximumReducer)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var item item = item{
|
||||
Priority: int64(i),
|
||||
Value: float64(i),
|
||||
}
|
||||
|
||||
heap.Push(&q, &item)
|
||||
}
|
||||
|
||||
c.Check(q, HasLen, 10)
|
||||
|
||||
e(&q)
|
||||
|
||||
c.Check(q, HasLen, 6)
|
||||
|
||||
c.Check(heap.Pop(&q), ValueEquals, 4.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 3.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 2.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 1.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 0.0)
|
||||
c.Check(heap.Pop(&q), ValueEquals, 9.0)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
||||
|
@ -8,8 +8,7 @@ package exp
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang"
|
||||
"github.com/prometheus/client_golang/metrics"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -33,11 +32,11 @@ type (
|
|||
)
|
||||
|
||||
var (
|
||||
requestCounts = metrics.NewCounter()
|
||||
requestDuration = metrics.NewCounter()
|
||||
requestDurations = metrics.NewDefaultHistogram()
|
||||
requestBytes = metrics.NewCounter()
|
||||
responseBytes = metrics.NewCounter()
|
||||
requestCounts = prometheus.NewCounter()
|
||||
requestDuration = prometheus.NewCounter()
|
||||
requestDurations = prometheus.NewDefaultHistogram()
|
||||
requestBytes = prometheus.NewCounter()
|
||||
responseBytes = prometheus.NewCounter()
|
||||
|
||||
// DefaultCoarseMux is a drop-in replacement for http.DefaultServeMux that
|
||||
// provides standardized telemetry for Go's standard HTTP handler registration
|
||||
|
@ -103,9 +102,9 @@ func HandleFunc(pattern string, handler http.HandlerFunc) {
|
|||
}
|
||||
|
||||
func init() {
|
||||
registry.Register("http_requests_total", "A counter of the total number of HTTP requests made against the default multiplexor.", registry.NilLabels, requestCounts)
|
||||
registry.Register("http_request_durations_total_microseconds", "The total amount of time the default multiplexor has spent answering HTTP requests (microseconds).", registry.NilLabels, requestDuration)
|
||||
registry.Register("http_request_durations_microseconds", "The amounts of time the default multiplexor has spent answering HTTP requests (microseconds).", registry.NilLabels, requestDurations)
|
||||
registry.Register("http_request_bytes_total", "The total volume of content body sizes received (bytes).", registry.NilLabels, requestBytes)
|
||||
registry.Register("http_response_bytes_total", "The total volume of response payloads emitted (bytes).", registry.NilLabels, responseBytes)
|
||||
prometheus.Register("http_requests_total", "A counter of the total number of HTTP requests made against the default multiplexor.", prometheus.NilLabels, requestCounts)
|
||||
prometheus.Register("http_request_durations_total_microseconds", "The total amount of time the default multiplexor has spent answering HTTP requests (microseconds).", prometheus.NilLabels, requestDuration)
|
||||
prometheus.Register("http_request_durations_microseconds", "The amounts of time the default multiplexor has spent answering HTTP requests (microseconds).", prometheus.NilLabels, requestDurations)
|
||||
prometheus.Register("http_request_bytes_total", "The total volume of content body sizes received (bytes).", prometheus.NilLabels, requestBytes)
|
||||
prometheus.Register("http_response_bytes_total", "The total volume of response payloads emitted (bytes).", prometheus.NilLabels, responseBytes)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
|
@ -1,14 +1,14 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
@ -17,15 +17,13 @@ import (
|
|||
// temperature or the hitherto bandwidth used, this would be the metric for such
|
||||
// circumstances.
|
||||
type Gauge interface {
|
||||
AsMarshallable() map[string]interface{}
|
||||
ResetAll()
|
||||
Metric
|
||||
Set(labels map[string]string, value float64) float64
|
||||
String() string
|
||||
}
|
||||
|
||||
type gaugeVector struct {
|
||||
labels map[string]string
|
||||
value float64
|
||||
Labels map[string]string `json:"labels"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
func NewGauge() Gauge {
|
||||
|
@ -56,14 +54,14 @@ func (metric *gauge) Set(labels map[string]string, value float64) float64 {
|
|||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
signature := utility.LabelsToSignature(labels)
|
||||
signature := labelsToSignature(labels)
|
||||
|
||||
if original, ok := metric.values[signature]; ok {
|
||||
original.value = value
|
||||
original.Value = value
|
||||
} else {
|
||||
metric.values[signature] = &gaugeVector{
|
||||
labels: labels,
|
||||
value: value,
|
||||
Labels: labels,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,27 +73,24 @@ func (metric *gauge) ResetAll() {
|
|||
defer metric.mutex.Unlock()
|
||||
|
||||
for key, value := range metric.values {
|
||||
for label := range value.labels {
|
||||
delete(value.labels, label)
|
||||
for label := range value.Labels {
|
||||
delete(value.Labels, label)
|
||||
}
|
||||
delete(metric.values, key)
|
||||
}
|
||||
}
|
||||
|
||||
func (metric gauge) AsMarshallable() map[string]interface{} {
|
||||
func (metric gauge) MarshalJSON() ([]byte, error) {
|
||||
metric.mutex.RLock()
|
||||
defer metric.mutex.RUnlock()
|
||||
|
||||
values := make([]map[string]interface{}, 0, len(metric.values))
|
||||
values := make([]*gaugeVector, 0, len(metric.values))
|
||||
for _, value := range metric.values {
|
||||
values = append(values, map[string]interface{}{
|
||||
labelsKey: value.labels,
|
||||
valueKey: value.value,
|
||||
})
|
||||
values = append(values, value)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
return json.Marshal(map[string]interface{}{
|
||||
typeKey: gaugeTypeValue,
|
||||
valueKey: values,
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/prometheus/client_golang/utility/test"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testGauge(t test.Tester) {
|
||||
func testGauge(t tester) {
|
||||
type input struct {
|
||||
steps []func(g Gauge)
|
||||
}
|
||||
|
@ -29,7 +28,7 @@ func testGauge(t test.Tester) {
|
|||
steps: []func(g Gauge){},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"gauge\",\"value\":[]}",
|
||||
value: `{"type":"gauge","value":[]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -41,7 +40,7 @@ func testGauge(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"gauge\",\"value\":[{\"labels\":{},\"value\":1}]}",
|
||||
value: `{"type":"gauge","value":[{"labels":{},"value":1}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -53,7 +52,7 @@ func testGauge(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"gauge\",\"value\":[{\"labels\":{},\"value\":2}]}",
|
||||
value: `{"type":"gauge","value":[{"labels":{},"value":2}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -68,7 +67,7 @@ func testGauge(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"gauge\",\"value\":[{\"labels\":{},\"value\":5}]}",
|
||||
value: `{"type":"gauge","value":[{"labels":{},"value":5}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -86,7 +85,7 @@ func testGauge(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"gauge\",\"value\":[]}",
|
||||
value: `{"type":"gauge","value":[]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -98,7 +97,7 @@ func testGauge(t test.Tester) {
|
|||
},
|
||||
},
|
||||
out: output{
|
||||
value: "{\"type\":\"gauge\",\"value\":[{\"labels\":{\"handler\":\"/foo\"},\"value\":19}]}",
|
||||
value: `{"type":"gauge","value":[{"labels":{"handler":"/foo"},"value":19}]}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -110,9 +109,7 @@ func testGauge(t test.Tester) {
|
|||
step(gauge)
|
||||
}
|
||||
|
||||
marshallable := gauge.AsMarshallable()
|
||||
|
||||
bytes, err := json.Marshal(marshallable)
|
||||
bytes, err := json.Marshal(gauge)
|
||||
if err != nil {
|
||||
t.Errorf("%d. could not marshal into JSON %s", i, err)
|
||||
continue
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package maths
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
|
@ -1,16 +1,15 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -54,10 +53,8 @@ type HistogramSpecification struct {
|
|||
}
|
||||
|
||||
type Histogram interface {
|
||||
Metric
|
||||
Add(labels map[string]string, value float64)
|
||||
AsMarshallable() map[string]interface{}
|
||||
ResetAll()
|
||||
String() string
|
||||
}
|
||||
|
||||
// The histogram is an accumulator for samples. It merely routes into which
|
||||
|
@ -96,7 +93,7 @@ func (h *histogram) Add(labels map[string]string, value float64) {
|
|||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
signature := utility.LabelsToSignature(labels)
|
||||
signature := labelsToSignature(labels)
|
||||
var histogram *histogramVector = nil
|
||||
if original, ok := h.values[signature]; ok {
|
||||
histogram = original
|
||||
|
@ -242,29 +239,30 @@ func formatFloat(value float64) string {
|
|||
return strconv.FormatFloat(value, floatFormat, floatPrecision, floatBitCount)
|
||||
}
|
||||
|
||||
func (h histogram) AsMarshallable() map[string]interface{} {
|
||||
func (h histogram) MarshalJSON() ([]byte, error) {
|
||||
h.mutex.RLock()
|
||||
defer h.mutex.RUnlock()
|
||||
|
||||
result := make(map[string]interface{}, 2)
|
||||
result[typeKey] = histogramTypeValue
|
||||
values := make([]map[string]interface{}, 0, len(h.values))
|
||||
|
||||
for signature, value := range h.values {
|
||||
metricContainer := map[string]interface{}{}
|
||||
metricContainer[labelsKey] = value.labels
|
||||
intermediate := map[string]interface{}{}
|
||||
percentiles := make(map[string]float64, len(h.reportablePercentiles))
|
||||
|
||||
for _, percentile := range h.reportablePercentiles {
|
||||
formatted := formatFloat(percentile)
|
||||
intermediate[formatted] = h.percentile(signature, percentile)
|
||||
percentiles[formatted] = h.percentile(signature, percentile)
|
||||
}
|
||||
metricContainer[valueKey] = intermediate
|
||||
values = append(values, metricContainer)
|
||||
|
||||
values = append(values, map[string]interface{}{
|
||||
labelsKey: value.labels,
|
||||
valueKey: percentiles,
|
||||
})
|
||||
}
|
||||
|
||||
result[valueKey] = values
|
||||
|
||||
return result
|
||||
return json.Marshal(map[string]interface{}{
|
||||
typeKey: histogramTypeValue,
|
||||
valueKey: values,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *histogram) ResetAll() {
|
||||
|
@ -298,7 +296,7 @@ func NewDefaultHistogram() Histogram {
|
|||
return NewHistogram(
|
||||
&HistogramSpecification{
|
||||
Starts: LogarithmicSizedBucketsFor(0, 4096),
|
||||
BucketBuilder: AccumulatingBucketBuilder(EvictAndReplaceWith(10, maths.Average), 50),
|
||||
BucketBuilder: AccumulatingBucketBuilder(EvictAndReplaceWith(10, AverageReducer), 50),
|
||||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.90, 0.99},
|
||||
},
|
||||
)
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
// TODO(matt): Re-Add tests for this type.
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package test
|
||||
package prometheus
|
||||
|
||||
type Tester interface {
|
||||
type tester interface {
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatal(args ...interface{})
|
|
@ -1,15 +1,17 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// A Metric is something that can be exposed via the registry framework.
|
||||
type Metric interface {
|
||||
// Produce a JSON-consumable representation of the metric.
|
||||
AsMarshallable() map[string]interface{}
|
||||
// Produce a JSON representation of the metric.
|
||||
json.Marshaler
|
||||
// Reset the parent metrics and delete all child metrics.
|
||||
ResetAll()
|
||||
// Produce a human-consumable representation of the metric.
|
|
@ -1,44 +1,44 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utility
|
||||
package prometheus
|
||||
|
||||
type Item struct {
|
||||
type item struct {
|
||||
Priority int64
|
||||
Value interface{}
|
||||
index int
|
||||
}
|
||||
|
||||
type PriorityQueue []*Item
|
||||
type priorityQueue []*item
|
||||
|
||||
func (q PriorityQueue) Len() int {
|
||||
func (q priorityQueue) Len() int {
|
||||
return len(q)
|
||||
}
|
||||
|
||||
func (q PriorityQueue) Less(i, j int) bool {
|
||||
func (q priorityQueue) Less(i, j int) bool {
|
||||
return q[i].Priority > q[j].Priority
|
||||
}
|
||||
|
||||
func (q PriorityQueue) Swap(i, j int) {
|
||||
func (q priorityQueue) Swap(i, j int) {
|
||||
q[i], q[j] = q[j], q[i]
|
||||
q[i].index = i
|
||||
q[j].index = j
|
||||
}
|
||||
|
||||
func (q *PriorityQueue) Push(x interface{}) {
|
||||
func (q *priorityQueue) Push(x interface{}) {
|
||||
queue := *q
|
||||
size := len(queue)
|
||||
queue = queue[0 : size+1]
|
||||
item := x.(*Item)
|
||||
item := x.(*item)
|
||||
item.index = size
|
||||
queue[size] = item
|
||||
*q = queue
|
||||
}
|
||||
|
||||
func (q *PriorityQueue) Pop() interface{} {
|
||||
func (q *priorityQueue) Pop() interface{} {
|
||||
queue := *q
|
||||
size := len(queue)
|
||||
item := queue[size-1]
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utility
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
|
@ -12,16 +12,16 @@ import (
|
|||
)
|
||||
|
||||
func (s *S) TestPriorityQueueSort(c *C) {
|
||||
q := make(PriorityQueue, 0, 6)
|
||||
q := make(priorityQueue, 0, 6)
|
||||
|
||||
c.Check(len(q), Equals, 0)
|
||||
|
||||
heap.Push(&q, &Item{Value: "newest", Priority: -100})
|
||||
heap.Push(&q, &Item{Value: "older", Priority: 90})
|
||||
heap.Push(&q, &Item{Value: "oldest", Priority: 100})
|
||||
heap.Push(&q, &Item{Value: "newer", Priority: -90})
|
||||
heap.Push(&q, &Item{Value: "new", Priority: -80})
|
||||
heap.Push(&q, &Item{Value: "old", Priority: 80})
|
||||
heap.Push(&q, &item{Value: "newest", Priority: -100})
|
||||
heap.Push(&q, &item{Value: "older", Priority: 90})
|
||||
heap.Push(&q, &item{Value: "oldest", Priority: 100})
|
||||
heap.Push(&q, &item{Value: "newer", Priority: -90})
|
||||
heap.Push(&q, &item{Value: "new", Priority: -80})
|
||||
heap.Push(&q, &item{Value: "old", Priority: 80})
|
||||
|
||||
c.Check(len(q), Equals, 6)
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utility
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
|
@ -15,6 +15,6 @@ type S struct{}
|
|||
|
||||
var _ = Suite(&S{})
|
||||
|
||||
func TestUtility(t *testing.T) {
|
||||
func TestPrometheus(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package registry
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
|
@ -12,14 +12,13 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/metrics"
|
||||
"github.com/prometheus/client_golang/utility"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -44,9 +43,9 @@ var (
|
|||
// container represents a top-level registered metric that encompasses its
|
||||
// static metadata.
|
||||
type container struct {
|
||||
baseLabels map[string]string
|
||||
docstring string
|
||||
metric metrics.Metric
|
||||
BaseLabels map[string]string `json:"baseLabels"`
|
||||
Docstring string `json:"docstring"`
|
||||
Metric Metric `json:"metric"`
|
||||
name string
|
||||
}
|
||||
|
||||
|
@ -61,7 +60,7 @@ type registry struct {
|
|||
// own.
|
||||
type Registry interface {
|
||||
// Register a metric with a given name. Name should be globally unique.
|
||||
Register(name, docstring string, baseLabels map[string]string, metric metrics.Metric) error
|
||||
Register(name, docstring string, baseLabels map[string]string, metric Metric) error
|
||||
// Create a http.HandlerFunc that is tied to a Registry such that requests
|
||||
// against it generate a representation of the housed metrics.
|
||||
Handler() http.HandlerFunc
|
||||
|
@ -79,10 +78,28 @@ func NewRegistry() Registry {
|
|||
}
|
||||
|
||||
// Associate a Metric with the DefaultRegistry.
|
||||
func Register(name, docstring string, baseLabels map[string]string, metric metrics.Metric) error {
|
||||
func Register(name, docstring string, baseLabels map[string]string, metric Metric) error {
|
||||
return DefaultRegistry.Register(name, docstring, baseLabels, metric)
|
||||
}
|
||||
|
||||
// Implements json.Marshaler
|
||||
func (r registry) MarshalJSON() (_ []byte, err error) {
|
||||
metrics := make([]interface{}, 0, len(r.signatureContainers))
|
||||
|
||||
keys := make([]string, 0, len(metrics))
|
||||
for key := range r.signatureContainers {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
metrics = append(metrics, r.signatureContainers[key])
|
||||
}
|
||||
|
||||
return json.Marshal(metrics)
|
||||
}
|
||||
|
||||
// isValidCandidate returns true if the candidate is acceptable for use. In the
|
||||
// event of any apparent incorrect use it will report the problem, invalidate
|
||||
// the candidate, or outright abort.
|
||||
|
@ -110,7 +127,7 @@ func (r registry) isValidCandidate(name string, baseLabels map[string]string) (s
|
|||
}
|
||||
|
||||
baseLabels[nameLabel] = name
|
||||
signature = utility.LabelsToSignature(baseLabels)
|
||||
signature = labelsToSignature(baseLabels)
|
||||
|
||||
if _, contains := r.signatureContainers[signature]; contains {
|
||||
err = fmt.Errorf("metric named %s with baseLabels %s is already registered", name, baseLabels)
|
||||
|
@ -126,7 +143,7 @@ func (r registry) isValidCandidate(name string, baseLabels map[string]string) (s
|
|||
if useAggressiveSanityChecks {
|
||||
for _, container := range r.signatureContainers {
|
||||
if container.name == name {
|
||||
err = fmt.Errorf("metric named %s with baseLabels %s is already registered as %s and risks causing confusion", name, baseLabels, container.baseLabels)
|
||||
err = fmt.Errorf("metric named %s with baseLabels %s is already registered as %s and risks causing confusion", name, baseLabels, container.BaseLabels)
|
||||
if abortOnMisuse {
|
||||
panic(err)
|
||||
} else if debugRegistration {
|
||||
|
@ -141,7 +158,7 @@ func (r registry) isValidCandidate(name string, baseLabels map[string]string) (s
|
|||
return
|
||||
}
|
||||
|
||||
func (r registry) Register(name, docstring string, baseLabels map[string]string, metric metrics.Metric) (err error) {
|
||||
func (r registry) Register(name, docstring string, baseLabels map[string]string, metric Metric) (err error) {
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
|
||||
|
@ -155,9 +172,9 @@ func (r registry) Register(name, docstring string, baseLabels map[string]string,
|
|||
}
|
||||
|
||||
r.signatureContainers[signature] = container{
|
||||
baseLabels: baseLabels,
|
||||
docstring: docstring,
|
||||
metric: metric,
|
||||
BaseLabels: baseLabels,
|
||||
Docstring: docstring,
|
||||
Metric: metric,
|
||||
name: name,
|
||||
}
|
||||
|
||||
|
@ -195,61 +212,6 @@ func (register registry) YieldBasicAuthExporter(username, password string) http.
|
|||
})
|
||||
}
|
||||
|
||||
func (registry registry) dumpToWriter(writer io.Writer) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
dumpErrorCount.Increment(nil)
|
||||
}
|
||||
}()
|
||||
|
||||
numberOfMetrics := len(registry.signatureContainers)
|
||||
keys := make([]string, 0, numberOfMetrics)
|
||||
for key := range registry.signatureContainers {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
_, err = writer.Write([]byte("["))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
index := 0
|
||||
|
||||
for _, key := range keys {
|
||||
container := registry.signatureContainers[key]
|
||||
intermediate := map[string]interface{}{
|
||||
baseLabelsKey: container.baseLabels,
|
||||
docstringKey: container.docstring,
|
||||
metricKey: container.metric.AsMarshallable(),
|
||||
}
|
||||
marshaled, err := json.Marshal(intermediate)
|
||||
if err != nil {
|
||||
marshalErrorCount.Increment(nil)
|
||||
index++
|
||||
continue
|
||||
}
|
||||
|
||||
if index > 0 && index < numberOfMetrics {
|
||||
_, err = writer.Write([]byte(","))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = writer.Write(marshaled)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
_, err = writer.Write([]byte("]"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// decorateWriter annotates the response writer to handle any other behaviors
|
||||
// that might be beneficial to the client---e.g., GZIP encoding.
|
||||
func decorateWriter(request *http.Request, writer http.ResponseWriter) io.Writer {
|
||||
|
@ -271,29 +233,26 @@ func (registry registry) YieldExporter() http.HandlerFunc {
|
|||
|
||||
func (registry registry) Handler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var instrumentable metrics.InstrumentableCall = func() {
|
||||
requestCount.Increment(nil)
|
||||
url := r.URL
|
||||
defer requestLatencyAccumulator(time.Now())
|
||||
|
||||
if strings.HasSuffix(url.Path, jsonSuffix) {
|
||||
header := w.Header()
|
||||
header.Set(ProtocolVersionHeader, APIVersion)
|
||||
header.Set(contentTypeHeader, jsonContentType)
|
||||
requestCount.Increment(nil)
|
||||
url := r.URL
|
||||
|
||||
writer := decorateWriter(r, w)
|
||||
if strings.HasSuffix(url.Path, jsonSuffix) {
|
||||
header := w.Header()
|
||||
header.Set(ProtocolVersionHeader, APIVersion)
|
||||
header.Set(contentTypeHeader, jsonContentType)
|
||||
|
||||
if closer, ok := writer.(io.Closer); ok {
|
||||
defer closer.Close()
|
||||
}
|
||||
writer := decorateWriter(r, w)
|
||||
|
||||
registry.dumpToWriter(writer)
|
||||
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
if closer, ok := writer.(io.Closer); ok {
|
||||
defer closer.Close()
|
||||
}
|
||||
|
||||
json.NewEncoder(writer).Encode(registry)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
metrics.InstrumentCall(instrumentable, requestLatencyAccumulator)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,21 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package registry
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/metrics"
|
||||
"github.com/prometheus/client_golang/utility/test"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testRegister(t test.Tester) {
|
||||
func testRegister(t tester) {
|
||||
var oldState = struct {
|
||||
abortOnMisuse bool
|
||||
debugRegistration bool
|
||||
|
@ -181,7 +180,7 @@ func (r *fakeResponseWriter) Write(d []byte) (l int, err error) {
|
|||
func (r *fakeResponseWriter) WriteHeader(c int) {
|
||||
}
|
||||
|
||||
func testDecorateWriter(t test.Tester) {
|
||||
func testDecorateWriter(t tester) {
|
||||
type input struct {
|
||||
headers map[string]string
|
||||
body []byte
|
||||
|
@ -266,9 +265,9 @@ func BenchmarkDecorateWriter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func testDumpToWriter(t test.Tester) {
|
||||
func testDumpToWriter(t tester) {
|
||||
type input struct {
|
||||
metrics map[string]metrics.Metric
|
||||
metrics map[string]Metric
|
||||
}
|
||||
|
||||
var scenarios = []struct {
|
||||
|
@ -280,20 +279,20 @@ func testDumpToWriter(t test.Tester) {
|
|||
},
|
||||
{
|
||||
in: input{
|
||||
metrics: map[string]metrics.Metric{
|
||||
"foo": metrics.NewCounter(),
|
||||
metrics: map[string]Metric{
|
||||
"foo": NewCounter(),
|
||||
},
|
||||
},
|
||||
out: []byte("[{\"baseLabels\":{\"label_foo\":\"foo\",\"name\":\"foo\"},\"docstring\":\"metric foo\",\"metric\":{\"type\":\"counter\",\"value\":[]}}]"),
|
||||
out: []byte(`[{"baseLabels":{"label_foo":"foo","name":"foo"},"docstring":"metric foo","metric":{"type":"counter","value":[]}}]`),
|
||||
},
|
||||
{
|
||||
in: input{
|
||||
metrics: map[string]metrics.Metric{
|
||||
"foo": metrics.NewCounter(),
|
||||
"bar": metrics.NewCounter(),
|
||||
metrics: map[string]Metric{
|
||||
"foo": NewCounter(),
|
||||
"bar": NewCounter(),
|
||||
},
|
||||
},
|
||||
out: []byte("[{\"baseLabels\":{\"label_bar\":\"bar\",\"name\":\"bar\"},\"docstring\":\"metric bar\",\"metric\":{\"type\":\"counter\",\"value\":[]}},{\"baseLabels\":{\"label_foo\":\"foo\",\"name\":\"foo\"},\"docstring\":\"metric foo\",\"metric\":{\"type\":\"counter\",\"value\":[]}}]"),
|
||||
out: []byte(`[{"baseLabels":{"label_bar":"bar","name":"bar"},"docstring":"metric bar","metric":{"type":"counter","value":[]}},{"baseLabels":{"label_foo":"foo","name":"foo"},"docstring":"metric foo","metric":{"type":"counter","value":[]}}]`),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -307,15 +306,14 @@ func testDumpToWriter(t test.Tester) {
|
|||
}
|
||||
}
|
||||
|
||||
actual := &bytes.Buffer{}
|
||||
actual, err := json.Marshal(registry)
|
||||
|
||||
err := registry.dumpToWriter(actual)
|
||||
if err != nil {
|
||||
t.Errorf("%d. encountered error while dumping %s", i, err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(scenario.out, actual.Bytes()) {
|
||||
t.Errorf("%d. expected %q for dumping, got %q", i, scenario.out, actual.Bytes())
|
||||
if !bytes.Equal(scenario.out, actual) {
|
||||
t.Errorf("%d. expected %q for dumping, got %q", i, scenario.out, actual)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utility
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -17,7 +17,7 @@ const (
|
|||
|
||||
// LabelsToSignature provides a way of building a unique signature
|
||||
// (i.e., fingerprint) for a given label set sequence.
|
||||
func LabelsToSignature(labels map[string]string) string {
|
||||
func labelsToSignature(labels map[string]string) string {
|
||||
// TODO(matt): This is a wart, and we'll want to validate that collisions
|
||||
// do not occur in less-than-diligent environments.
|
||||
cardinality := len(labels)
|
|
@ -1,17 +1,16 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utility
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/utility/test"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testLabelsToSignature(t test.Tester) {
|
||||
func testLabelsToSignature(t tester) {
|
||||
var scenarios = []struct {
|
||||
in map[string]string
|
||||
out string
|
||||
|
@ -24,7 +23,7 @@ func testLabelsToSignature(t test.Tester) {
|
|||
}
|
||||
|
||||
for i, scenario := range scenarios {
|
||||
actual := LabelsToSignature(scenario.in)
|
||||
actual := labelsToSignature(scenario.in)
|
||||
|
||||
if actual != scenario.out {
|
||||
t.Errorf("%d. expected %s, got %s", i, scenario.out, actual)
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package maths
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
@ -14,11 +14,32 @@ import (
|
|||
// TODO(mtp): Split this out into a summary statistics file once moving/rolling
|
||||
// averages are calculated.
|
||||
|
||||
// ReductionMethod provides a method for reducing metrics into a given scalar
|
||||
// value.
|
||||
// ReductionMethod provides a method for reducing metrics into a scalar value.
|
||||
type ReductionMethod func([]float64) float64
|
||||
|
||||
var Average ReductionMethod = func(input []float64) float64 {
|
||||
var (
|
||||
medianReducer = NearestRankReducer(50)
|
||||
)
|
||||
|
||||
// These are the canned ReductionMethods.
|
||||
var (
|
||||
// Reduce to the average of the set.
|
||||
AverageReducer = averageReducer
|
||||
|
||||
// Extract the first modal value.
|
||||
FirstModeReducer = firstModeReducer
|
||||
|
||||
// Reduce to the maximum of the set.
|
||||
MaximumReducer = maximumReducer
|
||||
|
||||
// Reduce to the median of the set.
|
||||
MedianReducer = medianReducer
|
||||
|
||||
// Reduce to the minimum of the set.
|
||||
MinimumReducer = minimumReducer
|
||||
)
|
||||
|
||||
func averageReducer(input []float64) float64 {
|
||||
count := 0.0
|
||||
sum := 0.0
|
||||
|
||||
|
@ -34,11 +55,10 @@ var Average ReductionMethod = func(input []float64) float64 {
|
|||
return sum / count
|
||||
}
|
||||
|
||||
// Extract the first modal value.
|
||||
var FirstMode ReductionMethod = func(input []float64) float64 {
|
||||
func firstModeReducer(input []float64) float64 {
|
||||
valuesToFrequency := map[float64]int64{}
|
||||
var largestTally int64 = math.MinInt64
|
||||
var largestTallyValue float64 = math.NaN()
|
||||
largestTally := int64(math.MinInt64)
|
||||
largestTallyValue := math.NaN()
|
||||
|
||||
for _, v := range input {
|
||||
presentCount, _ := valuesToFrequency[v]
|
||||
|
@ -56,7 +76,7 @@ var FirstMode ReductionMethod = func(input []float64) float64 {
|
|||
}
|
||||
|
||||
// Calculate the percentile by choosing the nearest neighboring value.
|
||||
func NearestRank(input []float64, percentile float64) float64 {
|
||||
func nearestRank(input []float64, percentile float64) float64 {
|
||||
inputSize := len(input)
|
||||
|
||||
if inputSize == 0 {
|
||||
|
@ -81,14 +101,12 @@ func NearestRank(input []float64, percentile float64) float64 {
|
|||
// Generate a ReductionMethod based off of extracting a given percentile value.
|
||||
func NearestRankReducer(percentile float64) ReductionMethod {
|
||||
return func(input []float64) float64 {
|
||||
return NearestRank(input, percentile)
|
||||
return nearestRank(input, percentile)
|
||||
}
|
||||
}
|
||||
|
||||
var Median ReductionMethod = NearestRankReducer(50)
|
||||
|
||||
var Minimum ReductionMethod = func(input []float64) float64 {
|
||||
var minimum float64 = math.MaxFloat64
|
||||
func minimumReducer(input []float64) float64 {
|
||||
minimum := math.MaxFloat64
|
||||
|
||||
for _, v := range input {
|
||||
minimum = math.Min(minimum, v)
|
||||
|
@ -97,8 +115,8 @@ var Minimum ReductionMethod = func(input []float64) float64 {
|
|||
return minimum
|
||||
}
|
||||
|
||||
var Maximum ReductionMethod = func(input []float64) float64 {
|
||||
var maximum float64 = math.SmallestNonzeroFloat64
|
||||
func maximumReducer(input []float64) float64 {
|
||||
maximum := math.SmallestNonzeroFloat64
|
||||
|
||||
for _, v := range input {
|
||||
maximum = math.Max(maximum, v)
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package maths
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
|
@ -12,42 +12,42 @@ import (
|
|||
|
||||
func (s *S) TestAverageOnEmpty(c *C) {
|
||||
empty := []float64{}
|
||||
var v float64 = Average(empty)
|
||||
var v float64 = AverageReducer(empty)
|
||||
|
||||
c.Assert(v, IsNaN)
|
||||
}
|
||||
|
||||
func (s *S) TestAverageForSingleton(c *C) {
|
||||
input := []float64{5}
|
||||
var v float64 = Average(input)
|
||||
var v float64 = AverageReducer(input)
|
||||
|
||||
c.Check(v, Equals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestAverage(c *C) {
|
||||
input := []float64{5, 15}
|
||||
var v float64 = Average(input)
|
||||
var v float64 = AverageReducer(input)
|
||||
|
||||
c.Check(v, Equals, 10.0)
|
||||
}
|
||||
|
||||
func (s *S) TestFirstModeOnEmpty(c *C) {
|
||||
input := []float64{}
|
||||
var v float64 = FirstMode(input)
|
||||
var v float64 = FirstModeReducer(input)
|
||||
|
||||
c.Assert(v, IsNaN)
|
||||
}
|
||||
|
||||
func (s *S) TestFirstModeForSingleton(c *C) {
|
||||
input := []float64{5}
|
||||
var v float64 = FirstMode(input)
|
||||
var v float64 = FirstModeReducer(input)
|
||||
|
||||
c.Check(v, Equals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestFirstModeForUnimodal(c *C) {
|
||||
input := []float64{1, 2, 3, 4, 3}
|
||||
var v float64 = FirstMode(input)
|
||||
var v float64 = FirstModeReducer(input)
|
||||
|
||||
c.Check(v, Equals, 3.0)
|
||||
}
|
||||
|
@ -55,25 +55,25 @@ func (s *S) TestFirstModeForUnimodal(c *C) {
|
|||
func (s *S) TestNearestRankForEmpty(c *C) {
|
||||
input := []float64{}
|
||||
|
||||
c.Assert(NearestRank(input, 0), IsNaN)
|
||||
c.Assert(NearestRank(input, 50), IsNaN)
|
||||
c.Assert(NearestRank(input, 100), IsNaN)
|
||||
c.Assert(nearestRank(input, 0), IsNaN)
|
||||
c.Assert(nearestRank(input, 50), IsNaN)
|
||||
c.Assert(nearestRank(input, 100), IsNaN)
|
||||
}
|
||||
|
||||
func (s *S) TestNearestRankForSingleton(c *C) {
|
||||
input := []float64{5}
|
||||
|
||||
c.Check(NearestRank(input, 0), Equals, 5.0)
|
||||
c.Check(NearestRank(input, 50), Equals, 5.0)
|
||||
c.Check(NearestRank(input, 100), Equals, 5.0)
|
||||
c.Check(nearestRank(input, 0), Equals, 5.0)
|
||||
c.Check(nearestRank(input, 50), Equals, 5.0)
|
||||
c.Check(nearestRank(input, 100), Equals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestNearestRankForDouble(c *C) {
|
||||
input := []float64{5, 5}
|
||||
|
||||
c.Check(NearestRank(input, 0), Equals, 5.0)
|
||||
c.Check(NearestRank(input, 50), Equals, 5.0)
|
||||
c.Check(NearestRank(input, 100), Equals, 5.0)
|
||||
c.Check(nearestRank(input, 0), Equals, 5.0)
|
||||
c.Check(nearestRank(input, 50), Equals, 5.0)
|
||||
c.Check(nearestRank(input, 100), Equals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestNearestRankFor100(c *C) {
|
||||
|
@ -83,9 +83,9 @@ func (s *S) TestNearestRankFor100(c *C) {
|
|||
input[i] = float64(i + 1)
|
||||
}
|
||||
|
||||
c.Check(NearestRank(input, 0), Equals, 1.0)
|
||||
c.Check(NearestRank(input, 50), Equals, 51.0)
|
||||
c.Check(NearestRank(input, 100), Equals, 100.0)
|
||||
c.Check(nearestRank(input, 0), Equals, 1.0)
|
||||
c.Check(nearestRank(input, 50), Equals, 51.0)
|
||||
c.Check(nearestRank(input, 100), Equals, 100.0)
|
||||
}
|
||||
|
||||
func (s *S) TestNearestRankFor101(c *C) {
|
||||
|
@ -95,25 +95,25 @@ func (s *S) TestNearestRankFor101(c *C) {
|
|||
input[i] = float64(i + 1)
|
||||
}
|
||||
|
||||
c.Check(NearestRank(input, 0), Equals, 1.0)
|
||||
c.Check(NearestRank(input, 50), Equals, 51.0)
|
||||
c.Check(NearestRank(input, 100), Equals, 101.0)
|
||||
c.Check(nearestRank(input, 0), Equals, 1.0)
|
||||
c.Check(nearestRank(input, 50), Equals, 51.0)
|
||||
c.Check(nearestRank(input, 100), Equals, 101.0)
|
||||
}
|
||||
|
||||
func (s *S) TestMedianReducer(c *C) {
|
||||
input := []float64{1, 2, 3}
|
||||
|
||||
c.Check(Median(input), Equals, 2.0)
|
||||
c.Check(MedianReducer(input), Equals, 2.0)
|
||||
}
|
||||
|
||||
func (s *S) TestMinimum(c *C) {
|
||||
input := []float64{5, 1, 10, 1.1, 4}
|
||||
|
||||
c.Check(Minimum(input), Equals, 1.0)
|
||||
c.Check(MinimumReducer(input), Equals, 1.0)
|
||||
}
|
||||
|
||||
func (s *S) TestMaximum(c *C) {
|
||||
input := []float64{5, 1, 10, 1.1, 4}
|
||||
|
||||
c.Check(Maximum(input), Equals, 10.0)
|
||||
c.Check(MaximumReducer(input), Equals, 10.0)
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
@ -35,38 +34,49 @@ func emptyFilter(e TallyingIndexEstimator) TallyingIndexEstimator {
|
|||
}
|
||||
}
|
||||
|
||||
// Report the smallest observed value in the bucket.
|
||||
var Minimum TallyingIndexEstimator = emptyFilter(func(minimum, maximum float64, _, observations int) float64 {
|
||||
return minimum
|
||||
})
|
||||
|
||||
// Report the largest observed value in the bucket.
|
||||
var Maximum TallyingIndexEstimator = emptyFilter(func(minimum, maximum float64, _, observations int) float64 {
|
||||
return maximum
|
||||
})
|
||||
|
||||
// Report the average of the extrema.
|
||||
var Average TallyingIndexEstimator = emptyFilter(func(minimum, maximum float64, _, observations int) float64 {
|
||||
return maths.Average([]float64{minimum, maximum})
|
||||
})
|
||||
|
||||
// Report the minimum value of the index is in the lower-third of observations,
|
||||
// the average if in the middle-third, and the maximum if in the largest third.
|
||||
var Uniform TallyingIndexEstimator = emptyFilter(func(minimum, maximum float64, index, observations int) float64 {
|
||||
if observations == 1 {
|
||||
var (
|
||||
minimumEstimator = emptyFilter(func(minimum, maximum float64, _, observations int) float64 {
|
||||
return minimum
|
||||
}
|
||||
})
|
||||
|
||||
location := float64(index) / float64(observations)
|
||||
|
||||
if location > upperThird {
|
||||
maximumEstimator = emptyFilter(func(minimum, maximum float64, _, observations int) float64 {
|
||||
return maximum
|
||||
} else if location < lowerThird {
|
||||
return minimum
|
||||
}
|
||||
})
|
||||
|
||||
return maths.Average([]float64{minimum, maximum})
|
||||
})
|
||||
averageEstimator = emptyFilter(func(minimum, maximum float64, _, observations int) float64 {
|
||||
return AverageReducer([]float64{minimum, maximum})
|
||||
})
|
||||
|
||||
uniformEstimator = emptyFilter(func(minimum, maximum float64, index, observations int) float64 {
|
||||
if observations == 1 {
|
||||
return minimum
|
||||
}
|
||||
|
||||
location := float64(index) / float64(observations)
|
||||
|
||||
if location > upperThird {
|
||||
return maximum
|
||||
} else if location < lowerThird {
|
||||
return minimum
|
||||
}
|
||||
|
||||
return AverageReducer([]float64{minimum, maximum})
|
||||
})
|
||||
)
|
||||
|
||||
// These are the canned TallyingIndexEstimators.
|
||||
var (
|
||||
// Report the smallest observed value in the bucket.
|
||||
MinimumEstimator = minimumEstimator
|
||||
// Report the largest observed value in the bucket.
|
||||
MaximumEstimator = maximumEstimator
|
||||
// Report the average of the extrema.
|
||||
AverageEstimator = averageEstimator
|
||||
// Report the minimum value of the index if it is in the lower-third of
|
||||
// observations, the average if in the middle-third, and the maximum if in
|
||||
// the largest third
|
||||
UniformEstimator = uniformEstimator
|
||||
)
|
||||
|
||||
// A TallyingBucket is a Bucket that tallies when an object is added to it.
|
||||
// Upon insertion, an object is compared against collected extrema and noted
|
||||
|
@ -127,7 +137,7 @@ func (b *TallyingBucket) Reset() {
|
|||
// Produce a TallyingBucket with sane defaults.
|
||||
func DefaultTallyingBucket() TallyingBucket {
|
||||
return TallyingBucket{
|
||||
estimator: Minimum,
|
||||
estimator: MinimumEstimator,
|
||||
largestObserved: math.SmallestNonzeroFloat64,
|
||||
smallestObserved: math.MaxFloat64,
|
||||
}
|
|
@ -1,40 +1,39 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
)
|
||||
|
||||
func (s *S) TestTallyingPercentileEstimatorMinimum(c *C) {
|
||||
c.Assert(Minimum(-2, -1, 0, 0), maths.IsNaN)
|
||||
c.Check(Minimum(-2, -1, 0, 1), Equals, -2.0)
|
||||
c.Assert(MinimumEstimator(-2, -1, 0, 0), IsNaN)
|
||||
c.Check(MinimumEstimator(-2, -1, 0, 1), Equals, -2.0)
|
||||
}
|
||||
|
||||
func (s *S) TestTallyingPercentileEstimatorMaximum(c *C) {
|
||||
c.Assert(Maximum(-2, -1, 0, 0), maths.IsNaN)
|
||||
c.Check(Maximum(-2, -1, 0, 1), Equals, -1.0)
|
||||
c.Assert(MaximumEstimator(-2, -1, 0, 0), IsNaN)
|
||||
c.Check(MaximumEstimator(-2, -1, 0, 1), Equals, -1.0)
|
||||
}
|
||||
|
||||
func (s *S) TestTallyingPercentilesEstimatorAverage(c *C) {
|
||||
c.Assert(Average(-2, -1, 0, 0), maths.IsNaN)
|
||||
c.Check(Average(-2, -2, 0, 1), Equals, -2.0)
|
||||
c.Check(Average(-1, -1, 0, 1), Equals, -1.0)
|
||||
c.Check(Average(1, 1, 0, 2), Equals, 1.0)
|
||||
c.Check(Average(2, 1, 0, 2), Equals, 1.5)
|
||||
c.Assert(AverageEstimator(-2, -1, 0, 0), IsNaN)
|
||||
c.Check(AverageEstimator(-2, -2, 0, 1), Equals, -2.0)
|
||||
c.Check(AverageEstimator(-1, -1, 0, 1), Equals, -1.0)
|
||||
c.Check(AverageEstimator(1, 1, 0, 2), Equals, 1.0)
|
||||
c.Check(AverageEstimator(2, 1, 0, 2), Equals, 1.5)
|
||||
}
|
||||
|
||||
func (s *S) TestTallyingPercentilesEstimatorUniform(c *C) {
|
||||
c.Assert(Uniform(-5, 5, 0, 0), maths.IsNaN)
|
||||
c.Assert(UniformEstimator(-5, 5, 0, 0), IsNaN)
|
||||
|
||||
c.Check(Uniform(-5, 5, 0, 2), Equals, -5.0)
|
||||
c.Check(Uniform(-5, 5, 1, 2), Equals, 0.0)
|
||||
c.Check(Uniform(-5, 5, 2, 2), Equals, 5.0)
|
||||
c.Check(UniformEstimator(-5, 5, 0, 2), Equals, -5.0)
|
||||
c.Check(UniformEstimator(-5, 5, 1, 2), Equals, 0.0)
|
||||
c.Check(UniformEstimator(-5, 5, 2, 2), Equals, 5.0)
|
||||
}
|
||||
|
||||
func (s *S) TestTallyingBucketBuilder(c *C) {
|
|
@ -1,15 +1,13 @@
|
|||
// Copyright (c) 2013, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
//
|
||||
|
||||
package registry
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/maths"
|
||||
"github.com/prometheus/client_golang/metrics"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -17,18 +15,15 @@ import (
|
|||
// exposed if the DefaultRegistry's exporter is hooked into the HTTP request
|
||||
// handler.
|
||||
var (
|
||||
marshalErrorCount = metrics.NewCounter()
|
||||
dumpErrorCount = metrics.NewCounter()
|
||||
|
||||
requestCount = metrics.NewCounter()
|
||||
requestLatencyBuckets = metrics.LogarithmicSizedBucketsFor(0, 1000)
|
||||
requestLatency = metrics.NewHistogram(&metrics.HistogramSpecification{
|
||||
requestCount = NewCounter()
|
||||
requestLatencyBuckets = LogarithmicSizedBucketsFor(0, 1000)
|
||||
requestLatency = NewHistogram(&HistogramSpecification{
|
||||
Starts: requestLatencyBuckets,
|
||||
BucketBuilder: metrics.AccumulatingBucketBuilder(metrics.EvictAndReplaceWith(50, maths.Average), 1000),
|
||||
BucketBuilder: AccumulatingBucketBuilder(EvictAndReplaceWith(50, AverageReducer), 1000),
|
||||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.9, 0.99},
|
||||
})
|
||||
|
||||
startTime = metrics.NewGauge()
|
||||
startTime = NewGauge()
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -42,8 +37,8 @@ func init() {
|
|||
|
||||
// This callback accumulates the microsecond duration of the reporting
|
||||
// framework's overhead such that it can be reported.
|
||||
var requestLatencyAccumulator metrics.CompletionCallback = func(duration time.Duration) {
|
||||
microseconds := float64(duration / time.Microsecond)
|
||||
var requestLatencyAccumulator = func(began time.Time) {
|
||||
microseconds := float64(time.Since(began) / time.Microsecond)
|
||||
|
||||
requestLatency.Add(nil, microseconds)
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// Copyright (c) 2013, Prometheus Team
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utility
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
. "github.com/matttproud/gocheck"
|
||||
|
@ -19,7 +19,7 @@ var ValueEquals Checker = &valueEqualsChecker{
|
|||
}
|
||||
|
||||
func (checker *valueEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
actual := params[0].(*Item).Value
|
||||
actual := params[0].(*item).Value
|
||||
expected := params[1]
|
||||
|
||||
return actual == expected, ""
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2012, Matt T. Proud
|
||||
// All rights reserved.
|
||||
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// The utility package provides general purpose helpers to assist with this
|
||||
// library.
|
||||
//
|
||||
// priority_queue.go provides a simple priority queue.
|
||||
//
|
||||
// priority_queue_test.go provides a test complement for the priority_queue.go
|
||||
// module.
|
||||
//
|
||||
// test_helper.go provides a testing assistents for this package and its
|
||||
// dependents.
|
||||
//
|
||||
// utility_test.go provides a test suite for all tests in the utility package
|
||||
// hierarchy. It employs the gocheck framework for test scaffolding.
|
||||
package documentation
|
Loading…
Reference in New Issue