meter: complete interface

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2021-01-27 00:54:19 +03:00
parent 286785491c
commit ac8a3a12c4
4 changed files with 157 additions and 33 deletions

View File

@ -2,6 +2,8 @@
package meter
import (
"io"
"sort"
"time"
)
@ -23,13 +25,14 @@ var (
// Meter is an interface for collecting and instrumenting metrics
type Meter interface {
Init(...Option) error
Counter(string, map[string]string) Counter
FloatCounter(string, map[string]string) FloatCounter
Gauge(string, func() float64, map[string]string) Gauge
Set(map[string]string) Meter
Histogram(string, map[string]string) Histogram
Summary(string, map[string]string) Summary
SummaryExt(string, time.Duration, []float64, map[string]string) Summary
Counter(string, ...Option) Counter
FloatCounter(string, ...Option) FloatCounter
Gauge(string, func() float64, ...Option) Gauge
Set(...Option) Meter
Histogram(string, ...Option) Histogram
Summary(string, ...Option) Summary
SummaryExt(string, time.Duration, []float64, ...Option) Summary
Write(io.Writer, bool) error
Options() Options
String() string
}
@ -69,3 +72,55 @@ type Summary interface {
Update(float64)
UpdateDuration(time.Time)
}
type Labels struct {
keys []string
vals []string
}
func (ls Labels) Len() int {
return len(ls.keys)
}
func (ls Labels) Swap(i, j int) {
ls.keys[i], ls.keys[j] = ls.keys[j], ls.keys[i]
ls.vals[i], ls.vals[j] = ls.vals[j], ls.vals[i]
}
func (ls Labels) Less(i, j int) bool {
return ls.vals[i] < ls.vals[j]
}
func (ls Labels) Sort() {
sort.Sort(ls)
}
func (ls Labels) Append(nls Labels) Labels {
for n := range nls.keys {
ls.keys = append(ls.keys, nls.keys[n])
ls.vals = append(ls.vals, nls.vals[n])
}
return ls
}
type LabelIter struct {
labels Labels
cnt int
cur int
}
func (ls Labels) Iter() *LabelIter {
ls.Sort()
return &LabelIter{labels: ls, cnt: len(ls.keys)}
}
func (iter *LabelIter) Next(k, v *string) bool {
if iter.cur+1 > iter.cnt {
return false
}
*k = iter.labels.keys[iter.cur]
*v = iter.labels.vals[iter.cur]
iter.cur++
return true
}

View File

@ -11,4 +11,53 @@ func TestNoopMeter(t *testing.T) {
assert.NotNil(t, meter)
assert.Equal(t, "/noop", meter.Options().Path)
assert.Implements(t, new(Meter), meter)
cnt := meter.Counter("counter", Label("server", "noop"))
cnt.Inc()
}
func TestLabels(t *testing.T) {
var ls Labels
ls.keys = []string{"type", "server"}
ls.vals = []string{"noop", "http"}
ls.Sort()
if ls.keys[0] != "server" || ls.vals[0] != "http" {
t.Fatalf("sort error: %v", ls)
}
}
func TestLabelsAppend(t *testing.T) {
var ls Labels
ls.keys = []string{"type", "server"}
ls.vals = []string{"noop", "http"}
var nls Labels
nls.keys = []string{"registry"}
nls.vals = []string{"gossip"}
ls = ls.Append(nls)
ls.Sort()
if ls.keys[0] != "registry" || ls.vals[0] != "gossip" {
t.Fatalf("append error: %v", ls)
}
}
func TestIterator(t *testing.T) {
var ls Labels
ls.keys = []string{"type", "server", "registry"}
ls.vals = []string{"noop", "http", "gossip"}
iter := ls.Iter()
var k, v string
cnt := 0
for iter.Next(&k, &v) {
if cnt == 1 && (k != "server" || v != "http") {
t.Fatalf("iter error: %s != %s || %s != %s", k, "server", v, "http")
}
cnt++
}
}

View File

@ -1,22 +1,19 @@
package meter
import (
"io"
"time"
"github.com/unistack-org/micro/v3/metadata"
)
// NoopMeter is an noop implementation of Meter
type noopMeter struct {
opts Options
md map[string]string
opts Options
labels Labels
}
// NewMeter returns a configured noop reporter:
func NewMeter(opts ...Option) Meter {
return &noopMeter{
opts: NewOptions(opts...),
}
return &noopMeter{opts: NewOptions(opts...)}
}
// Init initialize options
@ -28,38 +25,52 @@ func (r *noopMeter) Init(opts ...Option) error {
}
// Counter implements the Meter interface
func (r *noopMeter) Counter(name string, md map[string]string) Counter {
return &noopCounter{}
func (r *noopMeter) Counter(name string, opts ...Option) Counter {
options := Options{}
for _, o := range opts {
o(&options)
}
return &noopCounter{labels: options.Labels}
}
// FloatCounter implements the Meter interface
func (r *noopMeter) FloatCounter(name string, md map[string]string) FloatCounter {
func (r *noopMeter) FloatCounter(name string, opts ...Option) FloatCounter {
return &noopFloatCounter{}
}
// Gauge implements the Meter interface
func (r *noopMeter) Gauge(name string, f func() float64, md map[string]string) Gauge {
func (r *noopMeter) Gauge(name string, f func() float64, opts ...Option) Gauge {
return &noopGauge{}
}
// Summary implements the Meter interface
func (r *noopMeter) Summary(name string, md map[string]string) Summary {
func (r *noopMeter) Summary(name string, opts ...Option) Summary {
return &noopSummary{}
}
// SummaryExt implements the Meter interface
func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, md map[string]string) Summary {
func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, opts ...Option) Summary {
return &noopSummary{}
}
// Histogram implements the Meter interface
func (r *noopMeter) Histogram(name string, md map[string]string) Histogram {
func (r *noopMeter) Histogram(name string, opts ...Option) Histogram {
return &noopHistogram{}
}
// Set implements the Meter interface
func (r *noopMeter) Set(md map[string]string) Meter {
return &noopMeter{opts: r.opts, md: metadata.Copy(md)}
func (r *noopMeter) Set(opts ...Option) Meter {
m := &noopMeter{opts: r.opts}
for _, o := range opts {
o(&m.opts)
}
return m
}
func (r *noopMeter) Write(w io.Writer, withProcessMetrics bool) error {
return nil
}
// Options implements the Meter interface
@ -72,7 +83,9 @@ func (r *noopMeter) String() string {
return "noop"
}
type noopCounter struct{}
type noopCounter struct {
labels Labels
}
func (r *noopCounter) Add(int) {

View File

@ -11,9 +11,9 @@ type Option func(*Options)
// Options for metrics implementations:
type Options struct {
Address string
Path string
Metadata map[string]string
Address string
Path string
Labels Labels
//TimingObjectives map[float64]float64
Logger logger.Logger
Context context.Context
@ -25,7 +25,6 @@ type Options struct {
func NewOptions(opt ...Option) Options {
opts := Options{
Address: DefaultAddress,
Metadata: make(map[string]string, 3), // 3 elements contains service name, version and id
Path: DefaultPath,
Context: context.Background(),
Logger: logger.DefaultLogger,
@ -61,14 +60,14 @@ func Address(value string) Option {
}
}
// Metadata will be added to every metric
func Metadata(md map[string]string) Option {
/*
// Labels be added to every metric
func Labels(labels []string) Option {
return func(o *Options) {
for k, v := range md {
o.Metadata[k] = v
}
o.Labels = labels
}
}
*/
/*
// TimingObjectives defines the desired spread of statistics for histogram / timing metrics:
@ -85,3 +84,11 @@ func Logger(l logger.Logger) Option {
o.Logger = l
}
}
// Label sets the label
func Label(key, val string) Option {
return func(o *Options) {
o.Labels.keys = append(o.Labels.keys, key)
o.Labels.vals = append(o.Labels.vals, val)
}
}