Compare commits

..

No commits in common. "v3" and "v3.10.99" have entirely different histories.
v3 ... v3.10.99

8 changed files with 51 additions and 277 deletions

View File

@ -8,7 +8,6 @@ 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"
@ -32,27 +31,6 @@ 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:
@ -90,7 +68,7 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
type slogLogger struct { type slogLogger struct {
leveler *slog.LevelVar leveler *slog.LevelVar
handler *wrapper handler slog.Handler
opts logger.Options opts logger.Options
mu sync.RWMutex mu sync.RWMutex
} }
@ -104,52 +82,51 @@ func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
o(&options) o(&options)
} }
if len(options.ContextAttrFuncs) == 0 { l := &slogLogger{
options.ContextAttrFuncs = logger.DefaultContextAttrFuncs opts: options,
} }
attrs, _ := s.argsAttrs(options.Fields) l.leveler = new(slog.LevelVar)
l := &slogLogger{ handleOpt := &slog.HandlerOptions{
handler: &wrapper{h: s.handler.h.WithAttrs(attrs)}, ReplaceAttr: l.renameAttr,
opts: options, Level: l.leveler,
AddSource: l.opts.AddSource,
} }
l.handler.level.Store(int64(loggerToSlogLevel(options.Level))) l.leveler.Set(loggerToSlogLevel(l.opts.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 {
s.mu.Lock() return s.opts.Level.Enabled(level)
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.mu.Lock() s.leveler.Set(loggerToSlogLevel(level))
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(fields ...interface{}) logger.Logger { func (s *slogLogger) Fields(attrs ...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)
if len(options.ContextAttrFuncs) == 0 { handleOpt := &slog.HandlerOptions{
options.ContextAttrFuncs = logger.DefaultContextAttrFuncs ReplaceAttr: l.renameAttr,
Level: l.leveler,
AddSource: l.opts.AddSource,
} }
attrs, _ := s.argsAttrs(fields) l.handler = slog.New(slog.NewJSONHandler(l.opts.Out, handleOpt)).With(attrs...).Handler()
l.handler = &wrapper{h: s.handler.h.WithAttrs(attrs)}
l.handler.level.Store(int64(loggerToSlogLevel(l.opts.Level)))
return l return l
} }
@ -157,23 +134,22 @@ func (s *slogLogger) Fields(fields ...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()
for _, o := range opts {
o(&s.opts)
}
if len(s.opts.ContextAttrFuncs) == 0 { if len(s.opts.ContextAttrFuncs) == 0 {
s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
} }
handleOpt := &slog.HandlerOptions{ for _, o := range opts {
ReplaceAttr: s.renameAttr, o(&s.opts)
Level: loggerToSlogLevel(logger.TraceLevel),
AddSource: s.opts.AddSource,
} }
attrs, _ := s.argsAttrs(s.opts.Fields) s.leveler = new(slog.LevelVar)
s.handler = &wrapper{h: slog.NewJSONHandler(s.opts.Out, handleOpt).WithAttrs(attrs)} handleOpt := &slog.HandlerOptions{
s.handler.level.Store(int64(loggerToSlogLevel(s.opts.Level))) ReplaceAttr: s.renameAttr,
Level: s.leveler,
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()
s.mu.Unlock() s.mu.Unlock()
return nil return nil

View File

@ -15,56 +15,6 @@ import (
"go.unistack.org/micro/v3/logger" "go.unistack.org/micro/v3/logger"
) )
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)
@ -284,11 +234,4 @@ 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())
} }

View File

