From e0b92aec7a32cc5d8ee236ef044ab70a874cd811 Mon Sep 17 00:00:00 2001 From: "Matt T. Proud" Date: Thu, 24 May 2012 20:02:44 +0200 Subject: [PATCH] - Separate out the packages' files' documentation into a separate documentation file per package. - Provide better examples in the examples subdirectory. - Make the comments consistent in terms of using multi-line format for future-proofing. - Extract major constants out. --- README.md | 23 ++-- documentation.go | 54 ++++++++++ examples/random/main.go | 37 ++++--- examples/simple/main.go | 17 +-- maths/distributions.go | 25 +++-- maths/documentation.go | 26 +++++ maths/helpers_for_testing.go | 19 ++-- maths/maths_test.go | 13 ++- maths/statistics.go | 40 ++++--- maths/statistics_test.go | 12 +-- metrics/accumulating_bucket.go | 36 ++++--- metrics/accumulating_bucket_test.go | 39 ++++--- metrics/base.go | 17 --- metrics/bucket.go | 55 ++++++---- metrics/constants.go | 22 ++++ metrics/documentation.go | 51 +++++++++ metrics/eviction.go | 37 ++++--- metrics/eviction_test.go | 12 +-- metrics/gauge.go | 27 ++--- metrics/gauge_test.go | 12 +-- metrics/histogram.go | 162 +++++++++++++++++----------- metrics/histogram_test.go | 12 +-- metrics/metric.go | 23 ++++ metrics/metrics_test.go | 13 ++- metrics/tallying_bucket.go | 62 +++++++---- metrics/tallying_bucket_test.go | 13 ++- metrics/timer.go | 45 +++++--- metrics/timer_test.go | 12 +-- registry.go | 84 +++++++++------ utility/documentation.go | 29 +++++ utility/optional.go | 13 ++- utility/optional_test.go | 12 +-- utility/priority_queue.go | 12 +-- utility/priority_queue_test.go | 13 ++- utility/test_helper.go | 13 ++- utility/utility_test.go | 13 ++- 36 files changed, 721 insertions(+), 384 deletions(-) create mode 100644 documentation.go create mode 100644 maths/documentation.go delete mode 100644 metrics/base.go create mode 100644 metrics/constants.go create mode 100644 metrics/documentation.go create mode 100644 metrics/metric.go create mode 100644 utility/documentation.go diff --git a/README.md b/README.md index 9c8fed3..edbcbe3 100644 --- a/README.md +++ b/README.md @@ -17,42 +17,47 @@ to be made, but this task has been deferred for now. # Continuous Integration [![Build Status](https://secure.travis-ci.org/matttproud/golang_instrumentation.png?branch=master)](http://travis-ci.org/matttproud/golang_instrumentation) -# Metrics +# Documentation +Please read the [generated documentation](http://go.pkgdoc.org/launchpad.net/gocheck) +for the project's documentation from source code. + +# Basic Overview +## Metrics A metric is a measurement mechanism. -## Gauge +### Gauge A Gauge is a metric that exposes merely an instantaneous value or some snapshot thereof. -## Histogram +### Histogram A Histogram is a metric that captures events or samples into buckets. It exposes its values via percentile estimations. -### Buckets +#### Buckets A Bucket is a generic container that collects samples and their values. It prescribes no behavior on its own aside from merely accepting a value, leaving it up to the concrete implementation to what to do with the injected values. -#### Accumulating Bucket +##### Accumulating Bucket An Accumulating Bucket is a bucket that appends the new sample to a timestamped priority queue such that the eldest values are evicted according to a given policy. -#### Eviction Policies +##### Eviction Policies Once an Accumulating Bucket reaches capacity, its eviction policy is invoked. This reaps the oldest N objects subject to certain behavior. -##### Remove Oldest +###### Remove Oldest This merely removes the oldest N items without performing some aggregation replacement operation on them. -##### Aggregate Oldest +###### Aggregate Oldest This removes the oldest N items while performing some summary aggregation operation thereupon, which is then appended to the list in the former values' place. -#### Tallying Bucket +##### Tallying Bucket A Tallying Bucket differs from an Accumulating Bucket in that it never stores any of the values emitted into it but rather exposes a simplied summary representation thereof. For instance, if a values therein is requested, diff --git a/documentation.go b/documentation.go new file mode 100644 index 0000000..eb8ca81 --- /dev/null +++ b/documentation.go @@ -0,0 +1,54 @@ +/* +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) + +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 registry diff --git a/examples/random/main.go b/examples/random/main.go index 0f63c6e..1738408 100644 --- a/examples/random/main.go +++ b/examples/random/main.go @@ -1,16 +1,19 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// main.go provides a simple example of how to use this instrumentation -// framework in the context of having something that emits values into -// its collectors. -// -// The emitted values correspond to uniform, normal, and exponential -// distributions. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ +/* +main.go provides a simple example of how to use this instrumentation +framework in the context of having something that emits values into +its collectors. + +The emitted values correspond to uniform, normal, and exponential +distributions. +*/ package main import ( @@ -43,12 +46,12 @@ func main() { zed_rpc_calls := &metrics.GaugeMetric{} metrics := registry.NewRegistry() - metrics.Register("foo_rpc_latency_ms_histogram", foo_rpc_latency) - metrics.Register("foo_rpc_call_count", foo_rpc_calls) - metrics.Register("bar_rpc_latency_ms_histogram", bar_rpc_latency) - metrics.Register("bar_rpc_call_count", bar_rpc_calls) - metrics.Register("zed_rpc_latency_ms_histogram", zed_rpc_latency) - metrics.Register("zed_rpc_call_count", zed_rpc_calls) + metrics.Register("rpc_latency_foo_microseconds", foo_rpc_latency) + metrics.Register("rpc_calls_foo_total", foo_rpc_calls) + metrics.Register("rpc_latency_bar_microseconds", bar_rpc_latency) + metrics.Register("rpc_calls_bar_total", bar_rpc_calls) + metrics.Register("rpc_latency_zed_microseconds", zed_rpc_latency) + metrics.Register("rpc_calls_zed_total", zed_rpc_calls) go func() { for { diff --git a/examples/simple/main.go b/examples/simple/main.go index 61d1a6f..bcd117c 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -1,12 +1,15 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// main.go provides a simple skeletal example of how this instrumentation -// framework is registered and invoked. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ +/* +main.go provides a simple skeletal example of how this instrumentation +framework is registered and invoked. +*/ package main import ( diff --git a/maths/distributions.go b/maths/distributions.go index cf964a1..5ca1711 100644 --- a/maths/distributions.go +++ b/maths/distributions.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// distributions.go provides basic distribution-generating functions that are -// used primarily in testing contexts. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package maths @@ -13,7 +12,9 @@ import ( "math" ) -// Go's standard library does not offer a factorial function. +/* +Go's standard library does not offer a factorial function. +*/ func Factorial(of int) int64 { if of <= 0 { return 1 @@ -28,9 +29,11 @@ func Factorial(of int) int64 { return result } -// Create 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. +/* +Create 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)) intermediate := math.Pow(p, float64(k)) * math.Pow(1-p, float64(n-k)) diff --git a/maths/documentation.go b/maths/documentation.go new file mode 100644 index 0000000..375eb6f --- /dev/null +++ b/maths/documentation.go @@ -0,0 +1,26 @@ +/* +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 diff --git a/maths/helpers_for_testing.go b/maths/helpers_for_testing.go index 35e6832..0fb1e98 100644 --- a/maths/helpers_for_testing.go +++ b/maths/helpers_for_testing.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// helpers_for_testing.go provides a testing assistents for this package and its -// dependents. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package maths @@ -19,8 +18,10 @@ type isNaNChecker struct { *CheckerInfo } -// This piece provides a simple tester for the gocheck testing library to -// ascertain if a value is not-a-number. +/* +This piece provides a simple tester for the gocheck testing library to +ascertain if a value is not-a-number. +*/ var IsNaN Checker = &isNaNChecker{ &CheckerInfo{Name: "IsNaN", Params: []string{"value"}}, } diff --git a/maths/maths_test.go b/maths/maths_test.go index 307b5af..b5d21ae 100644 --- a/maths/maths_test.go +++ b/maths/maths_test.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// maths_test.go provides a test suite for all tests in the maths package -// hierarchy. It employs the gocheck framework for test scaffolding. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package maths diff --git a/maths/statistics.go b/maths/statistics.go index 76212fc..a837565 100644 --- a/maths/statistics.go +++ b/maths/statistics.go @@ -1,14 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// statistics.go provides basic summary statistics functions for the purpose of -// metrics aggregation. - -// TODO(mtp): Split this out into a summary statistics file once moving/rolling -// averages are calculated. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package maths @@ -17,8 +13,15 @@ import ( "sort" ) -// ReductionMethod provides a method for reducing metrics into a given scalar -// value. +/* +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. +*/ type ReductionMethod func([]float64) float64 var Average ReductionMethod = func(input []float64) float64 { @@ -37,7 +40,9 @@ var Average ReductionMethod = func(input []float64) float64 { return sum / count } -// Extract the first modal value. +/* +Extract the first modal value. +*/ var FirstMode ReductionMethod = func(input []float64) float64 { valuesToFrequency := map[float64]int64{} var largestTally int64 = math.MinInt64 @@ -58,7 +63,9 @@ var FirstMode ReductionMethod = func(input []float64) float64 { return largestTallyValue } -// Calculate the percentile by choosing the nearest neighboring value. +/* +Calculate the percentile by choosing the nearest neighboring value. +*/ func NearestRank(input []float64, percentile float64) float64 { inputSize := len(input) @@ -81,7 +88,10 @@ func NearestRank(input []float64, percentile float64) float64 { return copiedInput[preliminaryIndex] } -func NearestRankReducer(percentile float64) func(input []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) } diff --git a/maths/statistics_test.go b/maths/statistics_test.go index 4a26196..2c28a79 100644 --- a/maths/statistics_test.go +++ b/maths/statistics_test.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// statistics_test.go provides a test complement for the statistics.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package maths diff --git a/metrics/accumulating_bucket.go b/metrics/accumulating_bucket.go index 35fe586..4aa23f5 100644 --- a/metrics/accumulating_bucket.go +++ b/metrics/accumulating_bucket.go @@ -1,12 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// 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. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -29,9 +27,11 @@ type AccumulatingBucket struct { evictionPolicy EvictionPolicy } -// AccumulatingBucketBuilder is a convenience method for generating a -// BucketBuilder that produces AccumatingBucket entries with a certain -// behavior set. +/* +AccumulatingBucketBuilder is a convenience method for generating a +BucketBuilder that produces AccumatingBucket entries with a certain +behavior set. +*/ func AccumulatingBucketBuilder(evictionPolicy EvictionPolicy, maximumSize int) BucketBuilder { return func() Bucket { return &AccumulatingBucket{ @@ -42,8 +42,10 @@ func AccumulatingBucketBuilder(evictionPolicy EvictionPolicy, maximumSize int) B } } -// Add a value to the bucket. Depending on whether the bucket is full, it may -// trigger an eviction of older items. +/* +Add a value to the bucket. Depending on whether the bucket is full, it may +trigger an eviction of older items. +*/ func (b *AccumulatingBucket) Add(value float64) { b.mutex.Lock() defer b.mutex.Unlock() @@ -98,9 +100,11 @@ func (b *AccumulatingBucket) ValueForIndex(index int) float64 { sort.Float64s(sortedElements) - // N.B.(mtp): Interfacing components should not need to comprehend what - // eviction and storage container strategies used; therefore, - // we adjust this silently. + /* + N.B.(mtp): Interfacing components should not need to comprehend what + eviction and storage container strategies used; therefore, + we adjust this silently. + */ targetIndex := int(float64(elementCount-1) * (float64(index) / float64(b.observations))) return sortedElements[targetIndex] diff --git a/metrics/accumulating_bucket_test.go b/metrics/accumulating_bucket_test.go index 3c700d3..e83e5bc 100644 --- a/metrics/accumulating_bucket_test.go +++ b/metrics/accumulating_bucket_test.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// accumulating_bucket_test.go provides a test complement for the -// accumulating_bucket_go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -124,17 +123,23 @@ func (s *S) TestAccumulatingBucketValueForIndex(c *C) { c.Assert(b.ValueForIndex(i), maths.IsNaN) } - // The bucket has only observed one item and contains now one item. + /* + The bucket has only observed one item and contains now one item. + */ b.Add(1.0) c.Check(b.ValueForIndex(0), Equals, 1.0) - // Let's sanity check what occurs if presumably an eviction happened and - // we requested an index larger than what is contained. + /* + Let's sanity check what occurs if presumably an eviction happened and + we requested an index larger than what is contained. + */ c.Check(b.ValueForIndex(1), Equals, 1.0) for i := 2.0; i <= 100; i += 1 { b.Add(i) - // TODO(mtp): This is a sin. Provide a mechanism for deterministic testing. + /* + TODO(mtp): This is a sin. Provide a mechanism for deterministic testing. + */ time.Sleep(1 * time.Millisecond) } @@ -144,13 +149,17 @@ func (s *S) TestAccumulatingBucketValueForIndex(c *C) { for i := 101.0; i <= 150; i += 1 { b.Add(i) - // TODO(mtp): This is a sin. Provide a mechanism for deterministic testing. + /* + TODO(mtp): This is a sin. Provide a mechanism for deterministic testing. + */ time.Sleep(1 * time.Millisecond) } - // The bucket's capacity has been exceeded by inputs at this point; - // consequently, we search for a given element by percentage offset - // therein. + /* + The bucket's capacity has been exceeded by inputs at this point; + consequently, we search for a given element by percentage offset + therein. + */ c.Check(b.ValueForIndex(0), Equals, 51.0) c.Check(b.ValueForIndex(50), Equals, 84.0) c.Check(b.ValueForIndex(99), Equals, 116.0) diff --git a/metrics/base.go b/metrics/base.go deleted file mode 100644 index 53e634f..0000000 --- a/metrics/base.go +++ /dev/null @@ -1,17 +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. - -// base.go provides fundamental interface expectations for the various metrics. - -package metrics - -// A Metric is something that can be exposed via the registry framework. -type Metric interface { - // Produce a human-consumable representation of the metric. - Humanize() string - // Produce a JSON-consumable representation of the metric. - Marshallable() map[string]interface{} -} diff --git a/metrics/bucket.go b/metrics/bucket.go index b141831..a026306 100644 --- a/metrics/bucket.go +++ b/metrics/bucket.go @@ -1,32 +1,47 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// bucket.go provides fundamental interface expectations for various bucket -// types. +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 -// The Histogram class and associated types build buckets on their own. +/* +The Histogram class and associated types build buckets on their own. +*/ type BucketBuilder func() Bucket -// This defines the base Bucket type. The exact behaviors of the bucket are -// at the whim of the implementor. -// -// A Bucket is used as a container by Histogram as a collection for its -// accumulated samples. +/* +This defines the base Bucket type. The exact behaviors of the bucket are +at the whim of the implementor. + +A Bucket is used as a container by Histogram as a collection for its +accumulated samples. +*/ type Bucket interface { - // Add a value to the bucket. + /* + Add a value to the bucket. + */ Add(value float64) - // Provide a humanized representation hereof. + /* + Provide a humanized representation hereof. + */ Humanize() string - // Provide a count of observations throughout the bucket's lifetime. + /* + Provide a count of observations throughout the bucket's lifetime. + */ Observations() int - // Provide the value from the given in-memory value cache or an estimate - // thereof for the given index. The consumer of the bucket's data makes - // no assumptions about the underlying storage mechanisms that the bucket - // employs. + /* + Provide the value from the given in-memory value cache or an estimate + thereof for the given index. The consumer of the bucket's data makes + no assumptions about the underlying storage mechanisms that the bucket + employs. + */ ValueForIndex(index int) float64 } diff --git a/metrics/constants.go b/metrics/constants.go new file mode 100644 index 0000000..61f24bc --- /dev/null +++ b/metrics/constants.go @@ -0,0 +1,22 @@ +/* +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 ( + valueKey = "value" + gaugeTypeValue = "gauge" + typeKey = "type" + histogramTypeValue = "histogram" + floatFormat = 'f' + floatPrecision = 6 + floatBitCount = 64 +) diff --git a/metrics/documentation.go b/metrics/documentation.go new file mode 100644 index 0000000..4b850ec --- /dev/null +++ b/metrics/documentation.go @@ -0,0 +1,51 @@ +/* +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 diff --git a/metrics/eviction.go b/metrics/eviction.go index afcf86d..2d80be0 100644 --- a/metrics/eviction.go +++ b/metrics/eviction.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// eviction.go provides several histogram bucket eviction strategies. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -15,12 +15,16 @@ import ( "time" ) -// EvictionPolicy implements some sort of garbage collection methodology for -// an underlying heap.Interface. This is presently only used for -// AccumulatingBucket. +/* +EvictionPolicy implements some sort of garbage collection methodology for +an underlying heap.Interface. This is presently only used for +AccumulatingBucket. +*/ type EvictionPolicy func(h heap.Interface) -// As the name implies, this evicts the oldest x objects from the heap. +/* +As the name implies, this evicts the oldest x objects from the heap. +*/ func EvictOldest(count int) EvictionPolicy { return func(h heap.Interface) { for i := 0; i < count; i++ { @@ -29,10 +33,10 @@ func EvictOldest(count int) EvictionPolicy { } } -// This factory produces an EvictionPolicy that applies some standardized -// reduction methodology on the to-be-terminated values. -// -// TODO(mtp): Parameterize the priority generation since these tools are useful. +/* +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 { return func(h heap.Interface) { oldValues := make([]float64, count) @@ -44,7 +48,10 @@ func EvictAndReplaceWith(count int, reducer maths.ReductionMethod) EvictionPolic reduced := reducer(oldValues) heap.Push(h, &utility.Item{ - Value: reduced, + Value: reduced, + /* + TODO(mtp): Parameterize the priority generation since these tools are useful. + */ Priority: -1 * time.Now().UnixNano(), }) } diff --git a/metrics/eviction_test.go b/metrics/eviction_test.go index 3ae717f..b4d36d9 100644 --- a/metrics/eviction_test.go +++ b/metrics/eviction_test.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// eviction_test.go provides a test complement for the eviction.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics diff --git a/metrics/gauge.go b/metrics/gauge.go index 8c4779a..f988d28 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// gauge.go provides a scalar metric that one can monitor. It is useful for -// certain cases, such as instantaneous temperature. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -14,10 +13,12 @@ import ( "sync" ) -// A gauge metric merely provides an instantaneous representation of a scalar -// value or an accumulation. For instance, if one wants to expose the current -// temperature or the hitherto bandwidth used, this would be the metric for such -// circumstances. +/* +A gauge metric merely provides an instantaneous representation of a scalar +value or an accumulation. For instance, if one wants to expose the current +temperature or the hitherto bandwidth used, this would be the metric for such +circumstances. +*/ type GaugeMetric struct { value float64 mutex sync.RWMutex @@ -80,8 +81,8 @@ func (metric *GaugeMetric) Marshallable() map[string]interface{} { v := make(map[string]interface{}, 2) - v["value"] = metric.value - v["type"] = "gauge" + v[valueKey] = metric.value + v[typeKey] = gaugeTypeValue return v } diff --git a/metrics/gauge_test.go b/metrics/gauge_test.go index 94ef469..07fc106 100644 --- a/metrics/gauge_test.go +++ b/metrics/gauge_test.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// gauge_test.go provides a test complement for the gauge.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics diff --git a/metrics/histogram.go b/metrics/histogram.go index 1388675..6213b33 100644 --- a/metrics/histogram.go +++ b/metrics/histogram.go @@ -1,12 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// 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. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -17,9 +15,11 @@ import ( "strconv" ) -// This generates count-buckets of equal size distributed along the open -// interval of lower to upper. For instance, {lower=0, upper=10, count=5} -// yields the following: [0, 2, 4, 6, 8]. +/* +This generates count-buckets of equal size distributed along the open +interval of lower to upper. For instance, {lower=0, upper=10, count=5} +yields the following: [0, 2, 4, 6, 8]. +*/ func EquallySizedBucketsFor(lower, upper float64, count int) []float64 { buckets := make([]float64, count) @@ -33,8 +33,10 @@ func EquallySizedBucketsFor(lower, upper float64, count int) []float64 { return buckets } -// This generates log2-sized buckets spanning from lower to upper inclusively -// as well as values beyond it. +/* +This generates log2-sized buckets spanning from lower to upper inclusively +as well as values beyond it. +*/ func LogarithmicSizedBucketsFor(lower, upper float64) []float64 { bucketCount := int(math.Ceil(math.Log2(upper))) @@ -47,36 +49,46 @@ func LogarithmicSizedBucketsFor(lower, upper float64) []float64 { return buckets } -// A HistogramSpecification defines how a Histogram is to be built. +/* +A HistogramSpecification defines how a Histogram is to be built. +*/ type HistogramSpecification struct { Starts []float64 BucketMaker BucketBuilder ReportablePercentiles []float64 } -// The histogram is an accumulator for samples. It merely routes into which -// to bucket to capture an event and provides a percentile calculation -// mechanism. -// -// Histogram makes do without locking by employing the law of large numbers -// to presume a convergence toward a given bucket distribution. Locking -// may be implemented in the buckets themselves, though. +/* +The histogram is an accumulator for samples. It merely routes into which +to bucket to capture an event and provides a percentile calculation +mechanism. + +Histogram makes do without locking by employing the law of large numbers +to presume a convergence toward a given bucket distribution. Locking +may be implemented in the buckets themselves, though. +*/ type Histogram struct { - // This represents the open interval's start at which values shall be added to - // the bucket. The interval continues until the beginning of the next bucket - // exclusive or positive infinity. - // - // N.B. - // - bucketStarts should be sorted in ascending order; - // - len(bucketStarts) must be equivalent to len(buckets); - // - The index of a given bucketStarts' element is presumed to match - // correspond to the appropriate element in buckets. + /* + This represents the open interval's start at which values shall be added to + the bucket. The interval continues until the beginning of the next bucket + exclusive or positive infinity. + + N.B. + - bucketStarts should be sorted in ascending order; + - len(bucketStarts) must be equivalent to len(buckets); + - The index of a given bucketStarts' element is presumed to match + correspond to the appropriate element in buckets. + */ bucketStarts []float64 - // These are the buckets that capture samples as they are emitted to the - // histogram. Please consult the reference interface and its implements for - // further details about behavior expectations. + /* + These are the buckets that capture samples as they are emitted to the + histogram. Please consult the reference interface and its implements for + further details about behavior expectations. + */ buckets []Bucket - // These are the percentile values that will be reported on marshalling. + /* + These are the percentile values that will be reported on marshalling. + */ reportablePercentiles []float64 } @@ -108,7 +120,9 @@ func (h *Histogram) Humanize() string { return string(stringBuffer.Bytes()) } -// Determine the number of previous observations up to a given index. +/* +Determine the number of previous observations up to a given index. +*/ func previousCumulativeObservations(cumulativeObservations []int, bucketIndex int) int { if bucketIndex == 0 { return 0 @@ -117,12 +131,16 @@ func previousCumulativeObservations(cumulativeObservations []int, bucketIndex in return cumulativeObservations[bucketIndex-1] } -// Determine the index for an element given a percentage of length. +/* +Determine the index for an element given a percentage of length. +*/ func prospectiveIndexForPercentile(percentile float64, totalObservations int) int { return int(percentile * float64(totalObservations-1)) } -// Determine the next bucket element when interim bucket intervals may be empty. +/* +Determine the next bucket element when interim bucket intervals may be empty. +*/ func (h *Histogram) nextNonEmptyBucketElement(currentIndex, bucketCount int, observationsByBucket []int) (*Bucket, int) { for i := currentIndex; i < bucketCount; i++ { if observationsByBucket[i] == 0 { @@ -135,18 +153,24 @@ func (h *Histogram) nextNonEmptyBucketElement(currentIndex, bucketCount int, obs panic("Illegal Condition: There were no remaining buckets to provide a value.") } -// Find what bucket and element index contains a given percentile value. -// If a percentile is requested that results in a corresponding index that is no -// longer contained by the bucket, the index of the last item is returned. This -// may occur if the underlying bucket catalogs values and employs an eviction -// strategy. +/* +Find what bucket and element index contains a given percentile value. +If a percentile is requested that results in a corresponding index that is no +longer contained by the bucket, the index of the last item is returned. This +may occur if the underlying bucket catalogs values and employs an eviction +strategy. +*/ func (h *Histogram) bucketForPercentile(percentile float64) (*Bucket, int) { bucketCount := len(h.buckets) - // This captures the quantity of samples in a given bucket's range. + /* + This captures the quantity of samples in a given bucket's range. + */ observationsByBucket := make([]int, bucketCount) - // This captures the cumulative quantity of observations from all preceding - // buckets up and to the end of this bucket. + /* + This captures the cumulative quantity of observations from all preceding + buckets up and to the end of this bucket. + */ cumulativeObservationsByBucket := make([]int, bucketCount) var totalObservations int = 0 @@ -158,9 +182,11 @@ func (h *Histogram) bucketForPercentile(percentile float64) (*Bucket, int) { cumulativeObservationsByBucket[i] = totalObservations } - // This captures the index offset where the given percentile value would be - // were all submitted samples stored and never down-/re-sampled nor deleted - // and housed in a singular array. + /* + This captures the index offset where the given percentile value would be + were all submitted samples stored and never down-/re-sampled nor deleted + and housed in a singular array. + */ prospectiveIndex := prospectiveIndexForPercentile(percentile, totalObservations) for i, cumulativeObservation := range cumulativeObservationsByBucket { @@ -168,15 +194,21 @@ func (h *Histogram) bucketForPercentile(percentile float64) (*Bucket, int) { continue } - // Find the bucket that contains the given index. + /* + Find the bucket that contains the given index. + */ if cumulativeObservation >= prospectiveIndex { var subIndex int - // This calculates the index within the current bucket where the given - // percentile may be found. + /* + This calculates the index within the current bucket where the given + percentile may be found. + */ subIndex = prospectiveIndex - previousCumulativeObservations(cumulativeObservationsByBucket, i) - // Sometimes the index may be the last item, in which case we need to - // take this into account. + /* + Sometimes the index may be the last item, in which case we need to + take this into account. + */ if observationsByBucket[i] == subIndex { return h.nextNonEmptyBucketElement(i+1, bucketCount, observationsByBucket) } @@ -188,34 +220,42 @@ func (h *Histogram) bucketForPercentile(percentile float64) (*Bucket, int) { return &h.buckets[0], 0 } -// Return the histogram's estimate of the value for a given percentile of -// collected samples. The requested percentile is expected to be a real -// value within (0, 1.0]. +/* +Return the histogram's estimate of the value for a given percentile of +collected samples. The requested percentile is expected to be a real +value within (0, 1.0]. +*/ func (h *Histogram) Percentile(percentile float64) float64 { bucket, index := h.bucketForPercentile(percentile) return (*bucket).ValueForIndex(index) } +func formatFloat(value float64) string { + return strconv.FormatFloat(value, floatFormat, floatPrecision, floatBitCount) +} + func (h *Histogram) Marshallable() map[string]interface{} { numberOfPercentiles := len(h.reportablePercentiles) result := make(map[string]interface{}, 2) - result["type"] = "histogram" + result[typeKey] = histogramTypeValue value := make(map[string]interface{}, numberOfPercentiles) for _, percentile := range h.reportablePercentiles { - percentileString := strconv.FormatFloat(percentile, 'f', 6, 64) - value[percentileString] = strconv.FormatFloat(h.Percentile(percentile), 'f', 6, 64) + percentileString := formatFloat(percentile) + value[percentileString] = formatFloat(h.Percentile(percentile)) } - result["value"] = value + result[valueKey] = value return result } -// Produce a histogram from a given specification. +/* +Produce a histogram from a given specification. +*/ func CreateHistogram(specification *HistogramSpecification) *Histogram { bucketCount := len(specification.Starts) diff --git a/metrics/histogram_test.go b/metrics/histogram_test.go index 8dd97a3..f10d0d4 100644 --- a/metrics/histogram_test.go +++ b/metrics/histogram_test.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// histogram_test.go provides a test complement for the histogram.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics diff --git a/metrics/metric.go b/metrics/metric.go new file mode 100644 index 0000000..f33c636 --- /dev/null +++ b/metrics/metric.go @@ -0,0 +1,23 @@ +/* +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 + +/* +A Metric is something that can be exposed via the registry framework. +*/ +type Metric interface { + /* + Produce a human-consumable representation of the metric. + */ + Humanize() string + /* + Produce a JSON-consumable representation of the metric. + */ + Marshallable() map[string]interface{} +} diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go index 4a07de4..03c3888 100644 --- a/metrics/metrics_test.go +++ b/metrics/metrics_test.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// metrics_test.go provides a test suite for all tests in the metrics package -// hierarchy. It employs the gocheck framework for test scaffolding. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics diff --git a/metrics/tallying_bucket.go b/metrics/tallying_bucket.go index e3a200f..3209cc8 100644 --- a/metrics/tallying_bucket.go +++ b/metrics/tallying_bucket.go @@ -1,12 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// 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. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -22,13 +20,17 @@ const ( upperThird = 2.0 * lowerThird ) -// A TallyingIndexEstimator is responsible for estimating the value of index for -// a given TallyingBucket, even though a TallyingBucket does not possess a -// collection of samples. There are a few strategies listed below for how -// this value should be approximated. +/* +A TallyingIndexEstimator is responsible for estimating the value of index for +a given TallyingBucket, even though a TallyingBucket does not possess a +collection of samples. There are a few strategies listed below for how +this value should be approximated. +*/ type TallyingIndexEstimator func(minimum, maximum float64, index, observations int) float64 -// Provide a filter for handling empty buckets. +/* +Provide a filter for handling empty buckets. +*/ func emptyFilter(e TallyingIndexEstimator) TallyingIndexEstimator { return func(minimum, maximum float64, index, observations int) float64 { if observations == 0 { @@ -39,23 +41,31 @@ func emptyFilter(e TallyingIndexEstimator) TallyingIndexEstimator { } } -// Report the smallest observed value in the bucket. +/* +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. +/* +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. +/* +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. +/* +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 { return minimum @@ -72,9 +82,11 @@ var Uniform TallyingIndexEstimator = emptyFilter(func(minimum, maximum float64, return maths.Average([]float64{minimum, maximum}) }) -// 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 -// as a new minimum or maximum if appropriate. +/* +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 +as a new minimum or maximum if appropriate. +*/ type TallyingBucket struct { observations int smallestObserved float64 @@ -119,7 +131,9 @@ func (b *TallyingBucket) ValueForIndex(index int) float64 { return b.estimator(b.smallestObserved, b.largestObserved, index, b.observations) } -// Produce a TallyingBucket with sane defaults. +/* +Produce a TallyingBucket with sane defaults. +*/ func DefaultTallyingBucket() TallyingBucket { return TallyingBucket{ smallestObserved: math.MaxFloat64, @@ -136,7 +150,9 @@ func CustomTallyingBucket(estimator TallyingIndexEstimator) TallyingBucket { } } -// This is used strictly for testing. +/* +This is used strictly for testing. +*/ func TallyingBucketBuilder() Bucket { b := DefaultTallyingBucket() return &b diff --git a/metrics/tallying_bucket_test.go b/metrics/tallying_bucket_test.go index 2198fac..f669de1 100644 --- a/metrics/tallying_bucket_test.go +++ b/metrics/tallying_bucket_test.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// tallying_bucket_test.go provides a test complement for the -// tallying_bucket.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics diff --git a/metrics/timer.go b/metrics/timer.go index 58f9137..b3a7c23 100644 --- a/metrics/timer.go +++ b/metrics/timer.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// timer.go provides a scalar metric that times how long a given event takes. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics @@ -12,20 +12,33 @@ import ( "time" ) -// This callback is called upon the completion of the timer—i.e., when it stops. +/* +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. +/* +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 struct { startTime time.Time endTime time.Time onCompletion CompletionCallback } -// Return a new StopWatch that is ready for instrumentation. +/* +Return a new StopWatch that is ready for instrumentation. +*/ func Start(onCompletion CompletionCallback) *StopWatch { return &StopWatch{ startTime: time.Now(), @@ -33,8 +46,10 @@ func Start(onCompletion CompletionCallback) *StopWatch { } } -// Stop the StopWatch returning the elapsed duration of its lifetime while -// firing an optional CompletionCallback in the background. +/* +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) @@ -46,8 +61,10 @@ func (s *StopWatch) Stop() time.Duration { return duration } -// Provide a quick way of instrumenting a InstrumentableCall and emitting its -// 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() diff --git a/metrics/timer_test.go b/metrics/timer_test.go index 3e54d6e..294962e 100644 --- a/metrics/timer_test.go +++ b/metrics/timer_test.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// timer_test.go provides a test complement for the timer.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package metrics diff --git a/registry.go b/registry.go index b3928dd..66b406f 100644 --- a/registry.go +++ b/registry.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// registry.go provides a container for centralized exposition of metrics to -// their prospective consumers. +Use of this source code is governed by a BSD-style license that can be found in +the LICENSE file. +*/ package registry @@ -20,9 +19,18 @@ import ( "time" ) -// Boilerplate metrics about the metrics reporting subservice. These are only -// exposed if the DefaultRegistry's exporter is hooked into the HTTP request -// handler. +const ( + jsonContentType = "application/json" + contentType = "Content-Type" + jsonSuffix = ".json" +) + +/* +Boilerplate metrics about the metrics reporting subservice. These are only +exposed if the DefaultRegistry's exporter is hooked into the HTTP request +handler. +*/ + var requestCount *metrics.GaugeMetric = &metrics.GaugeMetric{} var requestLatencyLogarithmicBuckets []float64 = metrics.LogarithmicSizedBucketsFor(0, 1000) var requestLatencyEqualBuckets []float64 = metrics.EquallySizedBucketsFor(0, 1000, 10) @@ -47,8 +55,10 @@ var requestLatencyEqualTallying *metrics.Histogram = metrics.CreateHistogram(&me ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.9, 0.99}, }) -// This callback accumulates the microsecond duration of the reporting -// framework's overhead such that it can be reported. +/* +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(int64(duration) / 1E3) @@ -58,33 +68,43 @@ var requestLatencyAccumulator metrics.CompletionCallback = func(duration time.Du requestLatencyEqualTallying.Add(microseconds) } -// Registry is, as the name implies, a registrar where metrics are listed. -// -// In most situations, using DefaultRegistry is sufficient versus creating -// one's own. +/* +Registry is, as the name implies, a registrar where metrics are listed. + +In most situations, using DefaultRegistry is sufficient versus creating one's +own. +*/ type Registry struct { mutex sync.RWMutex NameToMetric map[string]metrics.Metric } -// This builds a new metric registry. It is not needed in the majority of -// cases. +/* +This builds a new metric registry. It is not needed in the majority of +cases. +*/ func NewRegistry() *Registry { return &Registry{ NameToMetric: make(map[string]metrics.Metric), } } -// 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. It +is primarily a read-only object after server instantiation. +*/ var DefaultRegistry = NewRegistry() -// Associate a Metric with the DefaultRegistry. +/* +Associate a Metric with the DefaultRegistry. +*/ func Register(name string, metric metrics.Metric) { DefaultRegistry.Register(name, metric) } -// Register a metric with a given name. Name should be globally unique. +/* +Register a metric with a given name. Name should be globally unique. +*/ func (r *Registry) Register(name string, metric metrics.Metric) { r.mutex.Lock() defer r.mutex.Unlock() @@ -97,17 +117,19 @@ func (r *Registry) Register(name string, metric metrics.Metric) { } } -// Create a http.HandlerFunc that is tied to r Registry such that requests -// against it generate a representation of the housed metrics. +/* +Create a http.HandlerFunc that is tied to r Registry such that requests +against it generate a representation of the housed metrics. +*/ func (registry *Registry) YieldExporter() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var instrumentable metrics.InstrumentableCall = func() { requestCount.Increment() url := r.URL - if strings.HasSuffix(url.Path, ".json") { + if strings.HasSuffix(url.Path, jsonSuffix) { w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(contentType, jsonContentType) composite := make(map[string]interface{}, len(registry.NameToMetric)) for name, metric := range registry.NameToMetric { composite[name] = metric.Marshallable() @@ -126,9 +148,9 @@ func (registry *Registry) YieldExporter() http.HandlerFunc { } func init() { - DefaultRegistry.Register("requests_total", requestCount) - DefaultRegistry.Register("request_latency_logarithmic_accumulating_microseconds", requestLatencyLogarithmicAccumulating) - DefaultRegistry.Register("request_latency_equal_accumulating_microseconds", requestLatencyEqualAccumulating) - DefaultRegistry.Register("request_latency_logarithmic_tallying_microseconds", requestLatencyLogarithmicTallying) - DefaultRegistry.Register("request_latency_equal_tallying_microseconds", requestLatencyEqualTallying) + DefaultRegistry.Register("requests_metrics_total", requestCount) + DefaultRegistry.Register("requests_metrics_latency_logarithmic_accumulating_microseconds", requestLatencyLogarithmicAccumulating) + DefaultRegistry.Register("requests_metrics_latency_equal_accumulating_microseconds", requestLatencyEqualAccumulating) + DefaultRegistry.Register("requests_metrics_latency_logarithmic_tallying_microseconds", requestLatencyLogarithmicTallying) + DefaultRegistry.Register("request_metrics_latency_equal_tallying_microseconds", requestLatencyEqualTallying) } diff --git a/utility/documentation.go b/utility/documentation.go new file mode 100644 index 0000000..2143a4b --- /dev/null +++ b/utility/documentation.go @@ -0,0 +1,29 @@ +/* +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. + +optional.go provides a mechanism for safely getting a set value or falling +back to defaults a la a Haskell and Scala Maybe or Guava Optional. + +optional_test.go provides a test complement for the optional.go module. + +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 diff --git a/utility/optional.go b/utility/optional.go index b292ac9..383b097 100644 --- a/utility/optional.go +++ b/utility/optional.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// optional.go provides a mechanism for safely getting a set value or falling -// back to defaults. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package utility diff --git a/utility/optional_test.go b/utility/optional_test.go index 61b01b3..00f0f15 100644 --- a/utility/optional_test.go +++ b/utility/optional_test.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// optional_test.go provides a test complement for the optional.go module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package utility diff --git a/utility/priority_queue.go b/utility/priority_queue.go index 9d665ed..e277e11 100644 --- a/utility/priority_queue.go +++ b/utility/priority_queue.go @@ -1,10 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// priority_queue.go provides a simple priority queue. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package utility diff --git a/utility/priority_queue_test.go b/utility/priority_queue_test.go index f6d8e7f..0d1e51c 100644 --- a/utility/priority_queue_test.go +++ b/utility/priority_queue_test.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// priority_queue_test.go provides a test complement for the priority_queue.go -// module. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package utility diff --git a/utility/test_helper.go b/utility/test_helper.go index ffa38dc..b41169b 100644 --- a/utility/test_helper.go +++ b/utility/test_helper.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// test_helper.go provides a testing assistents for this package and its -// dependents. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package utility diff --git a/utility/utility_test.go b/utility/utility_test.go index 9ee6744..0962788 100644 --- a/utility/utility_test.go +++ b/utility/utility_test.go @@ -1,11 +1,10 @@ -// 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. +/* +Copyright (c) 2012, Matt T. Proud +All rights reserved. -// utility_test.go provides a test suite for all tests in the utility package -// hierarchy. It employs the gocheck framework for test scaffolding. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. +*/ package utility