From a02a25d9558ed818ce2b26b10eca8ccf13066e02 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 8 Sep 2020 13:14:45 +0100 Subject: [PATCH] Remove all the external plugins except grpc (#1988) * Remove all the external plugins except grpc * strip cockroach * strip nats test * fix build --- broker/nats/context.go | 17 - broker/nats/nats.go | 294 -------------- broker/nats/nats_test.go | 98 ----- broker/nats/options.go | 19 - config/source/etcd/README.md | 51 --- config/source/etcd/etcd.go | 145 ------- config/source/etcd/options.go | 70 ---- config/source/etcd/util.go | 89 ---- config/source/etcd/watcher.go | 113 ------ events/stream/nats/nats.go | 190 --------- events/stream/nats/nats_test.go | 3 - events/stream/nats/options.go | 42 -- events/stream/test/stream_test.go | 9 +- go.mod | 27 +- go.sum | 133 +----- metrics/prometheus/README.md | 26 -- metrics/prometheus/metric_family.go | 118 ------ metrics/prometheus/metrics.go | 68 ---- metrics/prometheus/reporter.go | 75 ---- metrics/prometheus/reporter_test.go | 89 ---- registry/etcd/etcd.go | 605 ---------------------------- registry/etcd/etcd_test.go | 68 ---- registry/etcd/options.go | 37 -- registry/etcd/watcher.go | 105 ----- store/cockroach/cockroach.go | 513 ----------------------- store/cockroach/metadata.go | 45 --- store/test/store_test.go | 21 +- sync/etcd/etcd.go | 179 -------- 28 files changed, 24 insertions(+), 3225 deletions(-) delete mode 100644 broker/nats/context.go delete mode 100644 broker/nats/nats.go delete mode 100644 broker/nats/nats_test.go delete mode 100644 broker/nats/options.go delete mode 100644 config/source/etcd/README.md delete mode 100644 config/source/etcd/etcd.go delete mode 100644 config/source/etcd/options.go delete mode 100644 config/source/etcd/util.go delete mode 100644 config/source/etcd/watcher.go delete mode 100644 events/stream/nats/nats.go delete mode 100644 events/stream/nats/nats_test.go delete mode 100644 events/stream/nats/options.go delete mode 100644 metrics/prometheus/README.md delete mode 100644 metrics/prometheus/metric_family.go delete mode 100644 metrics/prometheus/metrics.go delete mode 100644 metrics/prometheus/reporter.go delete mode 100644 metrics/prometheus/reporter_test.go delete mode 100644 registry/etcd/etcd.go delete mode 100644 registry/etcd/etcd_test.go delete mode 100644 registry/etcd/options.go delete mode 100644 registry/etcd/watcher.go delete mode 100644 store/cockroach/cockroach.go delete mode 100644 store/cockroach/metadata.go delete mode 100644 sync/etcd/etcd.go diff --git a/broker/nats/context.go b/broker/nats/context.go deleted file mode 100644 index 2432291a..00000000 --- a/broker/nats/context.go +++ /dev/null @@ -1,17 +0,0 @@ -package nats - -import ( - "context" - - "github.com/micro/go-micro/v3/broker" -) - -// setBrokerOption returns a function to setup a context with given value -func setBrokerOption(k, v interface{}) broker.Option { - return func(o *broker.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, k, v) - } -} diff --git a/broker/nats/nats.go b/broker/nats/nats.go deleted file mode 100644 index d9907c10..00000000 --- a/broker/nats/nats.go +++ /dev/null @@ -1,294 +0,0 @@ -// Package nats provides a NATS broker -package nats - -import ( - "context" - "errors" - "strings" - "sync" - - "github.com/micro/go-micro/v3/broker" - "github.com/micro/go-micro/v3/codec/json" - "github.com/micro/go-micro/v3/logger" - "github.com/micro/go-micro/v3/registry/mdns" - nats "github.com/nats-io/nats.go" -) - -type natsBroker struct { - sync.Once - sync.RWMutex - - // indicate if we're connected - connected bool - - addrs []string - conn *nats.Conn - opts broker.Options - nopts nats.Options - - // should we drain the connection - drain bool - closeCh chan (error) -} - -type subscriber struct { - s *nats.Subscription - opts broker.SubscribeOptions -} - -func (s *subscriber) Options() broker.SubscribeOptions { - return s.opts -} - -func (s *subscriber) Topic() string { - return s.s.Subject -} - -func (s *subscriber) Unsubscribe() error { - return s.s.Unsubscribe() -} - -func (n *natsBroker) Address() string { - if n.conn != nil && n.conn.IsConnected() { - return n.conn.ConnectedUrl() - } - - if len(n.addrs) > 0 { - return n.addrs[0] - } - - return "" -} - -func (n *natsBroker) setAddrs(addrs []string) []string { - //nolint:prealloc - var cAddrs []string - for _, addr := range addrs { - if len(addr) == 0 { - continue - } - if !strings.HasPrefix(addr, "nats://") { - addr = "nats://" + addr - } - cAddrs = append(cAddrs, addr) - } - if len(cAddrs) == 0 { - cAddrs = []string{nats.DefaultURL} - } - return cAddrs -} - -func (n *natsBroker) Connect() error { - n.Lock() - defer n.Unlock() - - if n.connected { - return nil - } - - status := nats.CLOSED - if n.conn != nil { - status = n.conn.Status() - } - - switch status { - case nats.CONNECTED, nats.RECONNECTING, nats.CONNECTING: - n.connected = true - return nil - default: // DISCONNECTED or CLOSED or DRAINING - opts := n.nopts - opts.Servers = n.addrs - opts.Secure = n.opts.Secure - opts.TLSConfig = n.opts.TLSConfig - - // secure might not be set - if n.opts.TLSConfig != nil { - opts.Secure = true - } - - c, err := opts.Connect() - if err != nil { - if logger.V(logger.WarnLevel, logger.DefaultLogger) { - logger.Warnf("Error connecting to broker: %v", err) - } - - return err - } - n.conn = c - n.connected = true - return nil - } -} - -func (n *natsBroker) Disconnect() error { - n.Lock() - defer n.Unlock() - - // drain the connection if specified - if n.drain { - n.conn.Drain() - n.closeCh <- nil - } - - // close the client connection - n.conn.Close() - - // set not connected - n.connected = false - - return nil -} - -func (n *natsBroker) Init(opts ...broker.Option) error { - n.setOption(opts...) - return nil -} - -func (n *natsBroker) Options() broker.Options { - return n.opts -} - -func (n *natsBroker) Publish(topic string, msg *broker.Message, opts ...broker.PublishOption) error { - n.RLock() - defer n.RUnlock() - - if n.conn == nil { - return errors.New("not connected") - } - - b, err := n.opts.Codec.Marshal(msg) - if err != nil { - return err - } - return n.conn.Publish(topic, b) -} - -func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { - n.RLock() - if n.conn == nil { - n.RUnlock() - return nil, errors.New("not connected") - } - n.RUnlock() - - opt := broker.SubscribeOptions{ - Context: context.Background(), - } - - for _, o := range opts { - o(&opt) - } - - fn := func(msg *nats.Msg) { - var m *broker.Message - eh := opt.ErrorHandler - err := n.opts.Codec.Unmarshal(msg.Data, &m) - if err != nil { - m.Body = msg.Data - if logger.V(logger.ErrorLevel, logger.DefaultLogger) { - logger.Error(err) - } - if eh != nil { - eh(m, err) - } - return - } - if err := handler(m); err != nil { - if logger.V(logger.ErrorLevel, logger.DefaultLogger) { - logger.Error(err) - } - if eh != nil { - eh(m, err) - } - } - } - - var sub *nats.Subscription - var err error - - n.RLock() - if len(opt.Queue) > 0 { - sub, err = n.conn.QueueSubscribe(topic, opt.Queue, fn) - } else { - sub, err = n.conn.Subscribe(topic, fn) - } - n.RUnlock() - if err != nil { - return nil, err - } - return &subscriber{s: sub, opts: opt}, nil -} - -func (n *natsBroker) String() string { - return "nats" -} - -func (n *natsBroker) setOption(opts ...broker.Option) { - for _, o := range opts { - o(&n.opts) - } - - n.Once.Do(func() { - n.nopts = nats.GetDefaultOptions() - }) - - if nopts, ok := n.opts.Context.Value(optionsKey{}).(nats.Options); ok { - n.nopts = nopts - } - - // broker.Options have higher priority than nats.Options - // only if Addrs, Secure or TLSConfig were not set through a broker.Option - // we read them from nats.Option - if len(n.opts.Addrs) == 0 { - n.opts.Addrs = n.nopts.Servers - } - - if !n.opts.Secure { - n.opts.Secure = n.nopts.Secure - } - - if n.opts.TLSConfig == nil { - n.opts.TLSConfig = n.nopts.TLSConfig - } - n.addrs = n.setAddrs(n.opts.Addrs) - - if n.opts.Context.Value(drainConnectionKey{}) != nil { - n.drain = true - n.closeCh = make(chan error) - n.nopts.ClosedCB = n.onClose - n.nopts.AsyncErrorCB = n.onAsyncError - n.nopts.DisconnectedErrCB = n.onDisconnectedError - } -} - -func (n *natsBroker) onClose(conn *nats.Conn) { - n.closeCh <- nil -} - -func (n *natsBroker) onAsyncError(conn *nats.Conn, sub *nats.Subscription, err error) { - // There are kinds of different async error nats might callback, but we are interested - // in ErrDrainTimeout only here. - if err == nats.ErrDrainTimeout { - n.closeCh <- err - } -} - -func (n *natsBroker) onDisconnectedError(conn *nats.Conn, err error) { - n.closeCh <- err -} - -func NewBroker(opts ...broker.Option) broker.Broker { - options := broker.Options{ - // Default codec - Codec: json.Marshaler{}, - Context: context.Background(), - Registry: mdns.NewRegistry(), - } - - n := &natsBroker{ - opts: options, - } - n.setOption(opts...) - - return n -} diff --git a/broker/nats/nats_test.go b/broker/nats/nats_test.go deleted file mode 100644 index 2c3f0f0d..00000000 --- a/broker/nats/nats_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package nats - -import ( - "fmt" - "testing" - - "github.com/micro/go-micro/v3/broker" - nats "github.com/nats-io/nats.go" -) - -var addrTestCases = []struct { - name string - description string - addrs map[string]string // expected address : set address -}{ - { - "brokerOpts", - "set broker addresses through a broker.Option in constructor", - map[string]string{ - "nats://192.168.10.1:5222": "192.168.10.1:5222", - "nats://10.20.10.0:4222": "10.20.10.0:4222"}, - }, - { - "brokerInit", - "set broker addresses through a broker.Option in broker.Init()", - map[string]string{ - "nats://192.168.10.1:5222": "192.168.10.1:5222", - "nats://10.20.10.0:4222": "10.20.10.0:4222"}, - }, - { - "natsOpts", - "set broker addresses through the nats.Option in constructor", - map[string]string{ - "nats://192.168.10.1:5222": "192.168.10.1:5222", - "nats://10.20.10.0:4222": "10.20.10.0:4222"}, - }, - { - "default", - "check if default Address is set correctly", - map[string]string{ - "nats://127.0.0.1:4222": "", - }, - }, -} - -// TestInitAddrs tests issue #100. Ensures that if the addrs is set by an option in init it will be used. -func TestInitAddrs(t *testing.T) { - - for _, tc := range addrTestCases { - t.Run(fmt.Sprintf("%s: %s", tc.name, tc.description), func(t *testing.T) { - - var br broker.Broker - var addrs []string - - for _, addr := range tc.addrs { - addrs = append(addrs, addr) - } - - switch tc.name { - case "brokerOpts": - // we know that there are just two addrs in the dict - br = NewBroker(broker.Addrs(addrs[0], addrs[1])) - br.Init() - case "brokerInit": - br = NewBroker() - // we know that there are just two addrs in the dict - br.Init(broker.Addrs(addrs[0], addrs[1])) - case "natsOpts": - nopts := nats.GetDefaultOptions() - nopts.Servers = addrs - br = NewBroker(Options(nopts)) - br.Init() - case "default": - br = NewBroker() - br.Init() - } - - natsBroker, ok := br.(*natsBroker) - if !ok { - t.Fatal("Expected broker to be of types *natsBroker") - } - // check if the same amount of addrs we set has actually been set, default - // have only 1 address nats://127.0.0.1:4222 (current nats code) or - // nats://localhost:4222 (older code version) - if len(natsBroker.addrs) != len(tc.addrs) && tc.name != "default" { - t.Errorf("Expected Addr count = %d, Actual Addr count = %d", - len(natsBroker.addrs), len(tc.addrs)) - } - - for _, addr := range natsBroker.addrs { - _, ok := tc.addrs[addr] - if !ok { - t.Errorf("Expected '%s' has not been set", addr) - } - } - }) - } -} diff --git a/broker/nats/options.go b/broker/nats/options.go deleted file mode 100644 index debd7e65..00000000 --- a/broker/nats/options.go +++ /dev/null @@ -1,19 +0,0 @@ -package nats - -import ( - "github.com/micro/go-micro/v3/broker" - nats "github.com/nats-io/nats.go" -) - -type optionsKey struct{} -type drainConnectionKey struct{} - -// Options accepts nats.Options -func Options(opts nats.Options) broker.Option { - return setBrokerOption(optionsKey{}, opts) -} - -// DrainConnection will drain subscription on close -func DrainConnection() broker.Option { - return setBrokerOption(drainConnectionKey{}, struct{}{}) -} diff --git a/config/source/etcd/README.md b/config/source/etcd/README.md deleted file mode 100644 index a3025ad4..00000000 --- a/config/source/etcd/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Etcd Source - -The etcd source reads config from etcd key/values - -This source supports etcd version 3 and beyond. - -## Etcd Format - -The etcd source expects keys under the default prefix `/micro/config` (prefix can be changed) - -Values are expected to be JSON - -``` -// set database -etcdctl put /micro/config/database '{"address": "10.0.0.1", "port": 3306}' -// set cache -etcdctl put /micro/config/cache '{"address": "10.0.0.2", "port": 6379}' -``` - -Keys are split on `/` so access becomes - -``` -conf.Get("micro", "config", "database") -``` - -## New Source - -Specify source with data - -```go -etcdSource := etcd.NewSource( - // optionally specify etcd address; default to localhost:8500 - etcd.WithAddress("10.0.0.10:8500"), - // optionally specify prefix; defaults to /micro/config - etcd.WithPrefix("/my/prefix"), - // optionally strip the provided prefix from the keys, defaults to false - etcd.StripPrefix(true), -) -``` - -## Load Source - -Load the source into config - -```go -// Create new config -conf := config.NewConfig() - -// Load file source -conf.Load(etcdSource) -``` diff --git a/config/source/etcd/etcd.go b/config/source/etcd/etcd.go deleted file mode 100644 index 08ae4e0c..00000000 --- a/config/source/etcd/etcd.go +++ /dev/null @@ -1,145 +0,0 @@ -package etcd - -import ( - "context" - "fmt" - "net" - "time" - - cetcd "github.com/coreos/etcd/clientv3" - "github.com/coreos/etcd/mvcc/mvccpb" - "github.com/micro/go-micro/v3/config/source" -) - -// Currently a single etcd reader -type etcd struct { - prefix string - stripPrefix string - opts source.Options - client *cetcd.Client - cerr error -} - -var ( - DefaultPrefix = "/micro/config/" -) - -func (c *etcd) Read() (*source.ChangeSet, error) { - if c.cerr != nil { - return nil, c.cerr - } - - rsp, err := c.client.Get(context.Background(), c.prefix, cetcd.WithPrefix()) - if err != nil { - return nil, err - } - - if rsp == nil || len(rsp.Kvs) == 0 { - return nil, fmt.Errorf("source not found: %s", c.prefix) - } - - kvs := make([]*mvccpb.KeyValue, 0, len(rsp.Kvs)) - for _, v := range rsp.Kvs { - kvs = append(kvs, (*mvccpb.KeyValue)(v)) - } - - data := makeMap(c.opts.Encoder, kvs, c.stripPrefix) - - b, err := c.opts.Encoder.Encode(data) - if err != nil { - return nil, fmt.Errorf("error reading source: %v", err) - } - - cs := &source.ChangeSet{ - Timestamp: time.Now(), - Source: c.String(), - Data: b, - Format: c.opts.Encoder.String(), - } - cs.Checksum = cs.Sum() - - return cs, nil -} - -func (c *etcd) String() string { - return "etcd" -} - -func (c *etcd) Watch() (source.Watcher, error) { - if c.cerr != nil { - return nil, c.cerr - } - cs, err := c.Read() - if err != nil { - return nil, err - } - return newWatcher(c.prefix, c.stripPrefix, c.client.Watcher, cs, c.opts) -} - -func (c *etcd) Write(cs *source.ChangeSet) error { - return nil -} - -func NewSource(opts ...source.Option) source.Source { - options := source.NewOptions(opts...) - - var endpoints []string - - // check if there are any addrs - addrs, ok := options.Context.Value(addressKey{}).([]string) - if ok { - for _, a := range addrs { - addr, port, err := net.SplitHostPort(a) - if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { - port = "2379" - addr = a - endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port)) - } else if err == nil { - endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port)) - } - } - } - - if len(endpoints) == 0 { - endpoints = []string{"localhost:2379"} - } - - // check dial timeout option - dialTimeout, ok := options.Context.Value(dialTimeoutKey{}).(time.Duration) - if !ok { - dialTimeout = 3 * time.Second // default dial timeout - } - - config := cetcd.Config{ - Endpoints: endpoints, - DialTimeout: dialTimeout, - } - - u, ok := options.Context.Value(authKey{}).(*authCreds) - if ok { - config.Username = u.Username - config.Password = u.Password - } - - // use default config - client, err := cetcd.New(config) - - prefix := DefaultPrefix - sp := "" - f, ok := options.Context.Value(prefixKey{}).(string) - if ok { - prefix = f - } - - if b, ok := options.Context.Value(stripPrefixKey{}).(bool); ok && b { - sp = prefix - } - - return &etcd{ - prefix: prefix, - stripPrefix: sp, - opts: options, - client: client, - cerr: err, - } -} diff --git a/config/source/etcd/options.go b/config/source/etcd/options.go deleted file mode 100644 index 3d2c1e69..00000000 --- a/config/source/etcd/options.go +++ /dev/null @@ -1,70 +0,0 @@ -package etcd - -import ( - "context" - "time" - - "github.com/micro/go-micro/v3/config/source" -) - -type addressKey struct{} -type prefixKey struct{} -type stripPrefixKey struct{} -type authKey struct{} -type dialTimeoutKey struct{} - -type authCreds struct { - Username string - Password string -} - -// WithAddress sets the etcd address -func WithAddress(a ...string) source.Option { - return func(o *source.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, addressKey{}, a) - } -} - -// WithPrefix sets the key prefix to use -func WithPrefix(p string) source.Option { - return func(o *source.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, prefixKey{}, p) - } -} - -// StripPrefix indicates whether to remove the prefix from config entries, or leave it in place. -func StripPrefix(strip bool) source.Option { - return func(o *source.Options) { - if o.Context == nil { - o.Context = context.Background() - } - - o.Context = context.WithValue(o.Context, stripPrefixKey{}, strip) - } -} - -// Auth allows you to specify username/password -func Auth(username, password string) source.Option { - return func(o *source.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, authKey{}, &authCreds{Username: username, Password: password}) - } -} - -// WithDialTimeout set the time out for dialing to etcd -func WithDialTimeout(timeout time.Duration) source.Option { - return func(o *source.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, dialTimeoutKey{}, timeout) - } -} diff --git a/config/source/etcd/util.go b/config/source/etcd/util.go deleted file mode 100644 index e495b64c..00000000 --- a/config/source/etcd/util.go +++ /dev/null @@ -1,89 +0,0 @@ -package etcd - -import ( - "strings" - - "github.com/coreos/etcd/clientv3" - "github.com/coreos/etcd/mvcc/mvccpb" - "github.com/micro/go-micro/v3/config/encoder" -) - -func makeEvMap(e encoder.Encoder, data map[string]interface{}, kv []*clientv3.Event, stripPrefix string) map[string]interface{} { - if data == nil { - data = make(map[string]interface{}) - } - - for _, v := range kv { - switch mvccpb.Event_EventType(v.Type) { - case mvccpb.DELETE: - data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "delete", stripPrefix) - default: - data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "insert", stripPrefix) - } - } - - return data -} - -func makeMap(e encoder.Encoder, kv []*mvccpb.KeyValue, stripPrefix string) map[string]interface{} { - data := make(map[string]interface{}) - - for _, v := range kv { - data = update(e, data, v, "put", stripPrefix) - } - - return data -} - -func update(e encoder.Encoder, data map[string]interface{}, v *mvccpb.KeyValue, action, stripPrefix string) map[string]interface{} { - // remove prefix if non empty, and ensure leading / is removed as well - vkey := strings.TrimPrefix(strings.TrimPrefix(string(v.Key), stripPrefix), "/") - // split on prefix - haveSplit := strings.Contains(vkey, "/") - keys := strings.Split(vkey, "/") - - var vals interface{} - e.Decode(v.Value, &vals) - - if !haveSplit && len(keys) == 1 { - switch action { - case "delete": - data = make(map[string]interface{}) - default: - v, ok := vals.(map[string]interface{}) - if ok { - data = v - } - } - return data - } - - // set data for first iteration - kvals := data - // iterate the keys and make maps - for i, k := range keys { - kval, ok := kvals[k].(map[string]interface{}) - if !ok { - // create next map - kval = make(map[string]interface{}) - // set it - kvals[k] = kval - } - - // last key: write vals - if l := len(keys) - 1; i == l { - switch action { - case "delete": - delete(kvals, k) - default: - kvals[k] = vals - } - break - } - - // set kvals for next iterator - kvals = kval - } - - return data -} diff --git a/config/source/etcd/watcher.go b/config/source/etcd/watcher.go deleted file mode 100644 index 0d4fbf8b..00000000 --- a/config/source/etcd/watcher.go +++ /dev/null @@ -1,113 +0,0 @@ -package etcd - -import ( - "context" - "errors" - "sync" - "time" - - cetcd "github.com/coreos/etcd/clientv3" - "github.com/micro/go-micro/v3/config/source" -) - -type watcher struct { - opts source.Options - name string - stripPrefix string - - sync.RWMutex - cs *source.ChangeSet - - ch chan *source.ChangeSet - exit chan bool -} - -func newWatcher(key, strip string, wc cetcd.Watcher, cs *source.ChangeSet, opts source.Options) (source.Watcher, error) { - w := &watcher{ - opts: opts, - name: "etcd", - stripPrefix: strip, - cs: cs, - ch: make(chan *source.ChangeSet), - exit: make(chan bool), - } - - ch := wc.Watch(context.Background(), key, cetcd.WithPrefix()) - - go w.run(wc, ch) - - return w, nil -} - -func (w *watcher) handle(evs []*cetcd.Event) { - w.RLock() - data := w.cs.Data - w.RUnlock() - - var vals map[string]interface{} - - // unpackage existing changeset - if err := w.opts.Encoder.Decode(data, &vals); err != nil { - return - } - - // update base changeset - d := makeEvMap(w.opts.Encoder, vals, evs, w.stripPrefix) - - // pack the changeset - b, err := w.opts.Encoder.Encode(d) - if err != nil { - return - } - - // create new changeset - cs := &source.ChangeSet{ - Timestamp: time.Now(), - Source: w.name, - Data: b, - Format: w.opts.Encoder.String(), - } - cs.Checksum = cs.Sum() - - // set base change set - w.Lock() - w.cs = cs - w.Unlock() - - // send update - w.ch <- cs -} - -func (w *watcher) run(wc cetcd.Watcher, ch cetcd.WatchChan) { - for { - select { - case rsp, ok := <-ch: - if !ok { - return - } - w.handle(rsp.Events) - case <-w.exit: - wc.Close() - return - } - } -} - -func (w *watcher) Next() (*source.ChangeSet, error) { - select { - case cs := <-w.ch: - return cs, nil - case <-w.exit: - return nil, errors.New("watcher stopped") - } -} - -func (w *watcher) Stop() error { - select { - case <-w.exit: - return nil - default: - close(w.exit) - } - return nil -} diff --git a/events/stream/nats/nats.go b/events/stream/nats/nats.go deleted file mode 100644 index 6646ed02..00000000 --- a/events/stream/nats/nats.go +++ /dev/null @@ -1,190 +0,0 @@ -package nats - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/google/uuid" - "github.com/nats-io/nats.go" - stan "github.com/nats-io/stan.go" - "github.com/pkg/errors" - - "github.com/micro/go-micro/v3/events" - "github.com/micro/go-micro/v3/logger" -) - -const ( - defaultClusterID = "micro" -) - -// NewStream returns an initialized nats stream or an error if the connection to the nats -// server could not be established -func NewStream(opts ...Option) (events.Stream, error) { - // parse the options - options := Options{ - ClientID: uuid.New().String(), - ClusterID: defaultClusterID, - } - for _, o := range opts { - o(&options) - } - - // connect to nats - nopts := nats.GetDefaultOptions() - if options.TLSConfig != nil { - nopts.Secure = true - nopts.TLSConfig = options.TLSConfig - } - if len(options.Address) > 0 { - nopts.Servers = []string{options.Address} - } - conn, err := nopts.Connect() - if err != nil { - return nil, fmt.Errorf("Error connecting to nats at %v with tls enabled (%v): %v", options.Address, nopts.TLSConfig != nil, err) - } - - // connect to the cluster - clusterConn, err := stan.Connect(options.ClusterID, options.ClientID, stan.NatsConn(conn)) - if err != nil { - return nil, fmt.Errorf("Error connecting to nats cluster %v: %v", options.ClusterID, err) - } - - return &stream{clusterConn}, nil -} - -type stream struct { - conn stan.Conn -} - -// Publish a message to a topic -func (s *stream) Publish(topic string, msg interface{}, opts ...events.PublishOption) error { - // validate the topic - if len(topic) == 0 { - return events.ErrMissingTopic - } - - // parse the options - options := events.PublishOptions{ - Timestamp: time.Now(), - } - for _, o := range opts { - o(&options) - } - - // encode the message if it's not already encoded - var payload []byte - if p, ok := msg.([]byte); ok { - payload = p - } else { - p, err := json.Marshal(msg) - if err != nil { - return events.ErrEncodingMessage - } - payload = p - } - - // construct the event - event := &events.Event{ - ID: uuid.New().String(), - Topic: topic, - Timestamp: options.Timestamp, - Metadata: options.Metadata, - Payload: payload, - } - - // serialize the event to bytes - bytes, err := json.Marshal(event) - if err != nil { - return errors.Wrap(err, "Error encoding event") - } - - // publish the event to the topic's channel - if _, err := s.conn.PublishAsync(event.Topic, bytes, nil); err != nil { - return errors.Wrap(err, "Error publishing message to topic") - } - - return nil -} - -// Subscribe to a topic -func (s *stream) Subscribe(topic string, opts ...events.SubscribeOption) (<-chan events.Event, error) { - // validate the topic - if len(topic) == 0 { - return nil, events.ErrMissingTopic - } - - // parse the options - options := events.SubscribeOptions{ - Queue: uuid.New().String(), - AutoAck: true, - } - for _, o := range opts { - o(&options) - } - - // setup the subscriber - c := make(chan events.Event) - handleMsg := func(m *stan.Msg) { - // poison message handling - if options.GetRetryLimit() > -1 && m.Redelivered && int(m.RedeliveryCount) > options.GetRetryLimit() { - if logger.V(logger.ErrorLevel, logger.DefaultLogger) { - logger.Errorf("Message retry limit reached, discarding: %v", m.Sequence) - } - m.Ack() // ignoring error - return - } - - // decode the message - var evt events.Event - if err := json.Unmarshal(m.Data, &evt); err != nil { - if logger.V(logger.ErrorLevel, logger.DefaultLogger) { - logger.Errorf("Error decoding message: %v", err) - } - // not acknowledging the message is the way to indicate an error occurred - return - } - - if !options.AutoAck { - // set up the ack funcs - evt.SetAckFunc(func() error { - return m.Ack() - }) - evt.SetNackFunc(func() error { - // noop. not acknowledging the message is the way to indicate an error occurred - // we have to wait for the ack wait to kick in before the message is resent - return nil - }) - } - - // push onto the channel and wait for the consumer to take the event off before we acknowledge it. - c <- evt - - if !options.AutoAck { - return - } - if err := m.Ack(); err != nil && logger.V(logger.ErrorLevel, logger.DefaultLogger) { - logger.Errorf("Error acknowledging message: %v", err) - } - } - - // setup the options - subOpts := []stan.SubscriptionOption{ - stan.DurableName(topic), - stan.SetManualAckMode(), - } - if options.StartAtTime.Unix() > 0 { - subOpts = append(subOpts, stan.StartAtTime(options.StartAtTime)) - } - if options.AckWait > 0 { - subOpts = append(subOpts, stan.AckWait(options.AckWait)) - } - - // connect the subscriber - _, err := s.conn.QueueSubscribe(topic, options.Queue, handleMsg, subOpts...) - if err != nil { - return nil, errors.Wrap(err, "Error subscribing to topic") - } - - return c, nil -} diff --git a/events/stream/nats/nats_test.go b/events/stream/nats/nats_test.go deleted file mode 100644 index f079b586..00000000 --- a/events/stream/nats/nats_test.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build nats - -package nats diff --git a/events/stream/nats/options.go b/events/stream/nats/options.go deleted file mode 100644 index a4781734..00000000 --- a/events/stream/nats/options.go +++ /dev/null @@ -1,42 +0,0 @@ -package nats - -import "crypto/tls" - -// Options which are used to configure the nats stream -type Options struct { - ClusterID string - ClientID string - Address string - TLSConfig *tls.Config -} - -// Option is a function which configures options -type Option func(o *Options) - -// ClusterID sets the cluster id for the nats connection -func ClusterID(id string) Option { - return func(o *Options) { - o.ClusterID = id - } -} - -// ClientID sets the client id for the nats connection -func ClientID(id string) Option { - return func(o *Options) { - o.ClientID = id - } -} - -// Address of the nats cluster -func Address(addr string) Option { - return func(o *Options) { - o.Address = addr - } -} - -// TLSConfig to use when connecting to the cluster -func TLSConfig(t *tls.Config) Option { - return func(o *Options) { - o.TLSConfig = t - } -} diff --git a/events/stream/test/stream_test.go b/events/stream/test/stream_test.go index 0186ccc4..68528bc1 100644 --- a/events/stream/test/stream_test.go +++ b/events/stream/test/stream_test.go @@ -9,7 +9,6 @@ import ( "github.com/micro/go-micro/v3/events" "github.com/micro/go-micro/v3/events/stream/memory" - "github.com/micro/go-micro/v3/events/stream/nats" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -27,13 +26,7 @@ type testCase struct { func TestStream(t *testing.T) { tcs := []testCase{} - // NATS specific setup - stream, err := nats.NewStream(nats.ClusterID("test-cluster")) - assert.Nilf(t, err, "NewStream should not return an error") - assert.NotNilf(t, stream, "NewStream should return a stream object") - tcs = append(tcs, testCase{str: stream, name: "nats"}) - - stream, err = memory.NewStream() + stream, err := memory.NewStream() assert.Nilf(t, err, "NewStream should not return an error") assert.NotNilf(t, stream, "NewStream should return a stream object") tcs = append(tcs, testCase{str: stream, name: "memory"}) diff --git a/go.mod b/go.mod index 78ccda11..01024123 100644 --- a/go.mod +++ b/go.mod @@ -10,11 +10,6 @@ require ( github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/caddyserver/certmagic v0.10.6 - github.com/coreos/bbolt v1.3.3 // indirect - github.com/coreos/etcd v3.3.18+incompatible - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect - github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1 @@ -26,49 +21,31 @@ require ( github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee github.com/gobwas/pool v0.2.0 // indirect github.com/gobwas/ws v1.0.3 - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/gogo/protobuf v1.3.1 // indirect github.com/golang/protobuf v1.4.2 github.com/google/uuid v1.1.1 github.com/gorilla/handlers v1.4.2 - github.com/gorilla/websocket v1.4.1 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.9.5 // indirect github.com/hashicorp/hcl v1.0.0 github.com/hpcloud/tail v1.0.0 github.com/imdario/mergo v0.3.9 - github.com/jonboulle/clockwork v0.1.0 // indirect github.com/kr/pretty v0.2.0 github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.7.0 github.com/miekg/dns v1.1.27 - github.com/mitchellh/hashstructure v1.0.0 - github.com/nats-io/nats-streaming-server v0.18.0 // indirect - github.com/nats-io/nats.go v1.10.0 - github.com/nats-io/stan.go v0.7.0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.7.0 - github.com/soheilhy/cmux v0.1.4 // indirect github.com/stretchr/testify v1.5.1 github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf - github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc // indirect github.com/xanzy/go-gitlab v0.35.1 - github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect go.etcd.io/bbolt v1.3.5 - go.uber.org/zap v1.13.0 golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 golang.org/x/net v0.0.0-20200707034311-ab3426394381 - golang.org/x/tools v0.0.0-20200117065230-39095c1d176c // indirect + golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/grpc v1.27.0 google.golang.org/protobuf v1.25.0 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/square/go-jose.v2 v2.4.1 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect - sigs.k8s.io/yaml v1.1.0 // indirect ) - -replace google.golang.org/grpc => google.golang.org/grpc v1.26.0 diff --git a/go.sum b/go.sum index e3180739..6c7177f5 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= @@ -29,7 +30,6 @@ github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvd github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c h1:YMP6olTU903X3gxQJckdmiP8/zkSMq4kN3uipsU9XjU= @@ -39,14 +39,10 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -58,7 +54,6 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/caddyserver/certmagic v0.10.6 h1:sCya6FmfaN74oZE46kqfaFOVoROD/mF36rTQfjN7TZc= @@ -67,10 +62,7 @@ github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6R github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= @@ -83,17 +75,7 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= -github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.18+incompatible h1:Zz1aXgDrFFi1nadh58tA9ktt06cmPTwNNP3dXwIq1lE= -github.com/coreos/etcd v3.3.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -139,11 +121,8 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -162,8 +141,6 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= @@ -209,43 +186,22 @@ github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YAR github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.1 h1:9PZfAcVEvez4yhLH2TBU64/h/z4xlFI80cWXRrxuKuM= -github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/raft v1.1.2 h1:oxEL5DDeurYxLd3UbcY/hccgSPhLLpiBZ1YxtWEq59c= -github.com/hashicorp/raft v1.1.2/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= -github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= @@ -253,13 +209,9 @@ github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -282,8 +234,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= -github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= -github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -297,8 +247,6 @@ github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM= github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= -github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= -github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -310,21 +258,6 @@ github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8d github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= -github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.7 h1:jCoQwDvRYJy3OpOTHeYfvIPLP46BMeDmH7XEJg/r42I= -github.com/nats-io/nats-server/v2 v2.1.7/go.mod h1:rbRrRE/Iv93O/rUvZ9dh4NfT0Cm9HWjW/BqOWLGgYiE= -github.com/nats-io/nats-streaming-server v0.18.0 h1:+RDozeN9scwCm0Wc2fYlvGcP144hvxvSOtxZ8FE21ME= -github.com/nats-io/nats-streaming-server v0.18.0/go.mod h1:Y9Aiif2oANuoKazQrs4wXtF3jqt6p97ODQg68lR5TnY= -github.com/nats-io/nats.go v1.10.0 h1:L8qnKaofSfNFbXg0C5F71LdjPRnmQwSsA4ukmkt1TvY= -github.com/nats-io/nats.go v1.10.0/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.4 h1:aEsHIssIk6ETN5m2/MD8Y4B2X7FfXrBAUdkyRvbVYzA= -github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= -github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nats-io/stan.go v0.7.0 h1:sMVHD9RkxPOl6PJfDVBQd+gbxWkApeYl6GrH+10msO4= -github.com/nats-io/stan.go v0.7.0/go.mod h1:Ci6mUIpGQTjl++MqK2XzkWI/0vF+Bl72uScx7ejSYmU= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -346,14 +279,11 @@ github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -364,33 +294,21 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= -github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -406,8 +324,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -419,10 +335,7 @@ github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -433,8 +346,6 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -442,18 +353,7 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -461,11 +361,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -476,12 +374,12 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= @@ -495,7 +393,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -526,6 +423,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -540,7 +438,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -548,7 +445,6 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= @@ -563,8 +459,10 @@ golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -579,13 +477,9 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117065230-39095c1d176c h1:FodBYPZKH5tAN2O60HlglMwXGAeV/4k+NKbli79M/2c= -golang.org/x/tools v0.0.0-20200117065230-39095c1d176c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -613,8 +507,17 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -628,7 +531,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -648,12 +550,11 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -662,5 +563,3 @@ honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXe honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/metrics/prometheus/README.md b/metrics/prometheus/README.md deleted file mode 100644 index b950aa19..00000000 --- a/metrics/prometheus/README.md +++ /dev/null @@ -1,26 +0,0 @@ -Prometheus -========== - -A Prometheus "pull" based implementation of the metrics Reporter interface. - - -Capabilities ------------- - -* Go runtime metrics are handled natively by the Prometheus client library (CPU / MEM / GC / GoRoutines etc). -* User-defined metrics are registered in the Prometheus client dynamically (they must be pre-registered, hence all of the faffing around in metric_family.go). -* The metrics are made available on a Prometheus-compatible HTTP endpoint, which can be scraped at any time. This means that the user can very easily access stats even running locally as a standalone binary. -* Requires a micro.Server parameter (from which it gathers the service name and version). These are included as tags with every metric. - - -Usage ------ - -```golang - prometheusReporter := metrics.New(server) - tags := metrics.Tags{"greeter": "Janos"} - err := prometheusReporter.Count("hellos", 1, tags) - if err != nil { - fmt.Printf("Error setting a Count metric: %v", err) - } -``` diff --git a/metrics/prometheus/metric_family.go b/metrics/prometheus/metric_family.go deleted file mode 100644 index e8f0b1f1..00000000 --- a/metrics/prometheus/metric_family.go +++ /dev/null @@ -1,118 +0,0 @@ -package prometheus - -import ( - "sync" - - "github.com/prometheus/client_golang/prometheus" -) - -// metricFamily stores our cached metrics: -type metricFamily struct { - counters map[string]*prometheus.CounterVec - gauges map[string]*prometheus.GaugeVec - timings map[string]*prometheus.SummaryVec - defaultLabels prometheus.Labels - mutex sync.Mutex - prometheusRegistry *prometheus.Registry - timingObjectives map[float64]float64 -} - -// newMetricFamily returns a new metricFamily (useful in case we want to change the structure later): -func (r *Reporter) newMetricFamily() metricFamily { - - // Take quantile thresholds from our pre-defined list: - timingObjectives := make(map[float64]float64) - for _, percentile := range r.options.Percentiles { - if quantileThreshold, ok := quantileThresholds[percentile]; ok { - timingObjectives[percentile] = quantileThreshold - } - } - - return metricFamily{ - counters: make(map[string]*prometheus.CounterVec), - gauges: make(map[string]*prometheus.GaugeVec), - timings: make(map[string]*prometheus.SummaryVec), - defaultLabels: r.convertTags(r.options.DefaultTags), - prometheusRegistry: r.prometheusRegistry, - timingObjectives: timingObjectives, - } -} - -// getCounter either gets a counter, or makes a new one: -func (mf *metricFamily) getCounter(name string, labelNames []string) *prometheus.CounterVec { - mf.mutex.Lock() - defer mf.mutex.Unlock() - - // See if we already have this counter: - counter, ok := mf.counters[name] - if !ok { - - // Make a new counter: - counter = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: name, - ConstLabels: mf.defaultLabels, - }, - labelNames, - ) - - // Register it and add it to our list: - mf.prometheusRegistry.MustRegister(counter) - mf.counters[name] = counter - } - - return counter -} - -// getGauge either gets a gauge, or makes a new one: -func (mf *metricFamily) getGauge(name string, labelNames []string) *prometheus.GaugeVec { - mf.mutex.Lock() - defer mf.mutex.Unlock() - - // See if we already have this gauge: - gauge, ok := mf.gauges[name] - if !ok { - - // Make a new gauge: - gauge = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: name, - ConstLabels: mf.defaultLabels, - }, - labelNames, - ) - - // Register it and add it to our list: - mf.prometheusRegistry.MustRegister(gauge) - mf.gauges[name] = gauge - } - - return gauge -} - -// getTiming either gets a timing, or makes a new one: -func (mf *metricFamily) getTiming(name string, labelNames []string) *prometheus.SummaryVec { - mf.mutex.Lock() - defer mf.mutex.Unlock() - - // See if we already have this timing: - timing, ok := mf.timings[name] - if !ok { - - // Make a new timing: - timing = prometheus.NewSummaryVec( - prometheus.SummaryOpts{ - Name: name, - ConstLabels: mf.defaultLabels, - Objectives: mf.timingObjectives, - }, - labelNames, - ) - - // Register it and add it to our list: - mf.prometheusRegistry.MustRegister(timing) - mf.timings[name] = timing - } - - return timing -} diff --git a/metrics/prometheus/metrics.go b/metrics/prometheus/metrics.go deleted file mode 100644 index 32af323b..00000000 --- a/metrics/prometheus/metrics.go +++ /dev/null @@ -1,68 +0,0 @@ -package prometheus - -import ( - "errors" - "time" - - "github.com/micro/go-micro/v3/metrics" -) - -// ErrPrometheusPanic is a catch-all for the panics which can be thrown by the Prometheus client: -var ErrPrometheusPanic = errors.New("The Prometheus client panicked. Did you do something like change the tag cardinality or the type of a metric?") - -// Count is a counter with key/value tags: -// New values are added to any previous one (eg "number of hits") -func (r *Reporter) Count(name string, value int64, tags metrics.Tags) (err error) { - defer func() { - if r := recover(); r != nil { - err = ErrPrometheusPanic - } - }() - - counter := r.metrics.getCounter(r.stripUnsupportedCharacters(name), r.listTagKeys(tags)) - metric, err := counter.GetMetricWith(r.convertTags(tags)) - if err != nil { - return err - } - - metric.Add(float64(value)) - return err -} - -// Gauge is a register with key/value tags: -// New values simply override any previous one (eg "current connections") -func (r *Reporter) Gauge(name string, value float64, tags metrics.Tags) (err error) { - defer func() { - if r := recover(); r != nil { - err = ErrPrometheusPanic - } - }() - - gauge := r.metrics.getGauge(r.stripUnsupportedCharacters(name), r.listTagKeys(tags)) - metric, err := gauge.GetMetricWith(r.convertTags(tags)) - if err != nil { - return err - } - - metric.Set(value) - return err -} - -// Timing is a histogram with key/valye tags: -// New values are added into a series of aggregations -func (r *Reporter) Timing(name string, value time.Duration, tags metrics.Tags) (err error) { - defer func() { - if r := recover(); r != nil { - err = ErrPrometheusPanic - } - }() - - timing := r.metrics.getTiming(r.stripUnsupportedCharacters(name), r.listTagKeys(tags)) - metric, err := timing.GetMetricWith(r.convertTags(tags)) - if err != nil { - return err - } - - metric.Observe(value.Seconds()) - return err -} diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go deleted file mode 100644 index eb2c4f8d..00000000 --- a/metrics/prometheus/reporter.go +++ /dev/null @@ -1,75 +0,0 @@ -package prometheus - -import ( - "net/http" - "strings" - - log "github.com/micro/go-micro/v3/logger" - "github.com/micro/go-micro/v3/metrics" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" -) - -var ( - // quantileThresholds maps quantiles / percentiles to error thresholds (required by the Prometheus client). - // Must be from our pre-defined set [0.0, 0.5, 0.75, 0.90, 0.95, 0.98, 0.99, 1]: - quantileThresholds = 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} -) - -// Reporter is an implementation of metrics.Reporter: -type Reporter struct { - options metrics.Options - prometheusRegistry *prometheus.Registry - metrics metricFamily -} - -// New returns a configured prometheus reporter: -func New(opts ...metrics.Option) (*Reporter, error) { - options := metrics.NewOptions(opts...) - - // Make a prometheus registry (this keeps track of any metrics we generate): - prometheusRegistry := prometheus.NewRegistry() - prometheusRegistry.Register(prometheus.NewGoCollector()) - prometheusRegistry.Register(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{Namespace: "goruntime"})) - - // Make a new Reporter: - newReporter := &Reporter{ - options: options, - prometheusRegistry: prometheusRegistry, - } - - // Add metrics families for each type: - newReporter.metrics = newReporter.newMetricFamily() - - // Handle the metrics endpoint with prometheus: - log.Infof("Metrics/Prometheus [http] Listening on %s%s", options.Address, options.Path) - http.Handle(options.Path, promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) - go http.ListenAndServe(options.Address, nil) - - return newReporter, nil -} - -// convertTags turns Tags into prometheus labels: -func (r *Reporter) convertTags(tags metrics.Tags) prometheus.Labels { - labels := prometheus.Labels{} - for key, value := range tags { - labels[key] = r.stripUnsupportedCharacters(value) - } - return labels -} - -// listTagKeys returns a list of tag keys (we need to provide this to the Prometheus client): -func (r *Reporter) listTagKeys(tags metrics.Tags) (labelKeys []string) { - for key := range tags { - labelKeys = append(labelKeys, key) - } - return -} - -// stripUnsupportedCharacters cleans up a metrics key or value: -func (r *Reporter) stripUnsupportedCharacters(metricName string) string { - valueWithoutDots := strings.Replace(metricName, ".", "_", -1) - valueWithoutCommas := strings.Replace(valueWithoutDots, ",", "_", -1) - valueWIthoutSpaces := strings.Replace(valueWithoutCommas, " ", "", -1) - return valueWIthoutSpaces -} diff --git a/metrics/prometheus/reporter_test.go b/metrics/prometheus/reporter_test.go deleted file mode 100644 index 74b2f452..00000000 --- a/metrics/prometheus/reporter_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package prometheus - -import ( - "io/ioutil" - "net/http" - "testing" - "time" - - "github.com/micro/go-micro/v3/metrics" - - "github.com/stretchr/testify/assert" -) - -func TestPrometheusReporter(t *testing.T) { - - // Make a Reporter: - reporter, err := New(metrics.Address(":9999"), metrics.Path("/prometheus"), metrics.DefaultTags(map[string]string{"service": "prometheus-test"})) - assert.NoError(t, err) - assert.NotNil(t, reporter) - assert.Equal(t, "prometheus-test", reporter.options.DefaultTags["service"]) - assert.Equal(t, ":9999", reporter.options.Address) - assert.Equal(t, "/prometheus", reporter.options.Path) - - // Check that our implementation is valid: - assert.Implements(t, new(metrics.Reporter), reporter) - - // Test tag conversion: - tags := metrics.Tags{ - "tag1": "false", - "tag2": "true", - } - convertedTags := reporter.convertTags(tags) - assert.Equal(t, "false", convertedTags["tag1"]) - assert.Equal(t, "true", convertedTags["tag2"]) - - // Test tag enumeration: - listedTags := reporter.listTagKeys(tags) - assert.Contains(t, listedTags, "tag1") - assert.Contains(t, listedTags, "tag2") - - // Test string cleaning: - preparedMetricName := reporter.stripUnsupportedCharacters("some.kind,of tag") - assert.Equal(t, "some_kind_oftag", preparedMetricName) - - // Test MetricFamilies: - metricFamily := reporter.newMetricFamily() - - // Counters: - assert.NotNil(t, metricFamily.getCounter("testCounter", []string{"test", "counter"})) - assert.Len(t, metricFamily.counters, 1) - - // Gauges: - assert.NotNil(t, metricFamily.getGauge("testGauge", []string{"test", "gauge"})) - assert.Len(t, metricFamily.gauges, 1) - - // Timings: - assert.NotNil(t, metricFamily.getTiming("testTiming", []string{"test", "timing"})) - assert.Len(t, metricFamily.timings, 1) - - // Test submitting metrics through the interface methods: - assert.NoError(t, reporter.Count("test.counter.1", 6, tags)) - assert.NoError(t, reporter.Count("test.counter.2", 19, tags)) - assert.NoError(t, reporter.Count("test.counter.1", 5, tags)) - assert.NoError(t, reporter.Gauge("test.gauge.1", 99, tags)) - assert.NoError(t, reporter.Gauge("test.gauge.2", 55, tags)) - assert.NoError(t, reporter.Gauge("test.gauge.1", 98, tags)) - assert.NoError(t, reporter.Timing("test.timing.1", time.Second, tags)) - assert.NoError(t, reporter.Timing("test.timing.2", time.Minute, tags)) - assert.Len(t, reporter.metrics.counters, 2) - assert.Len(t, reporter.metrics.gauges, 2) - assert.Len(t, reporter.metrics.timings, 2) - - // Test reading back the metrics: - rsp, err := http.Get("http://localhost:9999/prometheus") - assert.NoError(t, err) - assert.Equal(t, http.StatusOK, rsp.StatusCode) - - // Read the response body and check for our metric: - bodyBytes, err := ioutil.ReadAll(rsp.Body) - assert.NoError(t, err) - - // Check for appropriately aggregated metrics: - assert.Contains(t, string(bodyBytes), `test_counter_1{service="prometheus-test",tag1="false",tag2="true"} 11`) - assert.Contains(t, string(bodyBytes), `test_counter_2{service="prometheus-test",tag1="false",tag2="true"} 19`) - assert.Contains(t, string(bodyBytes), `test_gauge_1{service="prometheus-test",tag1="false",tag2="true"} 98`) - assert.Contains(t, string(bodyBytes), `test_gauge_2{service="prometheus-test",tag1="false",tag2="true"} 55`) - assert.Contains(t, string(bodyBytes), `test_timing_1{service="prometheus-test",tag1="false",tag2="true",quantile="0"} 1`) - assert.Contains(t, string(bodyBytes), `test_timing_2{service="prometheus-test",tag1="false",tag2="true",quantile="0"} 60`) -} diff --git a/registry/etcd/etcd.go b/registry/etcd/etcd.go deleted file mode 100644 index 207a6a07..00000000 --- a/registry/etcd/etcd.go +++ /dev/null @@ -1,605 +0,0 @@ -// Package etcd provides an etcd service registry -package etcd - -import ( - "context" - "crypto/tls" - "encoding/json" - "errors" - "net" - "path" - "sort" - "strings" - "sync" - "time" - - "github.com/coreos/etcd/clientv3" - "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes" - "github.com/coreos/etcd/mvcc/mvccpb" - "github.com/micro/go-micro/v3/logger" - "github.com/micro/go-micro/v3/registry" - hash "github.com/mitchellh/hashstructure" - "go.uber.org/zap" -) - -const ( - prefix = "/micro/registry/" - defaultDomain = "micro" -) - -type etcdRegistry struct { - client *clientv3.Client - options registry.Options - - // register and leases are grouped by domain - sync.RWMutex - register map[string]register - leases map[string]leases -} - -type register map[string]uint64 -type leases map[string]clientv3.LeaseID - -// NewRegistry returns an initialized etcd registry -func NewRegistry(opts ...registry.Option) registry.Registry { - e := &etcdRegistry{ - options: registry.Options{}, - register: make(map[string]register), - leases: make(map[string]leases), - } - configure(e, opts...) - return e -} - -func newClient(e *etcdRegistry) (*clientv3.Client, error) { - config := clientv3.Config{ - Endpoints: []string{"127.0.0.1:2379"}, - } - - if e.options.Timeout == 0 { - e.options.Timeout = 5 * time.Second - } - - if e.options.Secure || e.options.TLSConfig != nil { - tlsConfig := e.options.TLSConfig - if tlsConfig == nil { - tlsConfig = &tls.Config{ - InsecureSkipVerify: true, - } - } - - config.TLS = tlsConfig - } - - if e.options.Context != nil { - u, ok := e.options.Context.Value(authKey{}).(*authCreds) - if ok { - config.Username = u.Username - config.Password = u.Password - } - cfg, ok := e.options.Context.Value(logConfigKey{}).(*zap.Config) - if ok && cfg != nil { - config.LogConfig = cfg - } - } - - var cAddrs []string - - for _, address := range e.options.Addrs { - if len(address) == 0 { - continue - } - addr, port, err := net.SplitHostPort(address) - if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { - port = "2379" - addr = address - cAddrs = append(cAddrs, net.JoinHostPort(addr, port)) - } else if err == nil { - cAddrs = append(cAddrs, net.JoinHostPort(addr, port)) - } - } - - // if we got addrs then we'll update - if len(cAddrs) > 0 { - config.Endpoints = cAddrs - } - - // check if the endpoints have https:// - if config.TLS != nil { - for i, ep := range config.Endpoints { - if !strings.HasPrefix(ep, "https://") { - config.Endpoints[i] = "https://" + ep - } - } - } - - cli, err := clientv3.New(config) - if err != nil { - return nil, err - } - - return cli, nil -} - -// configure will setup the registry with new options -func configure(e *etcdRegistry, opts ...registry.Option) error { - for _, o := range opts { - o(&e.options) - } - - // setup the client - cli, err := newClient(e) - if err != nil { - return err - } - - if e.client != nil { - e.client.Close() - } - - // setup new client - e.client = cli - - return nil -} - -// getName returns the domain and name -// it returns false if there's an issue -// the key is a path of /prefix/domain/name/id e.g /micro/registry/domain/service/uuid -func getName(key, prefix string) (string, string, bool) { - // strip the prefix from keys - key = strings.TrimPrefix(key, prefix) - - // split the key so we remove domain - parts := strings.Split(key, "/") - - if len(parts) == 0 { - return "", "", false - } - - if len(parts[0]) == 0 { - parts = parts[1:] - } - - // we expect a domain and then name domain/service - if len(parts) < 2 { - return "", "", false - } - - // return name, domain - return parts[0], parts[1], true -} - -func encode(s *registry.Service) string { - b, _ := json.Marshal(s) - return string(b) -} - -func decode(ds []byte) *registry.Service { - var s *registry.Service - json.Unmarshal(ds, &s) - return s -} - -func nodePath(domain, s, id string) string { - service := strings.Replace(s, "/", "-", -1) - node := strings.Replace(id, "/", "-", -1) - return path.Join(prefixWithDomain(domain), service, node) -} - -func servicePath(domain, s string) string { - return path.Join(prefixWithDomain(domain), serializeServiceName(s)) -} - -func serializeServiceName(s string) string { - return strings.ReplaceAll(s, "/", "-") -} - -func prefixWithDomain(domain string) string { - return path.Join(prefix, domain) -} - -func (e *etcdRegistry) Init(opts ...registry.Option) error { - return configure(e, opts...) -} - -func (e *etcdRegistry) Options() registry.Options { - return e.options -} - -func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, opts ...registry.RegisterOption) error { - if len(s.Nodes) == 0 { - return errors.New("Require at least one node") - } - - // parse the options - var options registry.RegisterOptions - for _, o := range opts { - o(&options) - } - if len(options.Domain) == 0 { - options.Domain = defaultDomain - } - - if s.Metadata == nil { - s.Metadata = map[string]string{} - } - if node.Metadata == nil { - node.Metadata = map[string]string{} - } - - // set the domain in metadata so it can be retrieved by wildcard queries - s.Metadata["domain"] = options.Domain - node.Metadata["domain"] = options.Domain - - e.Lock() - // ensure the leases and registers are setup for this domain - if _, ok := e.leases[options.Domain]; !ok { - e.leases[options.Domain] = make(leases) - } - if _, ok := e.register[options.Domain]; !ok { - e.register[options.Domain] = make(register) - } - - // check to see if we already have a lease cached - leaseID, ok := e.leases[options.Domain][s.Name+node.Id] - e.Unlock() - - if !ok { - // missing lease, check if the key exists - ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) - defer cancel() - - // look for the existing key - key := nodePath(options.Domain, s.Name, node.Id) - rsp, err := e.client.Get(ctx, key, clientv3.WithSerializable()) - if err != nil { - return err - } - - // get the existing lease - for _, kv := range rsp.Kvs { - if kv.Lease > 0 { - leaseID = clientv3.LeaseID(kv.Lease) - - // decode the existing node - srv := decode(kv.Value) - if srv == nil || len(srv.Nodes) == 0 { - continue - } - - // create hash of service; uint64 - h, err := hash.Hash(srv.Nodes[0], nil) - if err != nil { - continue - } - - // save the info - e.Lock() - e.leases[options.Domain][s.Name+node.Id] = leaseID - e.register[options.Domain][s.Name+node.Id] = h - e.Unlock() - - break - } - } - } - - var leaseNotFound bool - - // renew the lease if it exists - if leaseID > 0 { - if logger.V(logger.TraceLevel, logger.DefaultLogger) { - logger.Tracef("Renewing existing lease for %s %d", s.Name, leaseID) - } - - if _, err := e.client.KeepAliveOnce(context.TODO(), leaseID); err != nil { - if err != rpctypes.ErrLeaseNotFound { - return err - } - - if logger.V(logger.TraceLevel, logger.DefaultLogger) { - logger.Tracef("Lease not found for %s %d", s.Name, leaseID) - } - - // lease not found do register - leaseNotFound = true - } - } - - // create hash of service; uint64 - h, err := hash.Hash(node, nil) - if err != nil { - return err - } - - // get existing hash for the service node - e.RLock() - v, ok := e.register[options.Domain][s.Name+node.Id] - e.RUnlock() - - // the service is unchanged, skip registering - if ok && v == h && !leaseNotFound { - if logger.V(logger.TraceLevel, logger.DefaultLogger) { - logger.Tracef("Service %s node %s unchanged skipping registration", s.Name, node.Id) - } - return nil - } - - // add domain to the service metadata so it can be determined when doing wildcard queries - if s.Metadata == nil { - s.Metadata = map[string]string{"domain": options.Domain} - } else { - s.Metadata["domain"] = options.Domain - } - - service := ®istry.Service{ - Name: s.Name, - Version: s.Version, - Metadata: s.Metadata, - Endpoints: s.Endpoints, - Nodes: []*registry.Node{node}, - } - - ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) - defer cancel() - - var lgr *clientv3.LeaseGrantResponse - if options.TTL.Seconds() > 0 { - // get a lease used to expire keys since we have a ttl - lgr, err = e.client.Grant(ctx, int64(options.TTL.Seconds())) - if err != nil { - return err - } - } - - // create an entry for the node - var putOpts []clientv3.OpOption - if lgr != nil { - putOpts = append(putOpts, clientv3.WithLease(lgr.ID)) - - if logger.V(logger.TraceLevel, logger.DefaultLogger) { - logger.Tracef("Registering %s id %s with lease %v and leaseID %v and ttl %v", service.Name, node.Id, lgr, lgr.ID, options.TTL) - } - } else if logger.V(logger.TraceLevel, logger.DefaultLogger) { - logger.Tracef("Registering %s id %s without lease", service.Name, node.Id) - } - - key := nodePath(options.Domain, s.Name, node.Id) - if _, err = e.client.Put(ctx, key, encode(service), putOpts...); err != nil { - return err - } - - e.Lock() - // save our hash of the service - e.register[options.Domain][s.Name+node.Id] = h - // save our leaseID of the service - if lgr != nil { - e.leases[options.Domain][s.Name+node.Id] = lgr.ID - } - e.Unlock() - - return nil -} - -func (e *etcdRegistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error { - if len(s.Nodes) == 0 { - return errors.New("Require at least one node") - } - - // parse the options - var options registry.DeregisterOptions - for _, o := range opts { - o(&options) - } - if len(options.Domain) == 0 { - options.Domain = defaultDomain - } - - for _, node := range s.Nodes { - e.Lock() - // delete our hash of the service - nodes, ok := e.register[options.Domain] - if ok { - delete(nodes, s.Name+node.Id) - e.register[options.Domain] = nodes - } - - // delete our lease of the service - leases, ok := e.leases[options.Domain] - if ok { - delete(leases, s.Name+node.Id) - e.leases[options.Domain] = leases - } - e.Unlock() - - ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) - defer cancel() - - if logger.V(logger.TraceLevel, logger.DefaultLogger) { - logger.Tracef("Deregistering %s id %s", s.Name, node.Id) - } - - if _, err := e.client.Delete(ctx, nodePath(options.Domain, s.Name, node.Id)); err != nil { - return err - } - } - - return nil -} - -func (e *etcdRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error { - if len(s.Nodes) == 0 { - return errors.New("Require at least one node") - } - - var gerr error - - // register each node individually - for _, node := range s.Nodes { - if err := e.registerNode(s, node, opts...); err != nil { - gerr = err - } - } - - return gerr -} - -func (e *etcdRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) { - ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) - defer cancel() - - // parse the options and fallback to the default domain - var options registry.GetOptions - for _, o := range opts { - o(&options) - } - if len(options.Domain) == 0 { - options.Domain = defaultDomain - } - - var results []*mvccpb.KeyValue - - // TODO: refactorout wildcard, this is an incredibly expensive operation - if options.Domain == registry.WildcardDomain { - rsp, err := e.client.Get(ctx, prefix, clientv3.WithPrefix(), clientv3.WithSerializable()) - if err != nil { - return nil, err - } - - // filter the results for the key we care about - for _, kv := range rsp.Kvs { - // if the key does not contain the name then pass - _, service, ok := getName(string(kv.Key), prefix) - if !ok || service != name { - continue - } - - // save the result if its what we expect - results = append(results, kv) - } - } else { - prefix := servicePath(options.Domain, name) + "/" - rsp, err := e.client.Get(ctx, prefix, clientv3.WithPrefix(), clientv3.WithSerializable()) - if err != nil { - return nil, err - } - results = rsp.Kvs - } - - if len(results) == 0 { - return nil, registry.ErrNotFound - } - - versions := make(map[string]*registry.Service) - - for _, n := range results { - // only process the things we care about - domain, service, ok := getName(string(n.Key), prefix) - if !ok || service != name { - continue - } - - if sn := decode(n.Value); sn != nil { - // compose a key of name/version/domain - key := sn.Name + sn.Version + domain - - s, ok := versions[key] - if !ok { - s = ®istry.Service{ - Name: sn.Name, - Version: sn.Version, - Metadata: sn.Metadata, - Endpoints: sn.Endpoints, - } - versions[key] = s - } - s.Nodes = append(s.Nodes, sn.Nodes...) - } - } - - services := make([]*registry.Service, 0, len(versions)) - - for _, service := range versions { - services = append(services, service) - } - - return services, nil -} - -func (e *etcdRegistry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) { - // parse the options - var options registry.ListOptions - for _, o := range opts { - o(&options) - } - if len(options.Domain) == 0 { - options.Domain = defaultDomain - } - - // determine the prefix - var p string - if options.Domain == registry.WildcardDomain { - p = prefix - } else { - p = prefixWithDomain(options.Domain) - } - - ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) - defer cancel() - - rsp, err := e.client.Get(ctx, p, clientv3.WithPrefix(), clientv3.WithSerializable()) - if err != nil { - return nil, err - } - if len(rsp.Kvs) == 0 { - return []*registry.Service{}, nil - } - - versions := make(map[string]*registry.Service) - for _, n := range rsp.Kvs { - domain, service, ok := getName(string(n.Key), prefix) - if !ok { - continue - } - - sn := decode(n.Value) - if sn == nil || sn.Name != service { - continue - } - - // key based on name/version/domain - key := sn.Name + sn.Version + domain - - v, ok := versions[key] - if !ok { - versions[key] = sn - continue - } - - // append to service:version nodes - v.Nodes = append(v.Nodes, sn.Nodes...) - } - - services := make([]*registry.Service, 0, len(versions)) - for _, service := range versions { - services = append(services, service) - } - - // sort the services - sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name }) - - return services, nil -} - -func (e *etcdRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) { - cli, err := newClient(e) - if err != nil { - return nil, err - } - return newEtcdWatcher(cli, e.options.Timeout, opts...) -} - -func (e *etcdRegistry) String() string { - return "etcd" -} diff --git a/registry/etcd/etcd_test.go b/registry/etcd/etcd_test.go deleted file mode 100644 index 35c5668c..00000000 --- a/registry/etcd/etcd_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package etcd - -import ( - "testing" -) - -// test whether the name matches -func TestEtcdHasName(t *testing.T) { - testCases := []struct { - key string - prefix string - name string - domain string - expect bool - }{ - { - "/micro/registry/micro/registry", - "/micro/registry", - "registry", - "micro", - true, - }, - { - "/micro/registry/micro", - "/micro/registry", - "store", - "micro", - false, - }, - { - "/prefix/baz/*/registry", - "/prefix/baz", - "registry", - "*", - true, - }, - { - "/prefix/baz", - "/prefix/baz", - "store", - "micro", - false, - }, - { - "/prefix/baz/foobar/registry", - "/prefix/baz", - "registry", - "foobar", - true, - }, - } - - for _, c := range testCases { - domain, service, ok := getName(c.key, c.prefix) - if ok != c.expect { - t.Fatalf("Expected %t for %v got: %t", c.expect, c, ok) - } - if !ok { - continue - } - if service != c.name { - t.Fatalf("Expected service %s got %s", c.name, service) - } - if domain != c.domain { - t.Fatalf("Expected domain %s got %s", c.domain, domain) - } - } -} diff --git a/registry/etcd/options.go b/registry/etcd/options.go deleted file mode 100644 index f444c884..00000000 --- a/registry/etcd/options.go +++ /dev/null @@ -1,37 +0,0 @@ -package etcd - -import ( - "context" - - "github.com/micro/go-micro/v3/registry" - "go.uber.org/zap" -) - -type authKey struct{} - -type logConfigKey struct{} - -type authCreds struct { - Username string - Password string -} - -// Auth allows you to specify username/password -func Auth(username, password string) registry.Option { - return func(o *registry.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, authKey{}, &authCreds{Username: username, Password: password}) - } -} - -// LogConfig allows you to set etcd log config -func LogConfig(config *zap.Config) registry.Option { - return func(o *registry.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, logConfigKey{}, config) - } -} diff --git a/registry/etcd/watcher.go b/registry/etcd/watcher.go deleted file mode 100644 index ff1c6065..00000000 --- a/registry/etcd/watcher.go +++ /dev/null @@ -1,105 +0,0 @@ -package etcd - -import ( - "context" - "errors" - "sync" - "time" - - "github.com/coreos/etcd/clientv3" - "github.com/micro/go-micro/v3/registry" -) - -type etcdWatcher struct { - w clientv3.WatchChan - client *clientv3.Client - timeout time.Duration - - mtx sync.Mutex - stop chan bool - cancel func() -} - -func newEtcdWatcher(c *clientv3.Client, timeout time.Duration, opts ...registry.WatchOption) (registry.Watcher, error) { - var wo registry.WatchOptions - for _, o := range opts { - o(&wo) - } - if len(wo.Domain) == 0 { - wo.Domain = defaultDomain - } - - watchPath := prefix - if wo.Domain == registry.WildcardDomain { - if len(wo.Service) > 0 { - return nil, errors.New("Cannot watch a service across domains") - } - watchPath = prefix - } else if len(wo.Service) > 0 { - watchPath = servicePath(wo.Domain, wo.Service) + "/" - } - - ctx, cancel := context.WithCancel(context.Background()) - w := c.Watch(ctx, watchPath, clientv3.WithPrefix(), clientv3.WithPrevKV()) - stop := make(chan bool, 1) - - return &etcdWatcher{ - cancel: cancel, - stop: stop, - w: w, - client: c, - timeout: timeout, - }, nil -} - -func (ew *etcdWatcher) Next() (*registry.Result, error) { - for wresp := range ew.w { - if wresp.Err() != nil { - return nil, wresp.Err() - } - if wresp.Canceled { - return nil, errors.New("could not get next") - } - for _, ev := range wresp.Events { - service := decode(ev.Kv.Value) - var action string - - switch ev.Type { - case clientv3.EventTypePut: - if ev.IsCreate() { - action = "create" - } else if ev.IsModify() { - action = "update" - } - case clientv3.EventTypeDelete: - action = "delete" - - // get service from prevKv - service = decode(ev.PrevKv.Value) - } - - if service == nil { - continue - } - return ®istry.Result{ - Action: action, - Service: service, - }, nil - } - } - return nil, errors.New("could not get next") -} - -func (ew *etcdWatcher) Stop() { - ew.mtx.Lock() - defer ew.mtx.Unlock() - - select { - case <-ew.stop: - return - default: - close(ew.stop) - ew.cancel() - ew.client.Close() - } -} diff --git a/store/cockroach/cockroach.go b/store/cockroach/cockroach.go deleted file mode 100644 index c7801e8c..00000000 --- a/store/cockroach/cockroach.go +++ /dev/null @@ -1,513 +0,0 @@ -// Package cockroach implements the cockroach store -package cockroach - -import ( - "database/sql" - "fmt" - "net/url" - "regexp" - "strings" - "sync" - "time" - - "github.com/lib/pq" - "github.com/micro/go-micro/v3/logger" - "github.com/micro/go-micro/v3/store" - "github.com/pkg/errors" -) - -// DefaultDatabase is the namespace that the sql store -// will use if no namespace is provided. -var ( - DefaultDatabase = "micro" - DefaultTable = "micro" -) - -var ( - re = regexp.MustCompile("[^a-zA-Z0-9]+") - - statements = map[string]string{ - "list": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;", - "read": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key = $1;", - "readMany": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1;", - "readOffset": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;", - "write": "INSERT INTO %s.%s(key, value, metadata, expiry) VALUES ($1, $2::bytea, $3, $4) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, metadata = EXCLUDED.metadata, expiry = EXCLUDED.expiry;", - "delete": "DELETE FROM %s.%s WHERE key = $1;", - } -) - -type sqlStore struct { - options store.Options - db *sql.DB - - sync.RWMutex - // known databases - databases map[string]bool -} - -func (s *sqlStore) getDB(database, table string) (string, string) { - if len(database) == 0 { - if len(s.options.Database) > 0 { - database = s.options.Database - } else { - database = DefaultDatabase - } - } - - if len(table) == 0 { - if len(s.options.Table) > 0 { - table = s.options.Table - } else { - table = DefaultTable - } - } - - // store.namespace must only contain letters, numbers and underscores - database = re.ReplaceAllString(database, "_") - table = re.ReplaceAllString(table, "_") - - return database, table -} - -func (s *sqlStore) createDB(database, table string) error { - database, table = s.getDB(database, table) - - s.Lock() - defer s.Unlock() - - if _, ok := s.databases[database+":"+table]; ok { - return nil - } - - if err := s.initDB(database, table); err != nil { - return err - } - - s.databases[database+":"+table] = true - return nil -} - -func (s *sqlStore) initDB(database, table string) error { - if s.db == nil { - return errors.New("Database connection not initialised") - } - - // Create the namespace's database - _, err := s.db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", database)) - if err != nil { - return err - } - - // Create a table for the namespace's prefix - _, err = s.db.Exec(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.%s - ( - key text NOT NULL, - value bytea, - metadata JSONB, - expiry timestamp with time zone, - CONSTRAINT %s_pkey PRIMARY KEY (key) - );`, database, table, table)) - if err != nil { - return errors.Wrap(err, "Couldn't create table") - } - - // Create Index - _, err = s.db.Exec(fmt.Sprintf(`CREATE INDEX IF NOT EXISTS "%s" ON %s.%s USING btree ("key");`, "key_index_"+table, database, table)) - if err != nil { - return err - } - - // Create Metadata Index - _, err = s.db.Exec(fmt.Sprintf(`CREATE INDEX IF NOT EXISTS "%s" ON %s.%s USING GIN ("metadata");`, "metadata_index_"+table, database, table)) - if err != nil { - return err - } - - return nil -} - -func (s *sqlStore) configure() error { - if len(s.options.Nodes) == 0 { - s.options.Nodes = []string{"postgresql://root@localhost:26257?sslmode=disable"} - } - - source := s.options.Nodes[0] - // check if it is a standard connection string eg: host=%s port=%d user=%s password=%s dbname=%s sslmode=disable - // if err is nil which means it would be a URL like postgre://xxxx?yy=zz - _, err := url.Parse(source) - if err != nil { - if !strings.Contains(source, " ") { - source = fmt.Sprintf("host=%s", source) - } - } - - // create source from first node - db, err := sql.Open("postgres", source) - if err != nil { - return err - } - - if err := db.Ping(); err != nil { - return err - } - - if s.db != nil { - s.db.Close() - } - - // save the values - s.db = db - - // get DB - database, table := s.getDB(s.options.Database, s.options.Table) - - // initialise the database - return s.initDB(database, table) -} - -func (s *sqlStore) prepare(database, table, query string) (*sql.Stmt, error) { - st, ok := statements[query] - if !ok { - return nil, errors.New("unsupported statement") - } - - // get DB - database, table = s.getDB(database, table) - - q := fmt.Sprintf(st, database, table) - stmt, err := s.db.Prepare(q) - if err != nil { - return nil, err - } - return stmt, nil -} - -func (s *sqlStore) Close() error { - if s.db != nil { - return s.db.Close() - } - return nil -} - -func (s *sqlStore) Init(opts ...store.Option) error { - for _, o := range opts { - o(&s.options) - } - // reconfigure - return s.configure() -} - -// List all the known records -func (s *sqlStore) List(opts ...store.ListOption) ([]string, error) { - var options store.ListOptions - for _, o := range opts { - o(&options) - } - - // create the db if not exists - if err := s.createDB(options.Database, options.Table); err != nil { - return nil, err - } - limit := sql.NullInt32{} - offset := 0 - pattern := "%" - if options.Prefix != "" || options.Suffix != "" { - if options.Prefix != "" { - pattern = options.Prefix + pattern - } - if options.Suffix != "" { - pattern = pattern + options.Suffix - } - } - if options.Offset > 0 { - offset = int(options.Offset) - } - if options.Limit > 0 { - limit = sql.NullInt32{Int32: int32(options.Limit), Valid: true} - } - - st, err := s.prepare(options.Database, options.Table, "list") - if err != nil { - return nil, err - } - defer st.Close() - - rows, err := st.Query(pattern, limit, offset) - if err != nil { - if err == sql.ErrNoRows { - return nil, nil - } - return nil, err - } - defer rows.Close() - var keys []string - records, err := s.rowsToRecords(rows) - if err != nil { - return nil, err - } - for _, k := range records { - keys = append(keys, k.Key) - } - rowErr := rows.Close() - if rowErr != nil { - // transaction rollback or something - return keys, rowErr - } - if err := rows.Err(); err != nil { - return keys, err - } - return keys, nil -} - -// rowToRecord converts from sql.Row to a store.Record. If the record has expired it will issue a delete in a separate goroutine -func (s *sqlStore) rowToRecord(row *sql.Row) (*store.Record, error) { - var timehelper pq.NullTime - record := &store.Record{} - metadata := make(Metadata) - - if err := row.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil { - if err == sql.ErrNoRows { - return record, store.ErrNotFound - } - return nil, err - } - - // set the metadata - record.Metadata = toMetadata(&metadata) - if timehelper.Valid { - if timehelper.Time.Before(time.Now()) { - // record has expired - go s.Delete(record.Key) - return nil, store.ErrNotFound - } - record.Expiry = time.Until(timehelper.Time) - - } - return record, nil -} - -// rowsToRecords converts from sql.Rows to []*store.Record. If a record has expired it will issue a delete in a separate goroutine -func (s *sqlStore) rowsToRecords(rows *sql.Rows) ([]*store.Record, error) { - var records []*store.Record - var timehelper pq.NullTime - - for rows.Next() { - record := &store.Record{} - metadata := make(Metadata) - - if err := rows.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil { - return records, err - } - - // set the metadata - record.Metadata = toMetadata(&metadata) - - if timehelper.Valid { - if timehelper.Time.Before(time.Now()) { - // record has expired - go s.Delete(record.Key) - } else { - record.Expiry = time.Until(timehelper.Time) - records = append(records, record) - } - } else { - records = append(records, record) - } - } - return records, nil -} - -// Read a single key -func (s *sqlStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) { - var options store.ReadOptions - for _, o := range opts { - o(&options) - } - - // create the db if not exists - if err := s.createDB(options.Database, options.Table); err != nil { - return nil, err - } - - if options.Prefix || options.Suffix { - return s.read(key, options) - } - - st, err := s.prepare(options.Database, options.Table, "read") - if err != nil { - return nil, err - } - defer st.Close() - - row := st.QueryRow(key) - record, err := s.rowToRecord(row) - if err != nil { - return nil, err - } - var records []*store.Record - return append(records, record), nil -} - -// Read Many records -func (s *sqlStore) read(key string, options store.ReadOptions) ([]*store.Record, error) { - pattern := "%" - if options.Prefix { - pattern = key + pattern - } - if options.Suffix { - pattern = pattern + key - } - - var rows *sql.Rows - var st *sql.Stmt - var err error - - if options.Limit != 0 { - st, err = s.prepare(options.Database, options.Table, "readOffset") - if err != nil { - return nil, err - } - defer st.Close() - - rows, err = st.Query(pattern, options.Limit, options.Offset) - } else { - st, err = s.prepare(options.Database, options.Table, "readMany") - if err != nil { - return nil, err - } - defer st.Close() - - rows, err = st.Query(pattern) - } - if err != nil { - if err == sql.ErrNoRows { - return []*store.Record{}, nil - } - return []*store.Record{}, errors.Wrap(err, "sqlStore.read failed") - } - - defer rows.Close() - - records, err := s.rowsToRecords(rows) - if err != nil { - return nil, err - } - rowErr := rows.Close() - if rowErr != nil { - // transaction rollback or something - return records, rowErr - } - if err := rows.Err(); err != nil { - return records, err - } - - return records, nil -} - -// Write records -func (s *sqlStore) Write(r *store.Record, opts ...store.WriteOption) error { - var options store.WriteOptions - for _, o := range opts { - o(&options) - } - - // create the db if not exists - if err := s.createDB(options.Database, options.Table); err != nil { - return err - } - - st, err := s.prepare(options.Database, options.Table, "write") - if err != nil { - return err - } - defer st.Close() - - metadata := make(Metadata) - for k, v := range r.Metadata { - metadata[k] = v - } - - var expiry time.Time - if r.Expiry != 0 { - expiry = time.Now().Add(r.Expiry) - } - - if expiry.IsZero() { - _, err = st.Exec(r.Key, r.Value, metadata, nil) - } else { - _, err = st.Exec(r.Key, r.Value, metadata, expiry) - } - - if err != nil { - return errors.Wrap(err, "Couldn't insert record "+r.Key) - } - - return nil -} - -// Delete records with keys -func (s *sqlStore) Delete(key string, opts ...store.DeleteOption) error { - var options store.DeleteOptions - for _, o := range opts { - o(&options) - } - - // create the db if not exists - if err := s.createDB(options.Database, options.Table); err != nil { - return err - } - - st, err := s.prepare(options.Database, options.Table, "delete") - if err != nil { - return err - } - defer st.Close() - - result, err := st.Exec(key) - if err != nil { - return err - } - - _, err = result.RowsAffected() - if err != nil { - return err - } - - return nil -} - -func (s *sqlStore) Options() store.Options { - return s.options -} - -func (s *sqlStore) String() string { - return "cockroach" -} - -// NewStore returns a new micro Store backed by sql -func NewStore(opts ...store.Option) store.Store { - options := store.Options{ - Database: DefaultDatabase, - Table: DefaultTable, - } - - for _, o := range opts { - o(&options) - } - - // new store - s := new(sqlStore) - // set the options - s.options = options - // mark known databases - s.databases = make(map[string]bool) - // best-effort configure the store - if err := s.configure(); err != nil { - if logger.V(logger.ErrorLevel, logger.DefaultLogger) { - logger.Error("Error configuring store ", err) - } - } - - // return store - return s -} diff --git a/store/cockroach/metadata.go b/store/cockroach/metadata.go deleted file mode 100644 index 21bb284e..00000000 --- a/store/cockroach/metadata.go +++ /dev/null @@ -1,45 +0,0 @@ -package cockroach - -import ( - "database/sql/driver" - "encoding/json" - "errors" -) - -// https://github.com/upper/db/blob/master/postgresql/custom_types.go#L43 -type Metadata map[string]interface{} - -// Scan satisfies the sql.Scanner interface. -func (m *Metadata) Scan(src interface{}) error { - source, ok := src.([]byte) - if !ok { - return errors.New("Type assertion .([]byte) failed.") - } - - var i interface{} - err := json.Unmarshal(source, &i) - if err != nil { - return err - } - - *m, ok = i.(map[string]interface{}) - if !ok { - return errors.New("Type assertion .(map[string]interface{}) failed.") - } - - return nil -} - -// Value satisfies the driver.Valuer interface. -func (m Metadata) Value() (driver.Value, error) { - j, err := json.Marshal(m) - return j, err -} - -func toMetadata(m *Metadata) map[string]interface{} { - md := make(map[string]interface{}) - for k, v := range *m { - md[k] = v - } - return md -} diff --git a/store/test/store_test.go b/store/test/store_test.go index a8f0f0c1..6b0f54a5 100644 --- a/store/test/store_test.go +++ b/store/test/store_test.go @@ -10,18 +10,12 @@ import ( "testing" "time" - "github.com/micro/go-micro/v3/store/cache" - - "github.com/micro/go-micro/v3/store/memory" - - "github.com/kr/pretty" - "github.com/micro/go-micro/v3/store/cockroach" - - "github.com/micro/go-micro/v3/store" - - "github.com/micro/go-micro/v3/store/file" - "github.com/davecgh/go-spew/spew" + "github.com/kr/pretty" + "github.com/micro/go-micro/v3/store" + "github.com/micro/go-micro/v3/store/cache" + "github.com/micro/go-micro/v3/store/file" + "github.com/micro/go-micro/v3/store/memory" ) func fileStoreCleanup(db string, s store.Store) { @@ -53,7 +47,6 @@ func TestStoreReInit(t *testing.T) { cleanup func(db string, s store.Store) }{ {name: "file", s: file.NewStore(store.Table("aaa")), cleanup: fileStoreCleanup}, - {name: "cockroach", s: cockroach.NewStore(store.Table("aaa")), cleanup: cockroachStoreCleanup}, {name: "memory", s: memory.NewStore(store.Table("aaa")), cleanup: memoryCleanup}, {name: "cache", s: cache.NewStore(memory.NewStore(store.Table("aaa"))), cleanup: cacheCleanup}, } @@ -75,7 +68,6 @@ func TestStoreBasic(t *testing.T) { cleanup func(db string, s store.Store) }{ {name: "file", s: file.NewStore(), cleanup: fileStoreCleanup}, - {name: "cockroach", s: cockroach.NewStore(), cleanup: cockroachStoreCleanup}, {name: "memory", s: memory.NewStore(), cleanup: memoryCleanup}, {name: "cache", s: cache.NewStore(memory.NewStore()), cleanup: cacheCleanup}, } @@ -95,7 +87,6 @@ func TestStoreTable(t *testing.T) { cleanup func(db string, s store.Store) }{ {name: "file", s: file.NewStore(store.Table("testTable")), cleanup: fileStoreCleanup}, - {name: "cockroach", s: cockroach.NewStore(store.Table("testTable")), cleanup: cockroachStoreCleanup}, {name: "memory", s: memory.NewStore(store.Table("testTable")), cleanup: memoryCleanup}, {name: "cache", s: cache.NewStore(memory.NewStore(store.Table("testTable"))), cleanup: cacheCleanup}, } @@ -114,7 +105,6 @@ func TestStoreDatabase(t *testing.T) { cleanup func(db string, s store.Store) }{ {name: "file", s: file.NewStore(store.Database("testdb")), cleanup: fileStoreCleanup}, - {name: "cockroach", s: cockroach.NewStore(store.Database("testdb")), cleanup: cockroachStoreCleanup}, {name: "memory", s: memory.NewStore(store.Database("testdb")), cleanup: memoryCleanup}, {name: "cache", s: cache.NewStore(memory.NewStore(store.Database("testdb"))), cleanup: cacheCleanup}, } @@ -133,7 +123,6 @@ func TestStoreDatabaseTable(t *testing.T) { cleanup func(db string, s store.Store) }{ {name: "file", s: file.NewStore(store.Database("testdb"), store.Table("testTable")), cleanup: fileStoreCleanup}, - {name: "cockroach", s: cockroach.NewStore(store.Database("testdb"), store.Table("testTable")), cleanup: cockroachStoreCleanup}, {name: "memory", s: memory.NewStore(store.Database("testdb"), store.Table("testTable")), cleanup: memoryCleanup}, {name: "cache", s: cache.NewStore(memory.NewStore(store.Database("testdb"), store.Table("testTable"))), cleanup: cacheCleanup}, } diff --git a/sync/etcd/etcd.go b/sync/etcd/etcd.go deleted file mode 100644 index 553a6b25..00000000 --- a/sync/etcd/etcd.go +++ /dev/null @@ -1,179 +0,0 @@ -// Package etcd is an etcd implementation of lock -package etcd - -import ( - "context" - "errors" - "log" - "path" - "strings" - gosync "sync" - - client "github.com/coreos/etcd/clientv3" - cc "github.com/coreos/etcd/clientv3/concurrency" - "github.com/micro/go-micro/v3/sync" -) - -type etcdSync struct { - options sync.Options - path string - client *client.Client - - mtx gosync.Mutex - locks map[string]*etcdLock -} - -type etcdLock struct { - s *cc.Session - m *cc.Mutex -} - -type etcdLeader struct { - opts sync.LeaderOptions - s *cc.Session - e *cc.Election - id string -} - -func (e *etcdSync) Leader(id string, opts ...sync.LeaderOption) (sync.Leader, error) { - var options sync.LeaderOptions - for _, o := range opts { - o(&options) - } - - // make path - path := path.Join(e.path, strings.Replace(e.options.Prefix+id, "/", "-", -1)) - - s, err := cc.NewSession(e.client) - if err != nil { - return nil, err - } - - l := cc.NewElection(s, path) - - if err := l.Campaign(context.TODO(), id); err != nil { - return nil, err - } - - return &etcdLeader{ - opts: options, - e: l, - id: id, - }, nil -} - -func (e *etcdLeader) Status() chan bool { - ch := make(chan bool, 1) - ech := e.e.Observe(context.Background()) - - go func() { - for r := range ech { - if string(r.Kvs[0].Value) != e.id { - ch <- true - close(ch) - return - } - } - }() - - return ch -} - -func (e *etcdLeader) Resign() error { - return e.e.Resign(context.Background()) -} - -func (e *etcdSync) Init(opts ...sync.Option) error { - for _, o := range opts { - o(&e.options) - } - return nil -} - -func (e *etcdSync) Options() sync.Options { - return e.options -} - -func (e *etcdSync) Lock(id string, opts ...sync.LockOption) error { - var options sync.LockOptions - for _, o := range opts { - o(&options) - } - - // make path - path := path.Join(e.path, strings.Replace(e.options.Prefix+id, "/", "-", -1)) - - var sopts []cc.SessionOption - if options.TTL > 0 { - sopts = append(sopts, cc.WithTTL(int(options.TTL.Seconds()))) - } - - s, err := cc.NewSession(e.client, sopts...) - if err != nil { - return err - } - - m := cc.NewMutex(s, path) - - if err := m.Lock(context.TODO()); err != nil { - return err - } - - e.mtx.Lock() - e.locks[id] = &etcdLock{ - s: s, - m: m, - } - e.mtx.Unlock() - return nil -} - -func (e *etcdSync) Unlock(id string) error { - e.mtx.Lock() - defer e.mtx.Unlock() - v, ok := e.locks[id] - if !ok { - return errors.New("lock not found") - } - err := v.m.Unlock(context.Background()) - delete(e.locks, id) - return err -} - -func (e *etcdSync) String() string { - return "etcd" -} - -func NewSync(opts ...sync.Option) sync.Sync { - var options sync.Options - for _, o := range opts { - o(&options) - } - - var endpoints []string - - for _, addr := range options.Nodes { - if len(addr) > 0 { - endpoints = append(endpoints, addr) - } - } - - if len(endpoints) == 0 { - endpoints = []string{"http://127.0.0.1:2379"} - } - - // TODO: parse addresses - c, err := client.New(client.Config{ - Endpoints: endpoints, - }) - if err != nil { - log.Fatal(err) - } - - return &etcdSync{ - path: "/micro/sync", - client: c, - options: options, - locks: make(map[string]*etcdLock), - } -}