Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
d0f9d44fe4 | |||
725ed992cc | |||
b8928d3da9 | |||
76090f7569 | |||
f8c68a81f7 | |||
5d997f7654 | |||
56d33ae823 | |||
c3cabc1fe5 | |||
47497b49b3 | |||
e89cfdc80d |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,8 @@
|
|||||||
# Develop tools
|
# Develop tools
|
||||||
/.vscode/
|
/.vscode/
|
||||||
/.idea/
|
/.idea/
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
@ -13,6 +15,7 @@
|
|||||||
_obj
|
_obj
|
||||||
_test
|
_test
|
||||||
_build
|
_build
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
# Architecture specific extensions/prefixes
|
||||||
*.[568vq]
|
*.[568vq]
|
||||||
|
@ -4,6 +4,7 @@ package broker // import "go.unistack.org/micro/v4/broker"
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v4/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
@ -19,6 +20,8 @@ var (
|
|||||||
ErrDisconnected = errors.New("broker disconnected")
|
ErrDisconnected = errors.New("broker disconnected")
|
||||||
// ErrInvalidMessage returns when message has nvalid format
|
// ErrInvalidMessage returns when message has nvalid format
|
||||||
ErrInvalidMessage = errors.New("broker message has invalid format")
|
ErrInvalidMessage = errors.New("broker message has invalid format")
|
||||||
|
// DefaultGracefulTimeout
|
||||||
|
DefaultGracefulTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// Broker is an interface used for asynchronous messaging.
|
// Broker is an interface used for asynchronous messaging.
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"go.unistack.org/micro/v4/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v4/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
|
"go.unistack.org/micro/v4/sync"
|
||||||
"go.unistack.org/micro/v4/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,22 +37,27 @@ type Options struct {
|
|||||||
Name string
|
Name string
|
||||||
// Address holds the broker address
|
// Address holds the broker address
|
||||||
Address []string
|
Address []string
|
||||||
|
|
||||||
|
Wait *sync.WaitGroup
|
||||||
|
|
||||||
|
GracefulTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions create new Options
|
// NewOptions create new Options
|
||||||
func NewOptions(opts ...options.Option) Options {
|
func NewOptions(opts ...options.Option) Options {
|
||||||
options := Options{
|
newOpts := Options{
|
||||||
Register: register.DefaultRegister,
|
Register: register.DefaultRegister,
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
Meter: meter.DefaultMeter,
|
Meter: meter.DefaultMeter,
|
||||||
Codecs: make(map[string]codec.Codec),
|
Codecs: make(map[string]codec.Codec),
|
||||||
Tracer: tracer.DefaultTracer,
|
Tracer: tracer.DefaultTracer,
|
||||||
|
GracefulTimeout: DefaultGracefulTimeout,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&newOpts)
|
||||||
}
|
}
|
||||||
return options
|
return newOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublishOptions struct
|
// PublishOptions struct
|
||||||
|
@ -31,6 +31,9 @@ func (c *cfg) Validate() error {
|
|||||||
if c.IntValue != 10 {
|
if c.IntValue != 10 {
|
||||||
return fmt.Errorf("invalid IntValue %d != %d", 10, c.IntValue)
|
return fmt.Errorf("invalid IntValue %d != %d", 10, c.IntValue)
|
||||||
}
|
}
|
||||||
|
if c.MapValue["key1"] != true {
|
||||||
|
return fmt.Errorf("invalid MapValue %t != %t", true, c.MapValue["key1"])
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,3 +108,19 @@ func TestValidate(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestString(t *testing.T) {
|
||||||
|
cfg := config.NewConfig()
|
||||||
|
res := cfg.String()
|
||||||
|
if res != "default" {
|
||||||
|
t.Fatalf("string value invalid: %s", res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestName(t *testing.T) {
|
||||||
|
cfg := config.NewConfig()
|
||||||
|
res := cfg.Name()
|
||||||
|
if res != "" {
|
||||||
|
t.Fatal("name value not empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
36
flow/flow_test.go
Normal file
36
flow/flow_test.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package flow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FuzzMarshall(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, ref []byte) {
|
||||||
|
rm := RawMessage(ref)
|
||||||
|
|
||||||
|
b, err := rm.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error MarshalJSON: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(ref, b) {
|
||||||
|
t.Errorf("Error. Expected '%s', was '%s'", ref, b)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzUnmarshall(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, ref string) {
|
||||||
|
b := []byte(ref)
|
||||||
|
rm := RawMessage(b)
|
||||||
|
|
||||||
|
if err := rm.UnmarshalJSON(b); err != nil {
|
||||||
|
t.Errorf("Error UnmarshalJSON: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref != string(rm) {
|
||||||
|
t.Errorf("Error. Expected '%s', was '%s'", ref, rm)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -214,6 +214,20 @@ func WithMicroKeys() options.Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAddCallerSkipCount add skip count for copy logger
|
||||||
|
func WithAddCallerSkipCount(n int) options.Option {
|
||||||
|
return func(src interface{}) error {
|
||||||
|
c, err := options.Get(src, ".CallerSkipCount")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = options.Set(src, c.(int)+n, ".CallerSkipCount"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithAddStacktrace controls writing stacktrace on error
|
// WithAddStacktrace controls writing stacktrace on error
|
||||||
func WithAddStacktrace(v bool) options.Option {
|
func WithAddStacktrace(v bool) options.Option {
|
||||||
return func(src interface{}) error {
|
return func(src interface{}) error {
|
||||||
|
@ -17,4 +17,6 @@ var (
|
|||||||
SubscribeMessageTotal = "subscribe_message_total"
|
SubscribeMessageTotal = "subscribe_message_total"
|
||||||
// SubscribeMessageInflight specifies meter metric name
|
// SubscribeMessageInflight specifies meter metric name
|
||||||
SubscribeMessageInflight = "subscribe_message_inflight"
|
SubscribeMessageInflight = "subscribe_message_inflight"
|
||||||
|
// BrokerGroupLag specifies broker lag
|
||||||
|
BrokerGroupLag = "broker_lag"
|
||||||
)
|
)
|
||||||
|
12
semconv/cache.go
Normal file
12
semconv/cache.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package semconv
|
||||||
|
|
||||||
|
var (
|
||||||
|
// CacheRequestDurationSeconds specifies meter metric name
|
||||||
|
CacheRequestDurationSeconds = "cache_request_duration_seconds"
|
||||||
|
// ClientRequestLatencyMicroseconds specifies meter metric name
|
||||||
|
CacheRequestLatencyMicroseconds = "cache_request_latency_microseconds"
|
||||||
|
// CacheRequestTotal specifies meter metric name
|
||||||
|
CacheRequestTotal = "cache_request_total"
|
||||||
|
// CacheRequestInflight specifies meter metric name
|
||||||
|
CacheRequestInflight = "cache_request_inflight"
|
||||||
|
)
|
@ -1,10 +1,8 @@
|
|||||||
// Package tracer provides an interface for distributed tracing
|
// Package tracer provides an interface for distributed tracing
|
||||||
package tracer // import "go.unistack.org/micro/v4/tracer"
|
package tracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v4/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
@ -71,37 +69,3 @@ type Span interface {
|
|||||||
// SpanID returns span id
|
// SpanID returns span id
|
||||||
SpanID() string
|
SpanID() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort labels alphabeticaly by label name
|
|
||||||
type byKey []interface{}
|
|
||||||
|
|
||||||
func (k byKey) Len() int { return len(k) / 2 }
|
|
||||||
func (k byKey) Less(i, j int) bool { return fmt.Sprintf("%s", k[i*2]) < fmt.Sprintf("%s", k[j*2]) }
|
|
||||||
func (k byKey) Swap(i, j int) {
|
|
||||||
k[i*2], k[j*2] = k[j*2], k[i*2]
|
|
||||||
k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func UniqLabels(labels []interface{}) []interface{} {
|
|
||||||
if len(labels)%2 == 1 {
|
|
||||||
labels = labels[:len(labels)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(labels) > 2 {
|
|
||||||
sort.Sort(byKey(labels))
|
|
||||||
|
|
||||||
idx := 0
|
|
||||||
for {
|
|
||||||
if labels[idx] == labels[idx+2] {
|
|
||||||
copy(labels[idx:], labels[idx+2:])
|
|
||||||
labels = labels[:len(labels)-2]
|
|
||||||
} else {
|
|
||||||
idx += 2
|
|
||||||
}
|
|
||||||
if idx+2 >= len(labels) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return labels
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package reflect // import "go.unistack.org/micro/v4/util/reflect"
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -45,15 +46,23 @@ func SliceAppend(b bool) Option {
|
|||||||
|
|
||||||
// Merge merges map[string]interface{} to destination struct
|
// Merge merges map[string]interface{} to destination struct
|
||||||
func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error {
|
func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error {
|
||||||
var err error
|
|
||||||
var sval reflect.Value
|
|
||||||
var fname string
|
|
||||||
|
|
||||||
options := Options{}
|
options := Options{}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unmarshaler, ok := dst.(json.Unmarshaler); ok {
|
||||||
|
buf, err := json.Marshal(mp)
|
||||||
|
if err == nil {
|
||||||
|
err = unmarshaler.UnmarshalJSON(buf)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var sval reflect.Value
|
||||||
|
var fname string
|
||||||
|
|
||||||
dviface := reflect.ValueOf(dst)
|
dviface := reflect.ValueOf(dst)
|
||||||
if dviface.Kind() == reflect.Ptr {
|
if dviface.Kind() == reflect.Ptr {
|
||||||
dviface = dviface.Elem()
|
dviface = dviface.Elem()
|
||||||
|
40
util/sort/sort.go
Normal file
40
util/sort/sort.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package sort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sort labels alphabeticaly by label name
|
||||||
|
type byKey []interface{}
|
||||||
|
|
||||||
|
func (k byKey) Len() int { return len(k) / 2 }
|
||||||
|
func (k byKey) Less(i, j int) bool { return fmt.Sprintf("%s", k[i*2]) < fmt.Sprintf("%s", k[j*2]) }
|
||||||
|
func (k byKey) Swap(i, j int) {
|
||||||
|
k[i*2], k[j*2] = k[j*2], k[i*2]
|
||||||
|
k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func Uniq(labels []interface{}) []interface{} {
|
||||||
|
if len(labels)%2 == 1 {
|
||||||
|
labels = labels[:len(labels)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(labels) > 2 {
|
||||||
|
sort.Sort(byKey(labels))
|
||||||
|
|
||||||
|
idx := 0
|
||||||
|
for {
|
||||||
|
if labels[idx] == labels[idx+2] {
|
||||||
|
copy(labels[idx:], labels[idx+2:])
|
||||||
|
labels = labels[:len(labels)-2]
|
||||||
|
} else {
|
||||||
|
idx += 2
|
||||||
|
}
|
||||||
|
if idx+2 >= len(labels) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels
|
||||||
|
}
|
25
util/xpool/pool.go
Normal file
25
util/xpool/pool.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package pool
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type Pool[T any] struct {
|
||||||
|
p *sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPool[T any](fn func() T) Pool[T] {
|
||||||
|
return Pool[T]{
|
||||||
|
p: &sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return fn()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Pool[T]) Get() T {
|
||||||
|
return p.p.Get().(T)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Pool[T]) Put(t T) {
|
||||||
|
p.p.Put(t)
|
||||||
|
}
|
27
util/xpool/pool_test.go
Normal file
27
util/xpool/pool_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package pool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBytes(t *testing.T) {
|
||||||
|
p := NewPool(func() *bytes.Buffer { return bytes.NewBuffer(nil) })
|
||||||
|
b := p.Get()
|
||||||
|
b.Write([]byte(`test`))
|
||||||
|
if b.String() != "test" {
|
||||||
|
t.Fatal("pool not works")
|
||||||
|
}
|
||||||
|
p.Put(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStrings(t *testing.T) {
|
||||||
|
p := NewPool(func() *strings.Builder { return &strings.Builder{} })
|
||||||
|
b := p.Get()
|
||||||
|
b.Write([]byte(`test`))
|
||||||
|
if b.String() != "test" {
|
||||||
|
t.Fatal("pool not works")
|
||||||
|
}
|
||||||
|
p.Put(b)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user