forked from prometheus/client_golang
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit into version control.
- Loading branch information
0 parents
commit 959403a
Showing
32 changed files
with
3,131 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Compiled Object files, Static and Dynamic libs (Shared Objects) | ||
*.o | ||
*.a | ||
*.so | ||
|
||
# Folders | ||
_obj | ||
_test | ||
|
||
# Architecture specific extensions/prefixes | ||
*.[568vq] | ||
[568vq].out | ||
|
||
*.cgo1.go | ||
*.cgo2.c | ||
_cgo_defun.c | ||
_cgo_gotypes.go | ||
_cgo_export.* | ||
|
||
_testmain.go | ||
|
||
*.exe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Copyright (c) 2012, Matt T. Proud | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this | ||
list of conditions and the following disclaimer. | ||
2. Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Overview | ||
This [Go](http:https://golang.org) package is an extraction of a piece of | ||
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 | ||
observe behaviors of the server's various components, so this was written. | ||
|
||
The code here is not a verbatim copy thereof but rather a thoughtful | ||
re-implementation should other folks need to consume and analyze such telemetry. | ||
|
||
N.B. --- I have spent a bit of time working through the model in my head and | ||
probably haven't elucidated my ideas as clearly as I need to. If you examine | ||
src/main.go and src/export/registry.go, you'll find an example of what type of | ||
potential instrumentation use cases this package addresses. There are probably | ||
numerous Go language idiomatic changes that need 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:https://travis-ci.org/matttproud/golang_instrumentation) | ||
|
||
# Metrics | ||
A metric is a measurement mechanism. | ||
|
||
## Gauge | ||
A Gauge is a metric that exposes merely an instantaneous value or some snapshot | ||
thereof. | ||
|
||
## Histogram | ||
A Histogram is a metric that captures events or samples into buckets. It | ||
exposes its values via percentile estimations. | ||
|
||
### 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 | ||
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 | ||
Once an Accumulating Bucket reaches capacity, its eviction policy is invoked. | ||
This reaps the oldest N objects subject to certain behavior. | ||
|
||
##### Remove Oldest | ||
This merely removes the oldest N items without performing some aggregation | ||
replacement operation on them. | ||
|
||
##### 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 | ||
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, | ||
it may situationally emit a minimum, maximum, an average, or any other | ||
reduction mechanism requested. | ||
|
||
# Testing | ||
This package employs [gocheck](http:https://labix.org/gocheck) for testing. Please | ||
ensure that all tests pass by running the following from the project root: | ||
|
||
$ go test ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
- 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// 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 centralization exposition of metrics to | ||
// their prospective consumers. | ||
|
||
package export | ||
|
||
import ( | ||
"encoding/json" | ||
"github.com/matttproud/golang_instrumentation/maths" | ||
"github.com/matttproud/golang_instrumentation/metrics" | ||
"log" | ||
"net/http" | ||
"strings" | ||
"sync" | ||
"time" | ||
) | ||
|
||
var requestCount *metrics.GaugeMetric = &metrics.GaugeMetric{} | ||
var requestLatencyLogarithmicBuckets []float64 = metrics.LogarithmicSizedBucketsFor(0, 1000) | ||
var requestLatencyEqualBuckets []float64 = metrics.EquallySizedBucketsFor(0, 1000, 10) | ||
var requestLatencyLogarithmicAccumulating *metrics.Histogram = metrics.CreateHistogram(&metrics.HistogramSpecification{ | ||
Starts: requestLatencyLogarithmicBuckets, | ||
BucketMaker: metrics.AccumulatingBucketBuilder(metrics.EvictAndReplaceWith(50, maths.Average), 1000), | ||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.9, 0.99}, | ||
}) | ||
var requestLatencyEqualAccumulating *metrics.Histogram = metrics.CreateHistogram(&metrics.HistogramSpecification{ | ||
Starts: requestLatencyEqualBuckets, | ||
BucketMaker: metrics.AccumulatingBucketBuilder(metrics.EvictAndReplaceWith(50, maths.Average), 1000), | ||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.9, 0.99}, | ||
}) | ||
var requestLatencyLogarithmicTallying *metrics.Histogram = metrics.CreateHistogram(&metrics.HistogramSpecification{ | ||
Starts: requestLatencyLogarithmicBuckets, | ||
BucketMaker: metrics.TallyingBucketBuilder, | ||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.9, 0.99}, | ||
}) | ||
var requestLatencyEqualTallying *metrics.Histogram = metrics.CreateHistogram(&metrics.HistogramSpecification{ | ||
Starts: requestLatencyEqualBuckets, | ||
BucketMaker: metrics.TallyingBucketBuilder, | ||
ReportablePercentiles: []float64{0.01, 0.05, 0.5, 0.9, 0.99}, | ||
}) | ||
|
||
var requestLatencyAccumulator metrics.CompletionCallback = func(duration time.Duration) { | ||
micros := float64(int64(duration) / 1E3) | ||
|
||
requestLatencyLogarithmicAccumulating.Add(micros) | ||
requestLatencyEqualAccumulating.Add(micros) | ||
requestLatencyLogarithmicTallying.Add(micros) | ||
requestLatencyEqualTallying.Add(micros) | ||
} | ||
|
||
// 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. | ||
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. | ||
var DefaultRegistry = NewRegistry() | ||
|
||
// 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. | ||
func (r *Registry) Register(name string, metric metrics.Metric) { | ||
r.mutex.Lock() | ||
defer r.mutex.Unlock() | ||
|
||
if _, present := r.NameToMetric[name]; !present { | ||
r.NameToMetric[name] = metric | ||
log.Printf("Registered %s.\n", name) | ||
} else { | ||
log.Printf("Attempted to register duplicate %s metric.\n", name) | ||
} | ||
} | ||
|
||
func handleJson(w http.ResponseWriter, r *http.Request) { | ||
var instrumentable metrics.InstrumentableCall = func() { | ||
|
||
requestCount.Increment() | ||
|
||
w.Header().Set("Content-Type", "application/json") | ||
|
||
composite := make(map[string]interface{}, len(DefaultRegistry.NameToMetric)) | ||
for name, metric := range DefaultRegistry.NameToMetric { | ||
composite[name] = metric.Marshallable() | ||
} | ||
|
||
data, _ := json.Marshal(composite) | ||
|
||
w.Write(data) | ||
} | ||
|
||
metrics.InstrumentCall(instrumentable, requestLatencyAccumulator) | ||
} | ||
|
||
// TODO(mtp): Make instance-specific. | ||
var Exporter http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) { | ||
url := r.URL | ||
|
||
if strings.HasSuffix(url.Path, ".json") { | ||
handleJson(w, r) | ||
} | ||
} | ||
|
||
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/matttproud/golang_instrumentation/export" | ||
"net/http" | ||
) | ||
|
||
func main() { | ||
http.Handle("/metrics.json", export.Exporter) | ||
http.ListenAndServe(":8080", nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// 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. | ||
|
||
// distributions.go provides basic distribution-generating functions that are | ||
// used primarily in testing contexts. | ||
|
||
package maths | ||
|
||
import ( | ||
"math" | ||
) | ||
|
||
// Go's standard library does not offer a factorial function. | ||
func Factorial(of int) int64 { | ||
if of <= 0 { | ||
return 1 | ||
} | ||
|
||
var result int64 = 1 | ||
|
||
for i := int64(of); i >= 1; i-- { | ||
result *= i | ||
} | ||
|
||
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. | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// 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. | ||
|
||
// helpers_for_testing.go provides a testing assistents for this package and its | ||
// dependents. | ||
|
||
package maths | ||
|
||
import ( | ||
. "launchpad.net/gocheck" | ||
"math" | ||
"reflect" | ||
) | ||
|
||
type isNaNChecker struct { | ||
*CheckerInfo | ||
} | ||
|
||
// 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"}}, | ||
} | ||
|
||
func (checker *isNaNChecker) Check(params []interface{}, names []string) (result bool, error string) { | ||
return isNaN(params[0]), "" | ||
} | ||
|
||
func isNaN(obtained interface{}) (result bool) { | ||
if obtained == nil { | ||
result = false | ||
} else { | ||
switch v := reflect.ValueOf(obtained); v.Kind() { | ||
case reflect.Float64: | ||
return math.IsNaN(obtained.(float64)) | ||
} | ||
} | ||
|
||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
|
||
// maths_test.go provides a test suite for all tests in the maths package | ||
// hierarchy. It employs the gocheck framework for test scaffolding. | ||
|
||
package maths | ||
|
||
import ( | ||
. "launchpad.net/gocheck" | ||
"testing" | ||
) | ||
|
||
type S struct{} | ||
|
||
var _ = Suite(&S{}) | ||
|
||
func TestMaths(t *testing.T) { | ||
TestingT(t) | ||
} |
Oops, something went wrong.