-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #363 from suyash/pcp-go-kit-pr
metrics: add support for PCP
- Loading branch information
Showing
3 changed files
with
205 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
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,132 @@ | ||
package pcp | ||
|
||
import ( | ||
"github.com/performancecopilot/speed" | ||
|
||
"github.com/go-kit/kit/metrics" | ||
) | ||
|
||
// Reporter encapsulates a speed client. | ||
type Reporter struct { | ||
c *speed.PCPClient | ||
} | ||
|
||
// NewReporter creates a new Reporter instance. | ||
// The first parameter is the application name and is used to create | ||
// the speed client. Hence it should be a valid speed parameter name and | ||
// should not contain spaces or the path separator for your operating system. | ||
func NewReporter(appname string) (*Reporter, error) { | ||
c, err := speed.NewPCPClient(appname) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &Reporter{c}, nil | ||
} | ||
|
||
// Start starts the underlying speed client so it can start reporting registered | ||
// metrics to your PCP installation. | ||
func (r *Reporter) Start() { r.c.MustStart() } | ||
|
||
// Stop stops the underlying speed client so it can stop reporting registered | ||
// metrics to your PCP installation. | ||
func (r *Reporter) Stop() { r.c.MustStop() } | ||
|
||
// Counter implements metrics.Counter via a single dimensional speed.Counter. | ||
type Counter struct { | ||
c speed.Counter | ||
} | ||
|
||
// NewCounter creates a new Counter. | ||
// | ||
// This requires a name parameter and can optionally take a couple of | ||
// description strings, that are used to create the underlying speed.Counter | ||
// and are reported by PCP. | ||
func (r *Reporter) NewCounter(name string, desc ...string) (*Counter, error) { | ||
c, err := speed.NewPCPCounter(0, name, desc...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
r.c.MustRegister(c) | ||
return &Counter{c}, nil | ||
} | ||
|
||
// With is a no-op. | ||
func (c *Counter) With(labelValues ...string) metrics.Counter { return c } | ||
|
||
// Add increments Counter. | ||
// speed Counters only take int64, so delta is converted to int64 before | ||
// observation. speed Gauges can take float64 and `Add(float64)` | ||
// is implemented by metrics.Gauge. | ||
func (c *Counter) Add(delta float64) { c.c.Inc(int64(delta)) } | ||
|
||
// Gauge implements metrics.Gauge via a single dimensional speed.Gauge. | ||
type Gauge struct { | ||
g speed.Gauge | ||
} | ||
|
||
// NewGauge creates a new Gauge. | ||
// | ||
// This requires a name parameter, and again, can take a couple of | ||
// optional description strings. | ||
func (r *Reporter) NewGauge(name string, desc ...string) (*Gauge, error) { | ||
g, err := speed.NewPCPGauge(0, name, desc...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
r.c.MustRegister(g) | ||
return &Gauge{g}, nil | ||
} | ||
|
||
// With is a no-op. | ||
func (g *Gauge) With(labelValues ...string) metrics.Gauge { return g } | ||
|
||
// Set sets the value of the gauge. | ||
func (g *Gauge) Set(value float64) { g.g.Set(value) } | ||
|
||
// Add adds a value to the gauge. | ||
func (g *Gauge) Add(value float64) { g.g.Inc(value) } | ||
|
||
// Histogram wraps a speed Histogram. | ||
type Histogram struct { | ||
h speed.Histogram | ||
} | ||
|
||
// NewHistogram creates a new Histogram. | ||
// Minimum observeable value is 0. | ||
// Maximum observeable value is 3600000000. | ||
// | ||
// The required parameters are a metric name, | ||
// the minimum and maximum observable values, | ||
// and a metric unit for the units of the observed values. | ||
// | ||
// Optionally, it can also take a couple of description strings. | ||
func (r *Reporter) NewHistogram(name string, min, max int64, unit speed.MetricUnit, desc ...string) (*Histogram, error) { | ||
h, err := speed.NewPCPHistogram(name, min, max, 5, unit, desc...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
r.c.MustRegister(h) | ||
return &Histogram{h}, nil | ||
} | ||
|
||
// With is a no-op. | ||
func (h *Histogram) With(labelValues ...string) metrics.Histogram { return h } | ||
|
||
// Observe observes a value. | ||
// | ||
// This converts float64 value to int64 before observation, as the Histogram in | ||
// speed is backed using codahale/hdrhistogram, which only observes int64 | ||
// values. Additionally, the value is interpreted in the metric unit used to | ||
// construct the histogram. | ||
func (h *Histogram) Observe(value float64) { h.h.MustRecord(int64(value)) } | ||
|
||
// Mean returns the mean of the values observed so far by the Histogram. | ||
func (h *Histogram) Mean() float64 { return h.h.Mean() } | ||
|
||
// Percentile returns a percentile value for the given percentile | ||
// between 0 and 100 for all values observed by the histogram. | ||
func (h *Histogram) Percentile(p float64) int64 { return h.h.Percentile(p) } |
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,72 @@ | ||
package pcp | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/performancecopilot/speed" | ||
|
||
"github.com/go-kit/kit/metrics/teststat" | ||
) | ||
|
||
func TestCounter(t *testing.T) { | ||
r, err := NewReporter("test_counter") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
counter, err := r.NewCounter("speed_counter") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
counter = counter.With("label values", "not supported").(*Counter) | ||
|
||
value := func() float64 { f := counter.c.Val(); return float64(f) } | ||
if err := teststat.TestCounter(counter, value); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestGauge(t *testing.T) { | ||
r, err := NewReporter("test_gauge") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
gauge, err := r.NewGauge("speed_gauge") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
gauge = gauge.With("label values", "not supported").(*Gauge) | ||
|
||
value := func() float64 { f := gauge.g.Val(); return f } | ||
if err := teststat.TestGauge(gauge, value); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestHistogram(t *testing.T) { | ||
r, err := NewReporter("test_histogram") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
histogram, err := r.NewHistogram("speed_histogram", 0, 3600000000, speed.OneUnit) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
histogram = histogram.With("label values", "not supported").(*Histogram) | ||
|
||
quantiles := func() (float64, float64, float64, float64) { | ||
p50 := float64(histogram.Percentile(50)) | ||
p90 := float64(histogram.Percentile(90)) | ||
p95 := float64(histogram.Percentile(95)) | ||
p99 := float64(histogram.Percentile(99)) | ||
return p50, p90, p95, p99 | ||
} | ||
if err := teststat.TestHistogram(histogram, quantiles, 0.01); err != nil { | ||
t.Fatal(err) | ||
} | ||
} |