@ -6,7 +6,7 @@ import (
"sync" "sync"
"github.com/KimMachineGun/automemlimit/memlimit" "github.com/KimMachineGun/automemlimit/memlimit"
"go.uber.org/automaxprocs/maxprocs" _ "go.uber.org/automaxprocs"
"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,7 +20,6 @@ import (
) )
func init() { func init() {
maxprocs.Set()
memlimit.SetGoMemLimitWithOpts( memlimit.SetGoMemLimitWithOpts(
memlimit.WithRatio(0.9), memlimit.WithRatio(0.9),
memlimit.WithProvider( memlimit.WithProvider(

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"sort" "sort"
"strings" "strings"
"sync/atomic"
"time" "time"
cache "github.com/patrickmn/go-cache" cache "github.com/patrickmn/go-cache"
@ -21,10 +20,7 @@ func NewStore(opts ...store.Option) store.Store {
} }
func (m *memoryStore) Connect(ctx context.Context) error { func (m *memoryStore) Connect(ctx context.Context) error {
if m.opts.LazyConnect { return nil
return nil
}
return m.connect(ctx)
} }
func (m *memoryStore) Disconnect(ctx context.Context) error { func (m *memoryStore) Disconnect(ctx context.Context) error {
@ -33,14 +29,13 @@ 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 {
@ -150,11 +145,6 @@ 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...)
} }
@ -167,11 +157,6 @@ 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...)
} }
@ -184,11 +169,6 @@ 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...)
} }
@ -213,11 +193,6 @@ 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...)
} }
@ -236,11 +211,6 @@ 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...)
} }
@ -274,8 +244,3 @@ 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
}

View File

@ -2,7 +2,6 @@ package store
import ( import (
"context" "context"
"sync/atomic"
"go.unistack.org/micro/v3/options" "go.unistack.org/micro/v3/options"
) )
@ -10,13 +9,12 @@ 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 {
@ -54,10 +52,12 @@ func (n *noopStore) Init(opts ...Option) error {
} }
func (n *noopStore) Connect(ctx context.Context) error { func (n *noopStore) Connect(ctx context.Context) error {
if n.opts.LazyConnect { select {
return nil case <-ctx.Done():
return ctx.Err()
default:
} }
return n.connect(ctx) return nil
} }
func (n *noopStore) Disconnect(ctx context.Context) error { func (n *noopStore) Disconnect(ctx context.Context) error {
@ -70,11 +70,6 @@ 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...)
} }
@ -88,11 +83,6 @@ 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...)
} }
@ -106,11 +96,6 @@ 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...)
} }
@ -124,11 +109,6 @@ 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...)
} }
@ -142,11 +122,6 @@ 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...)
} }
@ -170,15 +145,3 @@ 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
}

View File

@ -41,8 +41,6 @@ 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
@ -134,13 +132,6 @@ 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.

View File

@ -6,8 +6,6 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"time" "time"
"gopkg.in/yaml.v3"
) )
type Duration int64 type Duration int64
@ -55,31 +53,6 @@ loop:
return time.ParseDuration(fmt.Sprintf("%dh%s", hours, s[p:])) return time.ParseDuration(fmt.Sprintf("%dh%s", hours, s[p:]))
} }
func (d Duration) MarshalYAML() (interface{}, error) {
return time.Duration(d).String(), nil
}
func (d *Duration) UnmarshalYAML(n *yaml.Node) error {
var v interface{}
if err := yaml.Unmarshal([]byte(n.Value), &v); err != nil {
return err
}
switch value := v.(type) {
case float64:
*d = Duration(time.Duration(value))
return nil
case string:
dv, err := ParseDuration(value)
if err != nil {
return err
}
*d = Duration(dv)
return nil
default:
return fmt.Errorf("invalid duration")
}
}
func (d Duration) MarshalJSON() ([]byte, error) { func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d).String()) return json.Marshal(time.Duration(d).String())
} }

View File

@ -5,44 +5,8 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"time" "time"
"gopkg.in/yaml.v3"
) )
func TestMarshalYAML(t *testing.T) {
d := Duration(10000000)
buf, err := yaml.Marshal(d)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf, []byte(`10ms
`)) {
t.Fatalf("invalid duration: %s != %s", buf, `10ms`)
}
}
func TestUnmarshalYAML(t *testing.T) {
type str struct {
TTL Duration `yaml:"ttl"`
}
v := &str{}
var err error
err = yaml.Unmarshal([]byte(`{"ttl":"10ms"}`), v)
if err != nil {
t.Fatal(err)
} else if v.TTL != 10000000 {
t.Fatalf("invalid duration %v != 10000000", v.TTL)
}
err = yaml.Unmarshal([]byte(`{"ttl":"1y"}`), v)
if err != nil {
t.Fatal(err)
} else if v.TTL != 31622400000000000 {
t.Fatalf("invalid duration %v != 31622400000000000", v.TTL)
}
}
func TestMarshalJSON(t *testing.T) { func TestMarshalJSON(t *testing.T) {
d := Duration(10000000) d := Duration(10000000)
buf, err := json.Marshal(d) buf, err := json.Marshal(d)