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 package meter
import ( import (
"io"
"sort"
"time" "time"
) )
@ -23,13 +25,14 @@ var (
// Meter is an interface for collecting and instrumenting metrics // Meter is an interface for collecting and instrumenting metrics
type Meter interface { type Meter interface {
Init(...Option) error Init(...Option) error
Counter(string, map[string]string) Counter Counter(string, ...Option) Counter
FloatCounter(string, map[string]string) FloatCounter FloatCounter(string, ...Option) FloatCounter
Gauge(string, func() float64, map[string]string) Gauge Gauge(string, func() float64, ...Option) Gauge
Set(map[string]string) Meter Set(...Option) Meter
Histogram(string, map[string]string) Histogram Histogram(string, ...Option) Histogram
Summary(string, map[string]string) Summary Summary(string, ...Option) Summary
SummaryExt(string, time.Duration, []float64, map[string]string) Summary SummaryExt(string, time.Duration, []float64, ...Option) Summary
Write(io.Writer, bool) error
Options() Options Options() Options
String() string String() string
} }
@ -69,3 +72,55 @@ type Summary interface {
Update(float64) Update(float64)
UpdateDuration(time.Time) 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.NotNil(t, meter)
assert.Equal(t, "/noop", meter.Options().Path) assert.Equal(t, "/noop", meter.Options().Path)
assert.Implements(t, new(Meter), meter) 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 package meter
import ( import (
"io"
"time" "time"
"github.com/unistack-org/micro/v3/metadata"
) )
// NoopMeter is an noop implementation of Meter // NoopMeter is an noop implementation of Meter
type noopMeter struct { type noopMeter struct {
opts Options opts Options
md map[string]string labels Labels
} }
// NewMeter returns a configured noop reporter: // NewMeter returns a configured noop reporter:
func NewMeter(opts ...Option) Meter { func NewMeter(opts ...Option) Meter {
return &noopMeter{ return &noopMeter{opts: NewOptions(opts...)}
opts: NewOptions(opts...),
}
} }
// Init initialize options // Init initialize options
@ -28,38 +25,52 @@ func (r *noopMeter) Init(opts ...Option) error {
} }
// Counter implements the Meter interface // Counter implements the Meter interface
func (r *noopMeter) Counter(name string, md map[string]string) Counter { func (r *noopMeter) Counter(name string, opts ...Option) Counter {
return &noopCounter{} options := Options{}
for _, o := range opts {
o(&options)
}
return &noopCounter{labels: options.Labels}
} }
// FloatCounter implements the Meter interface // 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{} return &noopFloatCounter{}
} }
// Gauge implements the Meter interface // 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{} return &noopGauge{}
} }
// Summary implements the Meter interface // 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{} return &noopSummary{}
} }
// SummaryExt implements the Meter interface // 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{} return &noopSummary{}
} }
// Histogram implements the Meter interface // 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{} return &noopHistogram{}
} }
// Set implements the Meter interface // Set implements the Meter interface
func (r *noopMeter) Set(md map[string]string) Meter { func (r *noopMeter) Set(opts ...Option) Meter {
return &noopMeter{opts: r.opts, md: metadata.Copy(md)} 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 // Options implements the Meter interface
@ -72,7 +83,9 @@ func (r *noopMeter) String() string {
return "noop" return "noop"
} }
type noopCounter struct{} type noopCounter struct {
labels Labels
}
func (r *noopCounter) Add(int) { func (r *noopCounter) Add(int) {

View File

@ -11,9 +11,9 @@ type Option func(*Options)
// Options for metrics implementations: // Options for metrics implementations:
type Options struct { type Options struct {
Address string Address string
Path string Path string
Metadata map[string]string Labels Labels
//TimingObjectives map[float64]float64 //TimingObjectives map[float64]float64
Logger logger.Logger Logger logger.Logger
Context context.Context Context context.Context
@ -25,7 +25,6 @@ type Options struct {
func NewOptions(opt ...Option) Options { func NewOptions(opt ...Option) Options {
opts := Options{ opts := Options{
Address: DefaultAddress, Address: DefaultAddress,
Metadata: make(map[string]string, 3), // 3 elements contains service name, version and id
Path: DefaultPath, Path: DefaultPath,
Context: context.Background(), Context: context.Background(),
Logger: logger.DefaultLogger, 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) { return func(o *Options) {
for k, v := range md { o.Labels = labels
o.Metadata[k] = v
}
} }
} }
*/
/* /*
// TimingObjectives defines the desired spread of statistics for histogram / timing metrics: // TimingObjectives defines the desired spread of statistics for histogram / timing metrics:
@ -85,3 +84,11 @@ func Logger(l logger.Logger) Option {
o.Logger = l 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)
}
}