meter: rework meter interface
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
8a2c4c511e
commit
8494178b0d
62
meter/meter.go
Normal file
62
meter/meter.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Package meter is for instrumentation
|
||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultReporter Meter = NewMeter()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Meter is an interface for collecting and instrumenting metrics
|
||||||
|
type Meter interface {
|
||||||
|
Init(...Option) error
|
||||||
|
Counter(string, metadata.Metadata) Counter
|
||||||
|
FloatCounter(string, metadata.Metadata) FloatCounter
|
||||||
|
Gauge(string, func() float64, metadata.Metadata) Gauge
|
||||||
|
Set(metadata.Metadata) Meter
|
||||||
|
Histogram(string, metadata.Metadata) Histogram
|
||||||
|
Summary(string, metadata.Metadata) Summary
|
||||||
|
SummaryExt(string, time.Duration, []float64, metadata.Metadata) Summary
|
||||||
|
Options() Options
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counter is a counter
|
||||||
|
type Counter interface {
|
||||||
|
Add(int)
|
||||||
|
Dec()
|
||||||
|
Get() uint64
|
||||||
|
Inc()
|
||||||
|
Set(uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatCounter is a float64 counter
|
||||||
|
type FloatCounter interface {
|
||||||
|
Add(float64)
|
||||||
|
Get() float64
|
||||||
|
Set(float64)
|
||||||
|
Sub(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gauge is a float64 gauge
|
||||||
|
type Gauge interface {
|
||||||
|
Get() float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Histogram is a histogram for non-negative values with automatically created buckets
|
||||||
|
type Histogram interface {
|
||||||
|
Reset()
|
||||||
|
Update(float64)
|
||||||
|
UpdateDuration(time.Time)
|
||||||
|
// VisitNonZeroBuckets(f func(vmrange string, count uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary is the summary
|
||||||
|
type Summary interface {
|
||||||
|
Update(float64)
|
||||||
|
UpdateDuration(time.Time)
|
||||||
|
}
|
14
meter/meter_test.go
Normal file
14
meter/meter_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNoopMeter(t *testing.T) {
|
||||||
|
meter := NewMeter(Path("/noop"))
|
||||||
|
assert.NotNil(t, meter)
|
||||||
|
assert.Equal(t, "/noop", meter.Options().Path)
|
||||||
|
assert.Implements(t, new(Meter), meter)
|
||||||
|
}
|
132
meter/noop.go
132
meter/noop.go
@ -6,42 +6,140 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NoopReporter is an noop implementation of Reporter:
|
// NoopMeter is an noop implementation of Meter
|
||||||
type noopReporter struct {
|
type noopMeter struct {
|
||||||
opts Options
|
opts Options
|
||||||
|
md metadata.Metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReporter returns a configured noop reporter:
|
// NewMeter returns a configured noop reporter:
|
||||||
func NewReporter(opts ...Option) Reporter {
|
func NewMeter(opts ...Option) Meter {
|
||||||
return &noopReporter{
|
return &noopMeter{
|
||||||
opts: NewOptions(opts...),
|
opts: NewOptions(opts...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize options
|
// Init initialize options
|
||||||
func (r *noopReporter) Init(opts ...Option) error {
|
func (r *noopMeter) Init(opts ...Option) error {
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&r.opts)
|
o(&r.opts)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count implements the Reporter interface Count method:
|
// Counter implements the Meter interface
|
||||||
func (r *noopReporter) Count(metricName string, value int64, md metadata.Metadata) error {
|
func (r *noopMeter) Counter(name string, md metadata.Metadata) Counter {
|
||||||
return nil
|
return &noopCounter{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gauge implements the Reporter interface Gauge method:
|
// FloatCounter implements the Meter interface
|
||||||
func (r *noopReporter) Gauge(metricName string, value float64, md metadata.Metadata) error {
|
func (r *noopMeter) FloatCounter(name string, md metadata.Metadata) FloatCounter {
|
||||||
return nil
|
return &noopFloatCounter{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timing implements the Reporter interface Timing method:
|
// Gauge implements the Meter interface
|
||||||
func (r *noopReporter) Timing(metricName string, value time.Duration, md metadata.Metadata) error {
|
func (r *noopMeter) Gauge(name string, f func() float64, md metadata.Metadata) Gauge {
|
||||||
return nil
|
return &noopGauge{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options implements the Reporter interface Optios method:
|
// Summary implements the Meter interface
|
||||||
func (r *noopReporter) Options() Options {
|
func (r *noopMeter) Summary(name string, md metadata.Metadata) Summary {
|
||||||
|
return &noopSummary{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SummaryExt implements the Meter interface
|
||||||
|
func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, md metadata.Metadata) Summary {
|
||||||
|
return &noopSummary{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Histogram implements the Meter interface
|
||||||
|
func (r *noopMeter) Histogram(name string, md metadata.Metadata) Histogram {
|
||||||
|
return &noopHistogram{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the Meter interface
|
||||||
|
func (r *noopMeter) Set(md metadata.Metadata) Meter {
|
||||||
|
return &noopMeter{opts: r.opts, md: metadata.Copy(md)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options implements the Meter interface
|
||||||
|
func (r *noopMeter) Options() Options {
|
||||||
return r.opts
|
return r.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String implements the Meter interface
|
||||||
|
func (r *noopMeter) String() string {
|
||||||
|
return "noop"
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopCounter struct{}
|
||||||
|
|
||||||
|
func (r *noopCounter) Add(int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Dec() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Get() uint64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Inc() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Set(uint64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopFloatCounter struct{}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Add(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Get() float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Set(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Sub(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopGauge struct{}
|
||||||
|
|
||||||
|
func (r *noopGauge) Get() float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopSummary struct{}
|
||||||
|
|
||||||
|
func (r *noopSummary) Update(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopSummary) UpdateDuration(time.Time) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopHistogram struct{}
|
||||||
|
|
||||||
|
func (r *noopHistogram) Reset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopHistogram) Update(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopHistogram) UpdateDuration(time.Time) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (r *noopHistogram) VisitNonZeroBuckets(f func(vmrange string, count uint64)) {}
|
||||||
|
@ -8,12 +8,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// The Prometheus metrics will be made available on this port:
|
// The Meter data will be made available on this port
|
||||||
defaultPrometheusListenAddress = ":9000"
|
DefaultAddress = ":9090"
|
||||||
// This is the endpoint where the Prometheus metrics will be made available ("/metrics" is the default with Prometheus):
|
// This is the endpoint where the Meter data will be made available ("/metrics" is the default)
|
||||||
defaultPath = "/metrics"
|
DefaultPath = "/metrics"
|
||||||
// timingObjectives is the default spread of stats we maintain for timings / histograms:
|
// timingObjectives is the default spread of stats we maintain for timings / histograms:
|
||||||
defaultTimingObjectives = map[float64]float64{0.0: 0, 0.5: 0.05, 0.75: 0.04, 0.90: 0.03, 0.95: 0.02, 0.98: 0.001, 1: 0}
|
//defaultTimingObjectives = map[float64]float64{0.0: 0, 0.5: 0.05, 0.75: 0.04, 0.90: 0.03, 0.95: 0.02, 0.98: 0.001, 1: 0}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option powers the configuration for metrics implementations:
|
// Option powers the configuration for metrics implementations:
|
||||||
@ -23,8 +23,8 @@ type Option func(*Options)
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
Address string
|
Address string
|
||||||
Path string
|
Path string
|
||||||
DefaultTags metadata.Metadata
|
Metadata metadata.Metadata
|
||||||
TimingObjectives map[float64]float64
|
//TimingObjectives map[float64]float64
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
@ -32,11 +32,12 @@ type Options struct {
|
|||||||
// NewOptions prepares a set of options:
|
// NewOptions prepares a set of options:
|
||||||
func NewOptions(opt ...Option) Options {
|
func NewOptions(opt ...Option) Options {
|
||||||
opts := Options{
|
opts := Options{
|
||||||
Address: defaultPrometheusListenAddress,
|
Address: DefaultAddress,
|
||||||
DefaultTags: metadata.New(2),
|
Metadata: metadata.New(3), // 3 elements contains service name, version and id
|
||||||
Path: defaultPath,
|
Path: DefaultPath,
|
||||||
TimingObjectives: defaultTimingObjectives,
|
// TimingObjectives: defaultTimingObjectives,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range opt {
|
for _, o := range opt {
|
||||||
@ -53,33 +54,35 @@ func Context(ctx context.Context) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path used to serve metrics over HTTP:
|
// Path used to serve metrics over HTTP
|
||||||
func Path(value string) Option {
|
func Path(value string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Path = value
|
o.Path = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address is the listen address to serve metrics on:
|
// Address is the listen address to serve metrics
|
||||||
func Address(value string) Option {
|
func Address(value string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Address = value
|
o.Address = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultTags will be added to every metric:
|
// Metadata will be added to every metric
|
||||||
func DefaultTags(md metadata.Metadata) Option {
|
func Metadata(md metadata.Metadata) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.DefaultTags = metadata.Copy(md)
|
o.Metadata = metadata.Copy(md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// TimingObjectives defines the desired spread of statistics for histogram / timing metrics:
|
// TimingObjectives defines the desired spread of statistics for histogram / timing metrics:
|
||||||
func TimingObjectives(value map[float64]float64) Option {
|
func TimingObjectives(value map[float64]float64) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.TimingObjectives = value
|
o.TimingObjectives = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Logger sets the logger
|
// Logger sets the logger
|
||||||
func Logger(l logger.Logger) Option {
|
func Logger(l logger.Logger) Option {
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
// Package meter is for instrumentation
|
|
||||||
package meter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultReporter Reporter = NewReporter()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reporter is an interface for collecting and instrumenting metrics
|
|
||||||
type Reporter interface {
|
|
||||||
Init(...Option) error
|
|
||||||
Count(id string, value int64, md metadata.Metadata) error
|
|
||||||
Gauge(id string, value float64, md metadata.Metadata) error
|
|
||||||
Timing(id string, value time.Duration, md metadata.Metadata) error
|
|
||||||
Options() Options
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package meter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNoopReporter(t *testing.T) {
|
|
||||||
// Make a Reporter:
|
|
||||||
reporter := NewReporter(Path("/noop"))
|
|
||||||
assert.NotNil(t, reporter)
|
|
||||||
assert.Equal(t, "/noop", reporter.Options().Path)
|
|
||||||
|
|
||||||
// Check that our implementation is valid:
|
|
||||||
assert.Implements(t, new(Reporter), reporter)
|
|
||||||
}
|
|
@ -9,15 +9,15 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/server"
|
"github.com/unistack-org/micro/v3/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Wrapper provides a HandlerFunc for meter.Reporter implementations:
|
// Wrapper provides a HandlerFunc for meter.Meter implementations
|
||||||
type Wrapper struct {
|
type Wrapper struct {
|
||||||
reporter meter.Reporter
|
meter meter.Meter
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a *Wrapper configured with the given meter.Reporter:
|
// New returns a *Wrapper configured with the given meter.Meter
|
||||||
func New(reporter meter.Reporter) *Wrapper {
|
func New(meter meter.Meter) *Wrapper {
|
||||||
return &Wrapper{
|
return &Wrapper{
|
||||||
reporter: reporter,
|
meter: meter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ func (w *Wrapper) HandlerFunc(handlerFunction server.HandlerFunc) server.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instrument the result (if the DefaultClient has been configured):
|
// Instrument the result (if the DefaultClient has been configured):
|
||||||
w.reporter.Timing("service.handler", time.Since(callTime), tags)
|
w.meter.Summary("service.handler", tags).Update(float64(time.Since(callTime).Seconds()))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user