Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
ac8a3a12c4 | |||
286785491c |
@@ -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
|
||||
}
|
||||
|
@@ -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++
|
||||
}
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -32,3 +32,53 @@ func SetOption(k, v interface{}) Option {
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetReadOption returns a function to setup a context with given value
|
||||
func SetReadOption(k, v interface{}) ReadOption {
|
||||
return func(o *ReadOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetWriteOption returns a function to setup a context with given value
|
||||
func SetWriteOption(k, v interface{}) WriteOption {
|
||||
return func(o *WriteOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetListOption returns a function to setup a context with given value
|
||||
func SetListOption(k, v interface{}) ListOption {
|
||||
return func(o *ListOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetDeleteOption returns a function to setup a context with given value
|
||||
func SetDeleteOption(k, v interface{}) DeleteOption {
|
||||
return func(o *DeleteOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetExistsOption returns a function to setup a context with given value
|
||||
func SetExistsOption(k, v interface{}) ExistsOption {
|
||||
return func(o *ExistsOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ func (n *noopStore) String() string {
|
||||
}
|
||||
|
||||
// Read reads store value by key
|
||||
func (n *noopStore) Exists(ctx context.Context, key string) error {
|
||||
func (n *noopStore) Exists(ctx context.Context, key string, opts ...ExistsOption) error {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"time"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
@@ -29,6 +30,9 @@ type Options struct {
|
||||
Meter meter.Meter
|
||||
// Tracer the tacer
|
||||
Tracer tracer.Tracer
|
||||
// TLSConfig specifies tls.Config for secure
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// Context should contain all implementation specific options, using context.WithValue.
|
||||
Context context.Context
|
||||
}
|
||||
@@ -51,6 +55,13 @@ func NewOptions(opts ...Option) Options {
|
||||
// Option sets values in Options
|
||||
type Option func(o *Options)
|
||||
|
||||
// TLSConfig specifies a *tls.Config
|
||||
func TLSConfig(t *tls.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.TLSConfig = t
|
||||
}
|
||||
}
|
||||
|
||||
// Context pass context to store
|
||||
func Context(ctx context.Context) Option {
|
||||
return func(o *Options) {
|
||||
@@ -120,8 +131,10 @@ func NewReadOptions(opts ...ReadOption) ReadOptions {
|
||||
|
||||
// ReadOptions configures an individual Read operation
|
||||
type ReadOptions struct {
|
||||
Database string
|
||||
Table string
|
||||
Database string
|
||||
Table string
|
||||
Namespace string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// ReadOption sets values in ReadOptions
|
||||
@@ -146,10 +159,12 @@ func NewWriteOptions(opts ...WriteOption) WriteOptions {
|
||||
|
||||
// WriteOptions configures an individual Write operation
|
||||
type WriteOptions struct {
|
||||
Database string
|
||||
Table string
|
||||
TTL time.Duration
|
||||
Metadata metadata.Metadata
|
||||
Database string
|
||||
Table string
|
||||
TTL time.Duration
|
||||
Metadata metadata.Metadata
|
||||
Namespace string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// WriteOption sets values in WriteOptions
|
||||
@@ -188,7 +203,10 @@ func NewDeleteOptions(opts ...DeleteOption) DeleteOptions {
|
||||
|
||||
// DeleteOptions configures an individual Delete operation
|
||||
type DeleteOptions struct {
|
||||
Database, Table string
|
||||
Database string
|
||||
Table string
|
||||
Namespace string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// DeleteOption sets values in DeleteOptions
|
||||
@@ -222,7 +240,9 @@ type ListOptions struct {
|
||||
// Limit limits the number of returned keys
|
||||
Limit uint
|
||||
// Offset when combined with Limit supports pagination
|
||||
Offset uint
|
||||
Offset uint
|
||||
Namespace string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// ListOption sets values in ListOptions
|
||||
@@ -263,3 +283,20 @@ func ListOffset(o uint) ListOption {
|
||||
l.Offset = o
|
||||
}
|
||||
}
|
||||
|
||||
type ExistsOption func(*ExistsOptions)
|
||||
|
||||
type ExistsOptions struct {
|
||||
Namespace string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
func NewExistsOptions(opts ...ExistsOption) ExistsOptions {
|
||||
options := ExistsOptions{
|
||||
Context: context.Background(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
@@ -12,6 +12,8 @@ import (
|
||||
var (
|
||||
// ErrNotFound is returned when a key doesn't exist
|
||||
ErrNotFound = errors.New("not found")
|
||||
// ErrInvalidKey is returned when a key has empty or have invalid format
|
||||
ErrInvalidKey = errors.New("invalid key")
|
||||
// DefaultStore is the global default store
|
||||
DefaultStore Store = NewStore()
|
||||
)
|
||||
@@ -25,7 +27,7 @@ type Store interface {
|
||||
// Options allows you to view the current options.
|
||||
Options() Options
|
||||
// Exists check that key exists in store
|
||||
Exists(ctx context.Context, key string) error
|
||||
Exists(ctx context.Context, key string, opts ...ExistsOption) error
|
||||
// Read reads a single key name to provided value with optional ReadOptions
|
||||
Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error
|
||||
// Write writes a value to key name to the store with optional WriteOption
|
||||
|
@@ -96,7 +96,7 @@ func (c *syncStore) List(ctx context.Context, opts ...store.ListOption) ([]strin
|
||||
return c.syncOpts.Stores[0].List(ctx, opts...)
|
||||
}
|
||||
|
||||
func (c *syncStore) Exists(ctx context.Context, key string) error {
|
||||
func (c *syncStore) Exists(ctx context.Context, key string, opts ...store.ExistsOption) error {
|
||||
return c.syncOpts.Stores[0].Exists(ctx, key)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user