Merge pull request #3 from prometheus/usability/sundry

Fix documentation after reading via server.
This commit is contained in:
juliusv 2013-02-18 04:59:08 -08:00
commit 339ecd434d
14 changed files with 151 additions and 119 deletions

View File

@ -1,20 +1,5 @@
# Major Notes
The project's documentation is *not up-to-date due to rapidly-changing
requirements* that have quieted down in the interim, but the overall API should
be stable for several months even if things change under the hood.
An update to reflect the current state is pending. Key changes for current
users:
1. The code has been qualified in production environments.
2. Label-oriented metric exposition and registration, including docstrings.
3. Deprecation of gocheck in favor of native table-driven tests.
4. The best way to get a handle on this is to look at the examples.
Barring that, the antique documentation is below:
# Overview # Overview
This [Go](http://golang.org) package is an extraction of a piece of These [Go](http://golang.org) packages are an extraction of pieces of
instrumentation code I whipped-up for a personal project that a friend of mine instrumentation code I whipped-up for a personal project that a friend of mine
and I are working on. We were in need for some rudimentary statistics to and I are working on. We were in need for some rudimentary statistics to
observe behaviors of the server's various components, so this was written. observe behaviors of the server's various components, so this was written.
@ -33,7 +18,7 @@ to be made, but this task has been deferred for now.
[![Build Status](https://secure.travis-ci.org/prometheus/client_golang.png?branch=master)](http://travis-ci.org/prometheus/client_golang) [![Build Status](https://secure.travis-ci.org/prometheus/client_golang.png?branch=master)](http://travis-ci.org/prometheus/client_golang)
# Documentation # Documentation
Please read the [generated documentation](http://go.pkgdoc.org/launchpad.net/gocheck) Please read the [generated documentation](http://go.pkgdoc.org/github.com/prometheus/client_golang)
for the project's documentation from source code. for the project's documentation from source code.
# Basic Overview # Basic Overview
@ -41,40 +26,42 @@ for the project's documentation from source code.
A metric is a measurement mechanism. A metric is a measurement mechanism.
### Gauge ### Gauge
A Gauge is a metric that exposes merely an instantaneous value or some snapshot A _Gauge_ is a metric that exposes merely an instantaneous value or some
thereof. snapshot thereof.
### Counter
A _Counter_ is a metric that exposes merely a sum or tally of things.
### Histogram ### Histogram
A Histogram is a metric that captures events or samples into buckets. It A _Histogram_ is a metric that captures events or samples into _Buckets_. It
exposes its values via percentile estimations. exposes its values via percentile estimations.
#### Buckets #### Buckets
A Bucket is a generic container that collects samples and their values. It 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, 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 leaving it up to the concrete implementation to what to do with the injected
values. values.
##### Accumulating Bucket ##### Accumulating Bucket
An Accumulating Bucket is a bucket that appends the new sample to a timestamped An _Accumulating Bucket_ is a _Bucket_ that appends the new sample to a queue
priority queue such that the eldest values are evicted according to a given such that the eldest values are evicted according to a given policy.
policy.
##### Eviction Policies ###### Eviction Policies
Once an Accumulating Bucket reaches capacity, its eviction policy is invoked. Once an _Accumulating Bucket_ reaches capacity, its eviction policy is invoked.
This reaps the oldest N objects subject to certain behavior. 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 This merely removes the oldest N items without performing some aggregation
replacement operation on them. replacement operation on them.
###### Aggregate Oldest ####### Aggregate Oldest
This removes the oldest N items while performing some summary aggregation This removes the oldest N items while performing some summary aggregation
operation thereupon, which is then appended to the list in the former values' operation thereupon, which is then appended to the list in the former values'
place. place.
##### Tallying Bucket ##### Tallying Bucket
A Tallying Bucket differs from an Accumulating Bucket in that it never stores A _Tallying Bucket_ differs from an _Accumulating Bucket_ in that it never
any of the values emitted into it but rather exposes a simplied summary stores any of the values emitted into it but rather exposes a simplied summary
representation thereof. For instance, if a values therein is requested, representation thereof. For instance, if a values therein is requested,
it may situationally emit a minimum, maximum, an average, or any other it may situationally emit a minimum, maximum, an average, or any other
reduction mechanism requested. reduction mechanism requested.
@ -84,3 +71,6 @@ This package employs [gocheck](http://labix.org/gocheck) for testing. Please
ensure that all tests pass by running the following from the project root: ensure that all tests pass by running the following from the project root:
$ go test ./... $ go test ./...
The use of gocheck is summarily being phased out; however, old tests that use it
still exist.

View File

@ -10,6 +10,16 @@ var (
// NilLabels is a nil set of labels merely for end-user convenience. // NilLabels is a nil set of labels merely for end-user convenience.
NilLabels map[string]string = nil NilLabels map[string]string = nil
// The default http.Handler for exposing telemetric data over a web services
// 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.
DefaultRegistry = NewRegistry()
)
const (
// A prefix to be used to namespace instrumentation flags from others. // A prefix to be used to namespace instrumentation flags from others.
FlagNamespace = "telemetry." FlagNamespace = "telemetry."
@ -17,8 +27,12 @@ var (
// which subscribes to the Semantic Versioning scheme. // which subscribes to the Semantic Versioning scheme.
APIVersion = "0.0.1" APIVersion = "0.0.1"
// When reporting telemetric data over the HTTP web services interface, a web
// services interface shall include this header along with APIVersion as its
// value.
ProtocolVersionHeader = "X-Prometheus-API-Version" ProtocolVersionHeader = "X-Prometheus-API-Version"
// The customary web services endpoint on which telemetric data is exposed.
ExpositionResource = "/metrics.json" ExpositionResource = "/metrics.json"
baseLabelsKey = "baseLabels" baseLabelsKey = "baseLabels"

View File

@ -0,0 +1,9 @@
// 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 contributed Prometheus client components that may
// assist in your use of the library.
package contributor

View File

@ -1,10 +1,8 @@
/* // Copyright (c) 2013, Matt T. Proud
Copyright (c) 2013, Matt T. Proud // All rights reserved.
All rights reserved. //
// Use of this source code is governed by a BSD-style license that can be found in
Use of this source code is governed by a BSD-style license that can be found in // the LICENSE file.
the LICENSE file.
*/
package contributor package contributor

View File

@ -6,47 +6,6 @@
// registry.go provides a container for centralized exposition of metrics to // registry.go provides a container for centralized exposition of metrics to
// their prospective consumers. // their prospective consumers.
//
// registry.Register("human_readable_metric_name", metric) // registry.Register("human_readable_metric_name", "metric docstring", map[string]string{"baseLabel": "baseLabelValue"}, 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 package registry

View File

@ -0,0 +1,8 @@
// 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

View File

@ -0,0 +1,48 @@
// 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

View File

@ -0,0 +1,8 @@
// 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

View File

@ -4,9 +4,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// main.go provides a simple example of how to use this instrumentation // A simple example of how to use this instrumentation framework in the context
// framework in the context of having something that emits values into // of having something that emits values into its collectors.
// its collectors.
// //
// The emitted values correspond to uniform, normal, and exponential // The emitted values correspond to uniform, normal, and exponential
// distributions. // distributions.

View File

@ -4,8 +4,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// main.go provides a simple skeletal example of how this instrumentation // A simple skeletal example of how this instrumentation framework is registered
// framework is registered and invoked. // and invoked. Literally, this is the bare bones.
package main package main
import ( import (

View File

@ -5,18 +5,18 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// The maths package provides a number of mathematical-related helpers: // The maths package provides a number of mathematical-related helpers:
//
// distributions.go provides basic distribution-generating functions that are // distributions.go provides basic distribution-generating functions that are
// used primarily in testing contexts. // used primarily in testing contexts.
//
// helpers_for_testing.go provides a testing assistents for this package and its // helpers_for_testing.go provides a testing assistents for this package and its
// dependents. // dependents.
//
// maths_test.go provides a test suite for all tests in the maths package // maths_test.go provides a test suite for all tests in the maths package
// hierarchy. It employs the gocheck framework for test scaffolding. // hierarchy. It employs the gocheck framework for test scaffolding.
//
// statistics.go provides basic summary statistics functions for the purpose of // statistics.go provides basic summary statistics functions for the purpose of
// metrics aggregation. // metrics aggregation.
//
// statistics_test.go provides a test complement for the statistics.go module. // statistics_test.go provides a test complement for the statistics.go module.
package maths package maths

View File

@ -39,8 +39,6 @@ var (
abortOnMisuse bool abortOnMisuse bool
debugRegistration bool debugRegistration bool
useAggressiveSanityChecks bool useAggressiveSanityChecks bool
DefaultHandler = DefaultRegistry.Handler()
) )
// container represents a top-level registered metric that encompasses its // container represents a top-level registered metric that encompasses its
@ -52,28 +50,32 @@ type container struct {
name string name string
} }
// Registry is, as the name implies, a registrar where metrics are listed.
// type registry struct {
// In most situations, using DefaultRegistry is sufficient versus creating one's
// own.
type Registry struct {
mutex sync.RWMutex mutex sync.RWMutex
signatureContainers map[string]container signatureContainers map[string]container
} }
// Registry is a registrar where metrics are listed.
//
// In most situations, using DefaultRegistry is sufficient versus creating one's
// 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
// 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
}
// This builds a new metric registry. It is not needed in the majority of // This builds a new metric registry. It is not needed in the majority of
// cases. // cases.
func NewRegistry() *Registry { func NewRegistry() Registry {
return &Registry{ return registry{
signatureContainers: make(map[string]container), signatureContainers: make(map[string]container),
} }
} }
// 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, docstring string, baseLabels map[string]string, metric metrics.Metric) error { func Register(name, docstring string, baseLabels map[string]string, metric metrics.Metric) error {
return DefaultRegistry.Register(name, docstring, baseLabels, metric) return DefaultRegistry.Register(name, docstring, baseLabels, metric)
@ -82,7 +84,7 @@ func Register(name, docstring string, baseLabels map[string]string, metric metri
// isValidCandidate returns true if the candidate is acceptable for use. In the // isValidCandidate returns true if the candidate is acceptable for use. In the
// event of any apparent incorrect use it will report the problem, invalidate // event of any apparent incorrect use it will report the problem, invalidate
// the candidate, or outright abort. // the candidate, or outright abort.
func (r *Registry) isValidCandidate(name string, baseLabels map[string]string) (signature string, err error) { func (r registry) isValidCandidate(name string, baseLabels map[string]string) (signature string, err error) {
if len(name) == 0 { if len(name) == 0 {
err = fmt.Errorf("unnamed metric named with baseLabels %s is invalid", baseLabels) err = fmt.Errorf("unnamed metric named with baseLabels %s is invalid", baseLabels)
@ -137,8 +139,7 @@ func (r *Registry) isValidCandidate(name string, baseLabels map[string]string) (
return return
} }
// Register a metric with a given name. Name should be globally unique. 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 metrics.Metric) (err error) {
r.mutex.Lock() r.mutex.Lock()
defer r.mutex.Unlock() defer r.mutex.Unlock()
@ -163,7 +164,7 @@ func (r *Registry) Register(name, docstring string, baseLabels map[string]string
// YieldBasicAuthExporter creates a http.HandlerFunc that is protected by HTTP's // YieldBasicAuthExporter creates a http.HandlerFunc that is protected by HTTP's
// basic authentication. // basic authentication.
func (register *Registry) YieldBasicAuthExporter(username, password string) http.HandlerFunc { func (register registry) YieldBasicAuthExporter(username, password string) http.HandlerFunc {
// XXX: Work with Daniel to get this removed from the library, as it is really // XXX: Work with Daniel to get this removed from the library, as it is really
// superfluous and can be much more elegantly accomplished via // superfluous and can be much more elegantly accomplished via
// delegation. // delegation.
@ -192,7 +193,7 @@ func (register *Registry) YieldBasicAuthExporter(username, password string) http
}) })
} }
func (registry *Registry) dumpToWriter(writer io.Writer) (err error) { func (registry registry) dumpToWriter(writer io.Writer) (err error) {
defer func() { defer func() {
if err != nil { if err != nil {
dumpErrorCount.Increment(nil) dumpErrorCount.Increment(nil)
@ -260,15 +261,13 @@ func decorateWriter(request *http.Request, writer http.ResponseWriter) io.Writer
return gziper return gziper
} }
func (registry *Registry) YieldExporter() http.HandlerFunc { func (registry registry) YieldExporter() http.HandlerFunc {
log.Println("Registry.YieldExporter is deprecated in favor of Registry.Handler.") log.Println("Registry.YieldExporter is deprecated in favor of Registry.Handler.")
return registry.Handler() return registry.Handler()
} }
// Create a http.HandlerFunc that is tied to a Registry such that requests func (registry registry) Handler() http.HandlerFunc {
// against it generate a representation of the housed metrics.
func (registry *Registry) Handler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var instrumentable metrics.InstrumentableCall = func() { var instrumentable metrics.InstrumentableCall = func() {
requestCount.Increment(nil) requestCount.Increment(nil)

View File

@ -298,7 +298,7 @@ func testDumpToWriter(t test.Tester) {
} }
for i, scenario := range scenarios { for i, scenario := range scenarios {
registry := NewRegistry() registry := NewRegistry().(registry)
for name, metric := range scenario.in.metrics { for name, metric := range scenario.in.metrics {
err := registry.Register(name, fmt.Sprintf("metric %s", name), map[string]string{fmt.Sprintf("label_%s", name): name}, metric) err := registry.Register(name, fmt.Sprintf("metric %s", name), map[string]string{fmt.Sprintf("label_%s", name): name}, metric)

View File

@ -3,18 +3,18 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//
// The utility package provides general purpose helpers to assist with this // The utility package provides general purpose helpers to assist with this
// library. // library.
//
// priority_queue.go provides a simple priority queue. // priority_queue.go provides a simple priority queue.
//
// priority_queue_test.go provides a test complement for the priority_queue.go // priority_queue_test.go provides a test complement for the priority_queue.go
// module. // module.
//
// test_helper.go provides a testing assistents for this package and its // test_helper.go provides a testing assistents for this package and its
// dependents. // dependents.
//
// utility_test.go provides a test suite for all tests in the utility package // utility_test.go provides a test suite for all tests in the utility package
// hierarchy. It employs the gocheck framework for test scaffolding. // hierarchy. It employs the gocheck framework for test scaffolding.
package documentation package documentation