Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
115ca6a018 | |||
89cf4ef8af | |||
2a6ce6d4da | |||
ad19fe2b90 | |||
49055a28ea | |||
d1c6e121c1 | |||
7cd7fb0c0a |
@ -80,6 +80,13 @@ func WithContextAttrFuncs(fncs ...ContextAttrFunc) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAddFields add fields for the logger
|
||||||
|
func WithAddFields(fields ...interface{}) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Fields = append(o.Fields, fields...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithFields set default fields for the logger
|
// WithFields set default fields for the logger
|
||||||
func WithFields(fields ...interface{}) Option {
|
func WithFields(fields ...interface{}) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v3/logger"
|
||||||
"go.unistack.org/micro/v3/semconv"
|
"go.unistack.org/micro/v3/semconv"
|
||||||
@ -31,6 +32,27 @@ var (
|
|||||||
fatalValue = slog.StringValue("fatal")
|
fatalValue = slog.StringValue("fatal")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type wrapper struct {
|
||||||
|
h slog.Handler
|
||||||
|
level atomic.Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *wrapper) Enabled(ctx context.Context, level slog.Level) bool {
|
||||||
|
return level >= slog.Level(int(h.level.Load()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *wrapper) Handle(ctx context.Context, rec slog.Record) error {
|
||||||
|
return h.h.Handle(ctx, rec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *wrapper) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
|
return h.WithAttrs(attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *wrapper) WithGroup(name string) slog.Handler {
|
||||||
|
return h.WithGroup(name)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
|
func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
|
||||||
switch a.Key {
|
switch a.Key {
|
||||||
case slog.SourceKey:
|
case slog.SourceKey:
|
||||||
@ -68,7 +90,7 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
|
|||||||
|
|
||||||
type slogLogger struct {
|
type slogLogger struct {
|
||||||
leveler *slog.LevelVar
|
leveler *slog.LevelVar
|
||||||
handler slog.Handler
|
handler *wrapper
|
||||||
opts logger.Options
|
opts logger.Options
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
@ -82,51 +104,52 @@ func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
|
|||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
l := &slogLogger{
|
if len(options.ContextAttrFuncs) == 0 {
|
||||||
opts: options,
|
options.ContextAttrFuncs = logger.DefaultContextAttrFuncs
|
||||||
}
|
}
|
||||||
|
|
||||||
l.leveler = new(slog.LevelVar)
|
attrs, _ := s.argsAttrs(options.Fields)
|
||||||
handleOpt := &slog.HandlerOptions{
|
l := &slogLogger{
|
||||||
ReplaceAttr: l.renameAttr,
|
handler: &wrapper{h: s.handler.h.WithAttrs(attrs)},
|
||||||
Level: l.leveler,
|
opts: options,
|
||||||
AddSource: l.opts.AddSource,
|
|
||||||
}
|
}
|
||||||
l.leveler.Set(loggerToSlogLevel(l.opts.Level))
|
l.handler.level.Store(int64(loggerToSlogLevel(options.Level)))
|
||||||
l.handler = slog.New(slog.NewJSONHandler(options.Out, handleOpt)).With(options.Fields...).Handler()
|
|
||||||
|
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) V(level logger.Level) bool {
|
func (s *slogLogger) V(level logger.Level) bool {
|
||||||
return s.opts.Level.Enabled(level)
|
s.mu.Lock()
|
||||||
|
v := s.opts.Level.Enabled(level)
|
||||||
|
s.mu.Unlock()
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Level(level logger.Level) {
|
func (s *slogLogger) Level(level logger.Level) {
|
||||||
s.leveler.Set(loggerToSlogLevel(level))
|
s.mu.Lock()
|
||||||
|
s.opts.Level = level
|
||||||
|
s.handler.level.Store(int64(loggerToSlogLevel(level)))
|
||||||
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Options() logger.Options {
|
func (s *slogLogger) Options() logger.Options {
|
||||||
return s.opts
|
return s.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Fields(attrs ...interface{}) logger.Logger {
|
func (s *slogLogger) Fields(fields ...interface{}) logger.Logger {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
level := s.leveler.Level()
|
|
||||||
options := s.opts
|
options := s.opts
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
|
||||||
l := &slogLogger{opts: options}
|
l := &slogLogger{opts: options}
|
||||||
l.leveler = new(slog.LevelVar)
|
|
||||||
l.leveler.Set(level)
|
|
||||||
|
|
||||||
handleOpt := &slog.HandlerOptions{
|
if len(options.ContextAttrFuncs) == 0 {
|
||||||
ReplaceAttr: l.renameAttr,
|
options.ContextAttrFuncs = logger.DefaultContextAttrFuncs
|
||||||
Level: l.leveler,
|
|
||||||
AddSource: l.opts.AddSource,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.handler = slog.New(slog.NewJSONHandler(l.opts.Out, handleOpt)).With(attrs...).Handler()
|
attrs, _ := s.argsAttrs(fields)
|
||||||
|
l.handler = &wrapper{h: s.handler.h.WithAttrs(attrs)}
|
||||||
|
l.handler.level.Store(int64(loggerToSlogLevel(l.opts.Level)))
|
||||||
|
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
@ -134,22 +157,23 @@ func (s *slogLogger) Fields(attrs ...interface{}) logger.Logger {
|
|||||||
func (s *slogLogger) Init(opts ...logger.Option) error {
|
func (s *slogLogger) Init(opts ...logger.Option) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
|
||||||
if len(s.opts.ContextAttrFuncs) == 0 {
|
|
||||||
s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&s.opts)
|
o(&s.opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.leveler = new(slog.LevelVar)
|
if len(s.opts.ContextAttrFuncs) == 0 {
|
||||||
|
s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
|
||||||
|
}
|
||||||
|
|
||||||
handleOpt := &slog.HandlerOptions{
|
handleOpt := &slog.HandlerOptions{
|
||||||
ReplaceAttr: s.renameAttr,
|
ReplaceAttr: s.renameAttr,
|
||||||
Level: s.leveler,
|
Level: loggerToSlogLevel(logger.TraceLevel),
|
||||||
AddSource: s.opts.AddSource,
|
AddSource: s.opts.AddSource,
|
||||||
}
|
}
|
||||||
s.leveler.Set(loggerToSlogLevel(s.opts.Level))
|
|
||||||
s.handler = slog.New(slog.NewJSONHandler(s.opts.Out, handleOpt)).With(s.opts.Fields...).Handler()
|
attrs, _ := s.argsAttrs(s.opts.Fields)
|
||||||
|
s.handler = &wrapper{h: slog.NewJSONHandler(s.opts.Out, handleOpt).WithAttrs(attrs)}
|
||||||
|
s.handler.level.Store(int64(loggerToSlogLevel(s.opts.Level)))
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -15,6 +15,84 @@ import (
|
|||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v3/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestWithAddFields(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
l := NewLogger(logger.WithLevel(logger.InfoLevel), logger.WithOutput(buf))
|
||||||
|
if err := l.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Info(ctx, "msg1")
|
||||||
|
|
||||||
|
if err := l.Init(logger.WithAddFields("key1", "val1")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
l.Info(ctx, "msg2")
|
||||||
|
|
||||||
|
if err := l.Init(logger.WithAddFields("key2", "val2")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
l.Info(ctx, "msg3")
|
||||||
|
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"key1"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"key2"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleFieldsWithLevel(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
l := NewLogger(logger.WithLevel(logger.InfoLevel), logger.WithOutput(buf))
|
||||||
|
if err := l.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l = l.Fields("key", "val")
|
||||||
|
|
||||||
|
l.Info(ctx, "msg1")
|
||||||
|
nl := l.Clone(logger.WithLevel(logger.DebugLevel))
|
||||||
|
nl.Debug(ctx, "msg2")
|
||||||
|
l.Debug(ctx, "msg3")
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"key":"val"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"msg1"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"msg2"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
if bytes.Contains(buf.Bytes(), []byte(`"msg3"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleFields(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
l := NewLogger(logger.WithLevel(logger.InfoLevel), logger.WithOutput(buf))
|
||||||
|
if err := l.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l = l.Fields("key", "val")
|
||||||
|
|
||||||
|
l = l.Fields("key1", "val1")
|
||||||
|
|
||||||
|
l.Info(ctx, "msg")
|
||||||
|
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"key":"val"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"key1":"val1"`)) {
|
||||||
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
func TestError(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
@ -234,4 +312,11 @@ func Test_WithContextAttrFunc(t *testing.T) {
|
|||||||
if !(bytes.Contains(buf.Bytes(), []byte(`"source-service":"Test-System"`))) {
|
if !(bytes.Contains(buf.Bytes(), []byte(`"source-service":"Test-System"`))) {
|
||||||
t.Fatalf("logger info, buf %s", buf.Bytes())
|
t.Fatalf("logger info, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
|
buf.Reset()
|
||||||
|
imd, _ := metadata.FromIncomingContext(ctx)
|
||||||
|
l.Info(ctx, "test message1")
|
||||||
|
imd.Set("Source-Service", "Test-System2")
|
||||||
|
l.Info(ctx, "test message2")
|
||||||
|
|
||||||
|
// t.Logf("xxx %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/KimMachineGun/automemlimit/memlimit"
|
"github.com/KimMachineGun/automemlimit/memlimit"
|
||||||
_ "go.uber.org/automaxprocs"
|
"go.uber.org/automaxprocs/maxprocs"
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v3/broker"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v3/client"
|
||||||
"go.unistack.org/micro/v3/config"
|
"go.unistack.org/micro/v3/config"
|
||||||
@ -20,6 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
maxprocs.Set()
|
||||||
memlimit.SetGoMemLimitWithOpts(
|
memlimit.SetGoMemLimitWithOpts(
|
||||||
memlimit.WithRatio(0.9),
|
memlimit.WithRatio(0.9),
|
||||||
memlimit.WithProvider(
|
memlimit.WithProvider(
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cache "github.com/patrickmn/go-cache"
|
cache "github.com/patrickmn/go-cache"
|
||||||
@ -20,7 +21,10 @@ func NewStore(opts ...store.Option) store.Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) Connect(ctx context.Context) error {
|
func (m *memoryStore) Connect(ctx context.Context) error {
|
||||||
return nil
|
if m.opts.LazyConnect {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return m.connect(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) Disconnect(ctx context.Context) error {
|
func (m *memoryStore) Disconnect(ctx context.Context) error {
|
||||||
@ -29,13 +33,14 @@ func (m *memoryStore) Disconnect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type memoryStore struct {
|
type memoryStore struct {
|
||||||
funcRead store.FuncRead
|
funcRead store.FuncRead
|
||||||
funcWrite store.FuncWrite
|
funcWrite store.FuncWrite
|
||||||
funcExists store.FuncExists
|
funcExists store.FuncExists
|
||||||
funcList store.FuncList
|
funcList store.FuncList
|
||||||
funcDelete store.FuncDelete
|
funcDelete store.FuncDelete
|
||||||
store *cache.Cache
|
store *cache.Cache
|
||||||
opts store.Options
|
opts store.Options
|
||||||
|
isConnected atomic.Int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) key(prefix, key string) string {
|
func (m *memoryStore) key(prefix, key string) string {
|
||||||
@ -145,6 +150,11 @@ func (m *memoryStore) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) Exists(ctx context.Context, key string, opts ...store.ExistsOption) error {
|
func (m *memoryStore) Exists(ctx context.Context, key string, opts ...store.ExistsOption) error {
|
||||||
|
if m.opts.LazyConnect {
|
||||||
|
if err := m.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return m.funcExists(ctx, key, opts...)
|
return m.funcExists(ctx, key, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +167,11 @@ func (m *memoryStore) fnExists(ctx context.Context, key string, opts ...store.Ex
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) Read(ctx context.Context, key string, val interface{}, opts ...store.ReadOption) error {
|
func (m *memoryStore) Read(ctx context.Context, key string, val interface{}, opts ...store.ReadOption) error {
|
||||||
|
if m.opts.LazyConnect {
|
||||||
|
if err := m.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return m.funcRead(ctx, key, val, opts...)
|
return m.funcRead(ctx, key, val, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,6 +184,11 @@ func (m *memoryStore) fnRead(ctx context.Context, key string, val interface{}, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) Write(ctx context.Context, key string, val interface{}, opts ...store.WriteOption) error {
|
func (m *memoryStore) Write(ctx context.Context, key string, val interface{}, opts ...store.WriteOption) error {
|
||||||
|
if m.opts.LazyConnect {
|
||||||
|
if err := m.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return m.funcWrite(ctx, key, val, opts...)
|
return m.funcWrite(ctx, key, val, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +213,11 @@ func (m *memoryStore) fnWrite(ctx context.Context, key string, val interface{},
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) Delete(ctx context.Context, key string, opts ...store.DeleteOption) error {
|
func (m *memoryStore) Delete(ctx context.Context, key string, opts ...store.DeleteOption) error {
|
||||||
|
if m.opts.LazyConnect {
|
||||||
|
if err := m.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return m.funcDelete(ctx, key, opts...)
|
return m.funcDelete(ctx, key, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +236,11 @@ func (m *memoryStore) Options() store.Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memoryStore) List(ctx context.Context, opts ...store.ListOption) ([]string, error) {
|
func (m *memoryStore) List(ctx context.Context, opts ...store.ListOption) ([]string, error) {
|
||||||
|
if m.opts.LazyConnect {
|
||||||
|
if err := m.connect(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return m.funcList(ctx, opts...)
|
return m.funcList(ctx, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,3 +274,8 @@ func (m *memoryStore) fnList(ctx context.Context, opts ...store.ListOption) ([]s
|
|||||||
|
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *memoryStore) connect(ctx context.Context) error {
|
||||||
|
m.isConnected.CompareAndSwap(0, 1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v3/options"
|
||||||
)
|
)
|
||||||
@ -9,12 +10,13 @@ import (
|
|||||||
var _ Store = (*noopStore)(nil)
|
var _ Store = (*noopStore)(nil)
|
||||||
|
|
||||||
type noopStore struct {
|
type noopStore struct {
|
||||||
funcRead FuncRead
|
funcRead FuncRead
|
||||||
funcWrite FuncWrite
|
funcWrite FuncWrite
|
||||||
funcExists FuncExists
|
funcExists FuncExists
|
||||||
funcList FuncList
|
funcList FuncList
|
||||||
funcDelete FuncDelete
|
funcDelete FuncDelete
|
||||||
opts Options
|
opts Options
|
||||||
|
isConnected atomic.Int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStore(opts ...Option) *noopStore {
|
func NewStore(opts ...Option) *noopStore {
|
||||||
@ -52,12 +54,10 @@ func (n *noopStore) Init(opts ...Option) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) Connect(ctx context.Context) error {
|
func (n *noopStore) Connect(ctx context.Context) error {
|
||||||
select {
|
if n.opts.LazyConnect {
|
||||||
case <-ctx.Done():
|
return nil
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
return nil
|
return n.connect(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) Disconnect(ctx context.Context) error {
|
func (n *noopStore) Disconnect(ctx context.Context) error {
|
||||||
@ -70,6 +70,11 @@ func (n *noopStore) Disconnect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error {
|
func (n *noopStore) Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error {
|
||||||
|
if n.opts.LazyConnect {
|
||||||
|
if err := n.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return n.funcRead(ctx, key, val, opts...)
|
return n.funcRead(ctx, key, val, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +88,11 @@ func (n *noopStore) fnRead(ctx context.Context, key string, val interface{}, opt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) Delete(ctx context.Context, key string, opts ...DeleteOption) error {
|
func (n *noopStore) Delete(ctx context.Context, key string, opts ...DeleteOption) error {
|
||||||
|
if n.opts.LazyConnect {
|
||||||
|
if err := n.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return n.funcDelete(ctx, key, opts...)
|
return n.funcDelete(ctx, key, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +106,11 @@ func (n *noopStore) fnDelete(ctx context.Context, key string, opts ...DeleteOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) Exists(ctx context.Context, key string, opts ...ExistsOption) error {
|
func (n *noopStore) Exists(ctx context.Context, key string, opts ...ExistsOption) error {
|
||||||
|
if n.opts.LazyConnect {
|
||||||
|
if err := n.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return n.funcExists(ctx, key, opts...)
|
return n.funcExists(ctx, key, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +124,11 @@ func (n *noopStore) fnExists(ctx context.Context, key string, opts ...ExistsOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) Write(ctx context.Context, key string, val interface{}, opts ...WriteOption) error {
|
func (n *noopStore) Write(ctx context.Context, key string, val interface{}, opts ...WriteOption) error {
|
||||||
|
if n.opts.LazyConnect {
|
||||||
|
if err := n.connect(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return n.funcWrite(ctx, key, val, opts...)
|
return n.funcWrite(ctx, key, val, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +142,11 @@ func (n *noopStore) fnWrite(ctx context.Context, key string, val interface{}, op
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *noopStore) List(ctx context.Context, opts ...ListOption) ([]string, error) {
|
func (n *noopStore) List(ctx context.Context, opts ...ListOption) ([]string, error) {
|
||||||
|
if n.opts.LazyConnect {
|
||||||
|
if err := n.connect(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return n.funcList(ctx, opts...)
|
return n.funcList(ctx, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,3 +170,15 @@ func (n *noopStore) String() string {
|
|||||||
func (n *noopStore) Options() Options {
|
func (n *noopStore) Options() Options {
|
||||||
return n.opts
|
return n.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *noopStore) connect(ctx context.Context) error {
|
||||||
|
if n.isConnected.CompareAndSwap(0, 1) {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -41,6 +41,8 @@ type Options struct {
|
|||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
// Hooks can be run before/after store Read/List/Write/Exists/Delete
|
// Hooks can be run before/after store Read/List/Write/Exists/Delete
|
||||||
Hooks options.Hooks
|
Hooks options.Hooks
|
||||||
|
// LazyConnect creates a connection when using store
|
||||||
|
LazyConnect bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions creates options struct
|
// NewOptions creates options struct
|
||||||
@ -132,6 +134,13 @@ func Timeout(td time.Duration) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LazyConnect initialize connection only when needed
|
||||||
|
func LazyConnect(b bool) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.LazyConnect = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Addrs contains the addresses or other connection information of the backing storage.
|
// Addrs contains the addresses or other connection information of the backing storage.
|
||||||
// For example, an etcd implementation would contain the nodes of the cluster.
|
// For example, an etcd implementation would contain the nodes of the cluster.
|
||||||
// A SQL implementation could contain one or more connection strings.
|
// A SQL implementation could contain one or more connection strings.
|
||||||
|
Loading…
Reference in New Issue
Block a user