Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d63723ed3 | |||
a7f84e0baa | |||
c209892ce8 | |||
421842315f | |||
25350a6531 | |||
5e47cc7e8c | |||
1687b98b11 | |||
a81649d2a2 | |||
b48faa3b2b | |||
0be584ef0d | |||
26a2d18766 | |||
25a796fe4f | |||
d23de14769 | |||
2fb108519c | |||
c7ce238da3 | |||
|
67aa79f18a | ||
e6c3d734a3 | |||
1374e27531 |
2
.github/workflows/autoapprove.yml
vendored
2
.github/workflows/autoapprove.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: approve
|
||||
uses: hmarr/auto-approve-action@v2
|
||||
uses: hmarr/auto-approve-action@v3
|
||||
if: github.actor == 'vtolstov' || github.actor == 'dependabot[bot]'
|
||||
id: approve
|
||||
with:
|
||||
|
@@ -74,7 +74,7 @@ type Request interface {
|
||||
type Response interface {
|
||||
// Read the response
|
||||
Codec() codec.Codec
|
||||
// read the header
|
||||
// Header data
|
||||
Header() metadata.Metadata
|
||||
// Read the undecoded response
|
||||
Read() ([]byte, error)
|
||||
|
@@ -49,7 +49,7 @@ func (l *defaultLogger) Clone(opts ...Option) Logger {
|
||||
|
||||
oldopts.Wrappers = newopts.Wrappers
|
||||
l.Lock()
|
||||
cl := &defaultLogger{opts: oldopts, logFunc: l.logFunc, logfFunc: l.logfFunc}
|
||||
cl := &defaultLogger{opts: oldopts, logFunc: l.logFunc, logfFunc: l.logfFunc, enc: json.NewEncoder(l.opts.Out)}
|
||||
l.Unlock()
|
||||
|
||||
// wrap the Log func
|
||||
|
@@ -35,6 +35,7 @@ var (
|
||||
nilAngleBytes = []byte("<nil>")
|
||||
circularShortBytes = []byte("<shown>")
|
||||
invalidAngleBytes = []byte("<invalid>")
|
||||
filteredBytes = []byte("<filtered>")
|
||||
openBracketBytes = []byte("[")
|
||||
closeBracketBytes = []byte("]")
|
||||
percentBytes = []byte("%")
|
||||
@@ -48,22 +49,25 @@ var (
|
||||
type unwrap struct {
|
||||
val interface{}
|
||||
s fmt.State
|
||||
depth int
|
||||
pointers map[uintptr]int
|
||||
opts *Options
|
||||
depth int
|
||||
ignoreNextType bool
|
||||
}
|
||||
|
||||
// Options struct
|
||||
type Options struct {
|
||||
Codec codec.Codec
|
||||
Indent string
|
||||
UnwrapMethods bool
|
||||
Codec codec.Codec
|
||||
Indent string
|
||||
Methods bool
|
||||
Tagged bool
|
||||
}
|
||||
|
||||
// NewOptions creates new Options struct via provided args
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Indent: " ",
|
||||
UnwrapMethods: false,
|
||||
Indent: " ",
|
||||
Methods: false,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
@@ -71,26 +75,37 @@ func NewOptions(opts ...Option) Options {
|
||||
return options
|
||||
}
|
||||
|
||||
// Option func signature
|
||||
type Option func(*Options)
|
||||
|
||||
func UnwrapIndent(f string) Option {
|
||||
// Indent option specify indent level
|
||||
func Indent(f string) Option {
|
||||
return func(o *Options) {
|
||||
o.Indent = f
|
||||
}
|
||||
}
|
||||
|
||||
func UnwrapMethods(b bool) Option {
|
||||
// Methods option toggles fmt.Stringer methods
|
||||
func Methods(b bool) Option {
|
||||
return func(o *Options) {
|
||||
o.UnwrapMethods = b
|
||||
o.Methods = b
|
||||
}
|
||||
}
|
||||
|
||||
func UnwrapCodec(c codec.Codec) Option {
|
||||
// Codec option automatic marshal arg via specified codec and write it to log
|
||||
func Codec(c codec.Codec) Option {
|
||||
return func(o *Options) {
|
||||
o.Codec = c
|
||||
}
|
||||
}
|
||||
|
||||
// Tagged option toggles output only logger:"take" fields
|
||||
func Tagged(b bool) Option {
|
||||
return func(o *Options) {
|
||||
o.Tagged = b
|
||||
}
|
||||
}
|
||||
|
||||
func Unwrap(val interface{}, opts ...Option) *unwrap {
|
||||
options := NewOptions(opts...)
|
||||
return &unwrap{val: val, opts: &options, pointers: make(map[uintptr]int)}
|
||||
@@ -197,10 +212,8 @@ func (f *unwrap) formatPtr(v reflect.Value) {
|
||||
switch {
|
||||
case nilFound:
|
||||
_, _ = f.s.Write(nilAngleBytes)
|
||||
|
||||
case cycleFound:
|
||||
_, _ = f.s.Write(circularShortBytes)
|
||||
|
||||
default:
|
||||
f.ignoreNextType = true
|
||||
f.format(ve)
|
||||
@@ -256,7 +269,7 @@ func (f *unwrap) format(v reflect.Value) {
|
||||
|
||||
// Call Stringer/error interfaces if they exist and the handle methods
|
||||
// flag is enabled.
|
||||
if !f.opts.UnwrapMethods {
|
||||
if f.opts.Methods {
|
||||
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||
if handled := handleMethods(f.opts, f.s, v); handled {
|
||||
return
|
||||
@@ -335,13 +348,22 @@ func (f *unwrap) format(v reflect.Value) {
|
||||
_, _ = f.s.Write(closeMapBytes)
|
||||
case reflect.Struct:
|
||||
numFields := v.NumField()
|
||||
numWritten := 0
|
||||
_, _ = f.s.Write(openBraceBytes)
|
||||
f.depth++
|
||||
vt := v.Type()
|
||||
prevSkip := false
|
||||
for i := 0; i < numFields; i++ {
|
||||
sv, ok := vt.Field(i).Tag.Lookup("logger")
|
||||
if ok && sv == "omit" {
|
||||
if ok {
|
||||
switch sv {
|
||||
case "omit":
|
||||
prevSkip = true
|
||||
continue
|
||||
case "take":
|
||||
break
|
||||
}
|
||||
} else if f.opts.Tagged {
|
||||
prevSkip = true
|
||||
continue
|
||||
}
|
||||
@@ -358,8 +380,12 @@ func (f *unwrap) format(v reflect.Value) {
|
||||
_, _ = f.s.Write(colonBytes)
|
||||
}
|
||||
f.format(f.unpackValue(v.Field(i)))
|
||||
numWritten++
|
||||
}
|
||||
f.depth--
|
||||
if numWritten == 0 && f.depth < 0 {
|
||||
_, _ = f.s.Write(filteredBytes)
|
||||
}
|
||||
_, _ = f.s.Write(closeBraceBytes)
|
||||
case reflect.Uintptr:
|
||||
getHexPtr(f.s, uintptr(v.Uint()))
|
||||
|
@@ -1,24 +1,13 @@
|
||||
package unwrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.unistack.org/micro/v3/codec"
|
||||
)
|
||||
|
||||
func TestUnwrapOmit(t *testing.T) {
|
||||
type val struct {
|
||||
MP map[string]string `json:"mp" logger:"omit"`
|
||||
STR string `json:"str"`
|
||||
AR []string `json:"ar"`
|
||||
}
|
||||
|
||||
v1 := &val{AR: []string{"string1", "string2"}, STR: "string", MP: map[string]string{"key": "val"}}
|
||||
|
||||
t.Logf("output: %#v", v1)
|
||||
t.Logf("output: %#v", Unwrap(v1))
|
||||
}
|
||||
|
||||
func TestUnwrap(t *testing.T) {
|
||||
string1 := "string1"
|
||||
string2 := "string2"
|
||||
@@ -32,7 +21,10 @@ func TestUnwrap(t *testing.T) {
|
||||
|
||||
v1 := &val1{ar: []*string{&string1, &string2}, str: &string1, val: &val1{str: &string2}, mp: map[string]string{"key": "val"}}
|
||||
|
||||
t.Logf("output: %#v", Unwrap(v1))
|
||||
buf := fmt.Sprintf("%#v", Unwrap(v1))
|
||||
if strings.Compare(buf, `&unwrap.val1{mp:map[string]string{"key":"val"}, val:(*unwrap.val1){mp:map[string]string<nil>, val:(*unwrap.val1)<nil>, str:(*string)"string2", ar:[]*string<nil>}, str:(*string)"string1", ar:[]*string{<*><shown>, <*>"string2"}}`) != 0 {
|
||||
t.Fatalf("not proper written %s", buf)
|
||||
}
|
||||
|
||||
type val2 struct {
|
||||
mp map[string]string
|
||||
@@ -42,11 +34,11 @@ func TestUnwrap(t *testing.T) {
|
||||
}
|
||||
|
||||
v2 := &val2{ar: []string{string1, string2}, str: string1, val: &val2{str: string2}, mp: map[string]string{"key": "val"}}
|
||||
|
||||
t.Logf("output: %#v", v2)
|
||||
_ = v2
|
||||
// t.Logf("output: %#v", v2)
|
||||
}
|
||||
|
||||
func TestUnwrapCodec(t *testing.T) {
|
||||
func TestCodec(t *testing.T) {
|
||||
type val struct {
|
||||
MP map[string]string `json:"mp"`
|
||||
STR string `json:"str"`
|
||||
@@ -55,5 +47,54 @@ func TestUnwrapCodec(t *testing.T) {
|
||||
|
||||
v1 := &val{AR: []string{"string1", "string2"}, STR: "string", MP: map[string]string{"key": "val"}}
|
||||
|
||||
t.Logf("output: %#v", Unwrap(v1, UnwrapCodec(codec.NewCodec())))
|
||||
buf := fmt.Sprintf("%#v", Unwrap(v1, Codec(codec.NewCodec())))
|
||||
if strings.Compare(buf, `{"mp":{"key":"val"},"str":"string","ar":["string1","string2"]}`) != 0 {
|
||||
t.Fatalf("not proper written %s", buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOmit(t *testing.T) {
|
||||
type val struct {
|
||||
Key1 string `logger:"omit"`
|
||||
Key2 string `logger:"take"`
|
||||
Key3 string
|
||||
}
|
||||
v1 := &val{Key1: "val1", Key2: "val2", Key3: "val3"}
|
||||
buf := fmt.Sprintf("%#v", Unwrap(v1))
|
||||
if strings.Compare(buf, `&unwrap.val{Key2:"val2", Key3:"val3"}`) != 0 {
|
||||
t.Fatalf("not proper written %s", buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagged(t *testing.T) {
|
||||
type val struct {
|
||||
Key1 string `logger:"take"`
|
||||
Key2 string
|
||||
}
|
||||
|
||||
v1 := &val{Key1: "val1", Key2: "val2"}
|
||||
buf := fmt.Sprintf("%#v", Unwrap(v1, Tagged(true)))
|
||||
if strings.Compare(buf, `&unwrap.val{Key1:"val1"}`) != 0 {
|
||||
t.Fatalf("not proper written %s", buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaggedNested(t *testing.T) {
|
||||
type val struct {
|
||||
key string `logger:"take"`
|
||||
val string `logger:"omit"`
|
||||
unk string
|
||||
}
|
||||
type str struct {
|
||||
val *val `logger:"take"`
|
||||
key string `logger:"omit"`
|
||||
}
|
||||
|
||||
var iface interface{}
|
||||
v := &str{key: "omit", val: &val{key: "test", val: "omit", unk: "unk"}}
|
||||
iface = v
|
||||
buf := fmt.Sprintf("%#v", Unwrap(iface, Tagged(true)))
|
||||
if strings.Compare(buf, `&unwrap.str{val:(*unwrap.val){key:"test"}}`) != 0 {
|
||||
t.Fatalf("not proper written %s", buf)
|
||||
}
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ var (
|
||||
}
|
||||
|
||||
// DefaultSkipEndpoints wrapper not called for this endpoints
|
||||
DefaultSkipEndpoints = []string{"Meter.Metrics"}
|
||||
DefaultSkipEndpoints = []string{"Meter.Metrics", "Health.Live", "Health.Ready", "Health.Version"}
|
||||
)
|
||||
|
||||
type lWrapper struct {
|
||||
@@ -228,11 +228,7 @@ func (l *lWrapper) Call(ctx context.Context, req client.Request, rsp interface{}
|
||||
for _, o := range l.opts.ClientCallObservers {
|
||||
labels = append(labels, o(ctx, req, rsp, opts, err)...)
|
||||
}
|
||||
fields := make(map[string]interface{}, len(labels)/2)
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
fields[labels[i]] = labels[i+1]
|
||||
}
|
||||
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
|
||||
l.opts.Logger.Fields(labels).Log(ctx, l.opts.Level)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -255,11 +251,7 @@ func (l *lWrapper) Stream(ctx context.Context, req client.Request, opts ...clien
|
||||
for _, o := range l.opts.ClientStreamObservers {
|
||||
labels = append(labels, o(ctx, req, opts, stream, err)...)
|
||||
}
|
||||
fields := make(map[string]interface{}, len(labels)/2)
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
fields[labels[i]] = labels[i+1]
|
||||
}
|
||||
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
|
||||
l.opts.Logger.Fields(labels).Log(ctx, l.opts.Level)
|
||||
|
||||
return stream, err
|
||||
}
|
||||
@@ -282,11 +274,7 @@ func (l *lWrapper) Publish(ctx context.Context, msg client.Message, opts ...clie
|
||||
for _, o := range l.opts.ClientPublishObservers {
|
||||
labels = append(labels, o(ctx, msg, opts, err)...)
|
||||
}
|
||||
fields := make(map[string]interface{}, len(labels)/2)
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
fields[labels[i]] = labels[i+1]
|
||||
}
|
||||
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
|
||||
l.opts.Logger.Fields(labels).Log(ctx, l.opts.Level)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -309,11 +297,7 @@ func (l *lWrapper) ServerHandler(ctx context.Context, req server.Request, rsp in
|
||||
for _, o := range l.opts.ServerHandlerObservers {
|
||||
labels = append(labels, o(ctx, req, rsp, err)...)
|
||||
}
|
||||
fields := make(map[string]interface{}, len(labels)/2)
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
fields[labels[i]] = labels[i+1]
|
||||
}
|
||||
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
|
||||
l.opts.Logger.Fields(labels).Log(ctx, l.opts.Level)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -336,11 +320,7 @@ func (l *lWrapper) ServerSubscriber(ctx context.Context, msg server.Message) err
|
||||
for _, o := range l.opts.ServerSubscriberObservers {
|
||||
labels = append(labels, o(ctx, msg, err)...)
|
||||
}
|
||||
fields := make(map[string]interface{}, len(labels)/2)
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
fields[labels[i]] = labels[i+1]
|
||||
}
|
||||
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
|
||||
l.opts.Logger.Fields(labels).Log(ctx, l.opts.Level)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -387,11 +367,7 @@ func (l *lWrapper) ClientCallFunc(ctx context.Context, addr string, req client.R
|
||||
for _, o := range l.opts.ClientCallFuncObservers {
|
||||
labels = append(labels, o(ctx, addr, req, rsp, opts, err)...)
|
||||
}
|
||||
fields := make(map[string]interface{}, len(labels)/2)
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
fields[labels[i]] = labels[i+1]
|
||||
}
|
||||
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
|
||||
l.opts.Logger.Fields(labels).Log(ctx, l.opts.Level)
|
||||
|
||||
return err
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ var (
|
||||
labelEndpoint = "endpoint"
|
||||
|
||||
// DefaultSkipEndpoints contains list of endpoints that not evaluted by wrapper
|
||||
DefaultSkipEndpoints = []string{"Meter.Metrics"}
|
||||
DefaultSkipEndpoints = []string{"Meter.Metrics", "Health.Live", "Health.Ready", "Health.Version"}
|
||||
)
|
||||
|
||||
// Options struct
|
||||
@@ -255,6 +255,7 @@ func (w *wrapper) Publish(ctx context.Context, p client.Message, opts ...client.
|
||||
}
|
||||
|
||||
// NewHandlerWrapper create new server handler wrapper
|
||||
// deprecated
|
||||
func NewHandlerWrapper(opts ...Option) server.HandlerWrapper {
|
||||
handler := &wrapper{
|
||||
opts: NewOptions(opts...),
|
||||
@@ -262,6 +263,14 @@ func NewHandlerWrapper(opts ...Option) server.HandlerWrapper {
|
||||
return handler.HandlerFunc
|
||||
}
|
||||
|
||||
// NewServerHandlerWrapper create new server handler wrapper
|
||||
func NewServerHandlerWrapper(opts ...Option) server.HandlerWrapper {
|
||||
handler := &wrapper{
|
||||
opts: NewOptions(opts...),
|
||||
}
|
||||
return handler.HandlerFunc
|
||||
}
|
||||
|
||||
func (w *wrapper) HandlerFunc(fn server.HandlerFunc) server.HandlerFunc {
|
||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
endpoint := req.Service() + "." + req.Endpoint()
|
||||
@@ -295,6 +304,7 @@ func (w *wrapper) HandlerFunc(fn server.HandlerFunc) server.HandlerFunc {
|
||||
}
|
||||
|
||||
// NewSubscriberWrapper create server subscribe wrapper
|
||||
// deprecated
|
||||
func NewSubscriberWrapper(opts ...Option) server.SubscriberWrapper {
|
||||
handler := &wrapper{
|
||||
opts: NewOptions(opts...),
|
||||
@@ -302,6 +312,13 @@ func NewSubscriberWrapper(opts ...Option) server.SubscriberWrapper {
|
||||
return handler.SubscriberFunc
|
||||
}
|
||||
|
||||
func NewServerSubscriberWrapper(opts ...Option) server.SubscriberWrapper {
|
||||
handler := &wrapper{
|
||||
opts: NewOptions(opts...),
|
||||
}
|
||||
return handler.SubscriberFunc
|
||||
}
|
||||
|
||||
func (w *wrapper) SubscriberFunc(fn server.SubscriberFunc) server.SubscriberFunc {
|
||||
return func(ctx context.Context, msg server.Message) error {
|
||||
endpoint := msg.Topic()
|
||||
|
@@ -35,7 +35,7 @@ type noopSpan struct {
|
||||
ctx context.Context
|
||||
tracer Tracer
|
||||
name string
|
||||
labels []Label
|
||||
opts SpanOptions
|
||||
}
|
||||
|
||||
func (s *noopSpan) Finish(opts ...SpanOption) {
|
||||
@@ -56,8 +56,12 @@ func (s *noopSpan) SetName(name string) {
|
||||
s.name = name
|
||||
}
|
||||
|
||||
func (s *noopSpan) SetLabels(labels ...Label) {
|
||||
s.labels = labels
|
||||
func (s *noopSpan) SetLabels(labels ...interface{}) {
|
||||
s.opts.Labels = labels
|
||||
}
|
||||
|
||||
func (s *noopSpan) AddLabels(labels ...interface{}) {
|
||||
s.opts.Labels = append(s.opts.Labels, labels...)
|
||||
}
|
||||
|
||||
// NewTracer returns new memory tracer
|
||||
|
@@ -3,7 +3,9 @@ package tracer
|
||||
import "go.unistack.org/micro/v3/logger"
|
||||
|
||||
// SpanOptions contains span option
|
||||
type SpanOptions struct{}
|
||||
type SpanOptions struct {
|
||||
Labels []interface{}
|
||||
}
|
||||
|
||||
// SpanOption func signature
|
||||
type SpanOption func(o *SpanOptions)
|
||||
@@ -14,6 +16,12 @@ type EventOptions struct{}
|
||||
// EventOption func signature
|
||||
type EventOption func(o *EventOptions)
|
||||
|
||||
func SpanLabels(labels ...interface{}) SpanOption {
|
||||
return func(o *SpanOptions) {
|
||||
o.Labels = labels
|
||||
}
|
||||
}
|
||||
|
||||
// Options struct
|
||||
type Options struct {
|
||||
// Logger used for logging
|
||||
|
@@ -30,34 +30,7 @@ type Span interface {
|
||||
// SetName set the span name
|
||||
SetName(name string)
|
||||
// SetLabels set the span labels
|
||||
SetLabels(labels ...Label)
|
||||
}
|
||||
|
||||
type Label struct {
|
||||
val interface{}
|
||||
key string
|
||||
}
|
||||
|
||||
func LabelAny(k string, v interface{}) Label {
|
||||
return Label{key: k, val: v}
|
||||
}
|
||||
|
||||
func LabelString(k string, v string) Label {
|
||||
return Label{key: k, val: v}
|
||||
}
|
||||
|
||||
func LabelInt(k string, v int) Label {
|
||||
return Label{key: k, val: v}
|
||||
}
|
||||
|
||||
func LabelInt64(k string, v int64) Label {
|
||||
return Label{key: k, val: v}
|
||||
}
|
||||
|
||||
func LabelFloat64(k string, v float64) Label {
|
||||
return Label{key: k, val: v}
|
||||
}
|
||||
|
||||
func LabelBool(k string, v bool) Label {
|
||||
return Label{key: k, val: v}
|
||||
SetLabels(labels ...interface{})
|
||||
// AddLabels append the span labels
|
||||
AddLabels(labels ...interface{})
|
||||
}
|
||||
|
@@ -14,95 +14,95 @@ import (
|
||||
var (
|
||||
DefaultClientCallObserver = func(ctx context.Context, req client.Request, rsp interface{}, opts []client.CallOption, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()))
|
||||
var labels []tracer.Label
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = make([]tracer.Label, 0, len(md))
|
||||
labels = make([]interface{}, 0, len(md))
|
||||
for k, v := range md {
|
||||
labels = append(labels, tracer.LabelString(k, v))
|
||||
labels = append(labels, k, v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
labels = append(labels, tracer.LabelBool("error", true))
|
||||
labels = append(labels, "error", true)
|
||||
}
|
||||
sp.SetLabels(labels...)
|
||||
}
|
||||
|
||||
DefaultClientStreamObserver = func(ctx context.Context, req client.Request, opts []client.CallOption, stream client.Stream, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()))
|
||||
var labels []tracer.Label
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = make([]tracer.Label, 0, len(md))
|
||||
labels = make([]interface{}, 0, len(md))
|
||||
for k, v := range md {
|
||||
labels = append(labels, tracer.LabelString(k, v))
|
||||
labels = append(labels, k, v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
labels = append(labels, tracer.LabelBool("error", true))
|
||||
labels = append(labels, "error", true)
|
||||
}
|
||||
sp.SetLabels(labels...)
|
||||
}
|
||||
|
||||
DefaultClientPublishObserver = func(ctx context.Context, msg client.Message, opts []client.PublishOption, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("Pub to %s", msg.Topic()))
|
||||
var labels []tracer.Label
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = make([]tracer.Label, 0, len(md))
|
||||
labels = make([]interface{}, 0, len(md))
|
||||
for k, v := range md {
|
||||
labels = append(labels, tracer.LabelString(k, v))
|
||||
labels = append(labels, k, v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
labels = append(labels, tracer.LabelBool("error", true))
|
||||
labels = append(labels, "error", true)
|
||||
}
|
||||
sp.SetLabels(labels...)
|
||||
}
|
||||
|
||||
DefaultServerHandlerObserver = func(ctx context.Context, req server.Request, rsp interface{}, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()))
|
||||
var labels []tracer.Label
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
||||
labels = make([]tracer.Label, 0, len(md))
|
||||
labels = make([]interface{}, 0, len(md))
|
||||
for k, v := range md {
|
||||
labels = append(labels, tracer.LabelString(k, v))
|
||||
labels = append(labels, k, v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
labels = append(labels, tracer.LabelBool("error", true))
|
||||
labels = append(labels, "error", true)
|
||||
}
|
||||
sp.SetLabels(labels...)
|
||||
}
|
||||
|
||||
DefaultServerSubscriberObserver = func(ctx context.Context, msg server.Message, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("Sub from %s", msg.Topic()))
|
||||
var labels []tracer.Label
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
||||
labels = make([]tracer.Label, 0, len(md))
|
||||
labels = make([]interface{}, 0, len(md))
|
||||
for k, v := range md {
|
||||
labels = append(labels, tracer.LabelString(k, v))
|
||||
labels = append(labels, k, v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
labels = append(labels, tracer.LabelBool("error", true))
|
||||
labels = append(labels, "error", true)
|
||||
}
|
||||
sp.SetLabels(labels...)
|
||||
}
|
||||
|
||||
DefaultClientCallFuncObserver = func(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()))
|
||||
var labels []tracer.Label
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = make([]tracer.Label, 0, len(md))
|
||||
labels = make([]interface{}, 0, len(md))
|
||||
for k, v := range md {
|
||||
labels = append(labels, tracer.LabelString(k, v))
|
||||
labels = append(labels, k, v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
labels = append(labels, tracer.LabelBool("error", true))
|
||||
labels = append(labels, "error", true)
|
||||
}
|
||||
sp.SetLabels(labels...)
|
||||
}
|
||||
|
||||
DefaultSkipEndpoints = []string{"Meter.Metrics"}
|
||||
DefaultSkipEndpoints = []string{"Meter.Metrics", "Health.Live", "Health.Ready", "Health.Version"}
|
||||
)
|
||||
|
||||
type tWrapper struct {
|
||||
|
@@ -7,6 +7,7 @@ package http
|
||||
// Modified by Unistack LLC to support interface{} type handler and parameters in map[string]string
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@@ -15,6 +16,11 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("route not found")
|
||||
ErrMethodNotAllowed = errors.New("method not allowed")
|
||||
)
|
||||
|
||||
type methodTyp uint
|
||||
|
||||
const (
|
||||
@@ -399,16 +405,19 @@ func (n *Trie) setEndpoint(method methodTyp, handler interface{}, pattern string
|
||||
}
|
||||
|
||||
// Search try to find element in tree with path and method
|
||||
func (n *Trie) Search(method string, path string) (interface{}, map[string]string, bool) {
|
||||
func (n *Trie) Search(method string, path string) (interface{}, map[string]string, error) {
|
||||
params := &routeParams{}
|
||||
// Find the routing handlers for the path
|
||||
rn := n.findRoute(params, methodMap[method], path)
|
||||
if rn == nil {
|
||||
return nil, nil, false
|
||||
if rn == nil && !params.methodNotAllowed {
|
||||
return nil, nil, ErrNotFound
|
||||
}
|
||||
if params.methodNotAllowed {
|
||||
return nil, nil, ErrMethodNotAllowed
|
||||
}
|
||||
ep, ok := rn.endpoints[methodMap[method]]
|
||||
if !ok {
|
||||
return nil, nil, false
|
||||
return nil, nil, ErrMethodNotAllowed
|
||||
}
|
||||
|
||||
eparams := make(map[string]string, len(params.keys))
|
||||
@@ -416,12 +425,13 @@ func (n *Trie) Search(method string, path string) (interface{}, map[string]strin
|
||||
eparams[key] = params.vals[idx]
|
||||
}
|
||||
|
||||
return ep.handler, eparams, true
|
||||
return ep.handler, eparams, nil
|
||||
}
|
||||
|
||||
type routeParams struct {
|
||||
keys []string
|
||||
vals []string
|
||||
keys []string
|
||||
vals []string
|
||||
methodNotAllowed bool
|
||||
}
|
||||
|
||||
// Recursive edge traversal by checking all nodeTyp groups along the way.
|
||||
@@ -495,6 +505,7 @@ func (n *Trie) findRoute(params *routeParams, method methodTyp, path string) *Tr
|
||||
params.keys = append(params.keys, h.paramKeys...)
|
||||
return xn
|
||||
}
|
||||
params.methodNotAllowed = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,6 +541,7 @@ func (n *Trie) findRoute(params *routeParams, method methodTyp, path string) *Tr
|
||||
params.keys = append(params.keys, h.paramKeys...)
|
||||
return xn
|
||||
}
|
||||
params.methodNotAllowed = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,22 +21,22 @@ func TestTrieWildcardPathPrefix(t *testing.T) {
|
||||
if err = tr.Insert([]string{http.MethodPost}, "/v1/*", &handler{name: "post_create"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
h, _, ok := tr.Search(http.MethodPost, "/v1/test/one")
|
||||
if !ok {
|
||||
h, _, err := tr.Search(http.MethodPost, "/v1/test/one")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error handler not found")
|
||||
}
|
||||
if h.(*handler).name != "post_create" {
|
||||
t.Fatalf("invalid handler %v", h)
|
||||
}
|
||||
h, _, ok = tr.Search(http.MethodPost, "/v1/update")
|
||||
if !ok {
|
||||
h, _, err = tr.Search(http.MethodPost, "/v1/update")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
}
|
||||
if h.(*handler).name != "post_update" {
|
||||
t.Fatalf("invalid handler %v", h)
|
||||
}
|
||||
h, _, ok = tr.Search(http.MethodPost, "/v1/update/some/{x}")
|
||||
if !ok {
|
||||
h, _, err = tr.Search(http.MethodPost, "/v1/update/some/{x}")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
}
|
||||
if h.(*handler).name != "post_create" {
|
||||
@@ -52,8 +52,8 @@ func TestTriePathPrefix(t *testing.T) {
|
||||
_ = tr.Insert([]string{http.MethodPost}, "/v1/create/{id}", &handler{name: "post_create"})
|
||||
_ = tr.Insert([]string{http.MethodPost}, "/v1/update/{id}", &handler{name: "post_update"})
|
||||
_ = tr.Insert([]string{http.MethodPost}, "/", &handler{name: "post_wildcard"})
|
||||
h, _, ok := tr.Search(http.MethodPost, "/")
|
||||
if !ok {
|
||||
h, _, err := tr.Search(http.MethodPost, "/")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
}
|
||||
if h.(*handler).name != "post_wildcard" {
|
||||
@@ -68,8 +68,8 @@ func TestTrieFixedPattern(t *testing.T) {
|
||||
tr := NewTrie()
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create/{id}", &handler{name: "pattern"})
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create/12", &handler{name: "fixed"})
|
||||
h, _, ok := tr.Search(http.MethodPut, "/v1/create/12")
|
||||
if !ok {
|
||||
h, _, err := tr.Search(http.MethodPut, "/v1/create/12")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
}
|
||||
if h.(*handler).name != "fixed" {
|
||||
@@ -80,8 +80,8 @@ func TestTrieFixedPattern(t *testing.T) {
|
||||
func TestTrieNoMatchMethod(t *testing.T) {
|
||||
tr := NewTrie()
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create/{id}", nil)
|
||||
_, _, ok := tr.Search(http.MethodPost, "/v1/create")
|
||||
if ok {
|
||||
_, _, err := tr.Search(http.MethodPost, "/v1/create")
|
||||
if err == nil && err != ErrNotFound {
|
||||
t.Fatalf("must be not found error")
|
||||
}
|
||||
}
|
||||
@@ -90,9 +90,9 @@ func TestTrieMatchRegexp(t *testing.T) {
|
||||
type handler struct{}
|
||||
tr := NewTrie()
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create/{category}/{id:[0-9]+}", &handler{})
|
||||
_, params, ok := tr.Search(http.MethodPut, "/v1/create/test_cat/12345")
|
||||
_, params, err := tr.Search(http.MethodPut, "/v1/create/test_cat/12345")
|
||||
switch {
|
||||
case !ok:
|
||||
case err != nil:
|
||||
t.Fatalf("route not found")
|
||||
case len(params) != 2:
|
||||
t.Fatalf("param matching error %v", params)
|
||||
@@ -105,8 +105,8 @@ func TestTrieMatchRegexpFail(t *testing.T) {
|
||||
type handler struct{}
|
||||
tr := NewTrie()
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create/{id:[a-z]+}", &handler{})
|
||||
_, _, ok := tr.Search(http.MethodPut, "/v1/create/12345")
|
||||
if ok {
|
||||
_, _, err := tr.Search(http.MethodPut, "/v1/create/12345")
|
||||
if err != ErrNotFound {
|
||||
t.Fatalf("route must not be not found")
|
||||
}
|
||||
}
|
||||
@@ -118,14 +118,28 @@ func TestTrieMatchLongest(t *testing.T) {
|
||||
tr := NewTrie()
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create", &handler{name: "first"})
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create/{id:[0-9]+}", &handler{name: "second"})
|
||||
if h, _, ok := tr.Search(http.MethodPut, "/v1/create/12345"); !ok {
|
||||
if h, _, err := tr.Search(http.MethodPut, "/v1/create/12345"); err != nil {
|
||||
t.Fatalf("route must be found")
|
||||
} else if h.(*handler).name != "second" {
|
||||
t.Fatalf("invalid handler found: %s != %s", h.(*handler).name, "second")
|
||||
}
|
||||
if h, _, ok := tr.Search(http.MethodPut, "/v1/create"); !ok {
|
||||
if h, _, err := tr.Search(http.MethodPut, "/v1/create"); err != nil {
|
||||
t.Fatalf("route must be found")
|
||||
} else if h.(*handler).name != "first" {
|
||||
t.Fatalf("invalid handler found: %s != %s", h.(*handler).name, "first")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMethodNotAllowed(t *testing.T) {
|
||||
type handler struct{}
|
||||
tr := NewTrie()
|
||||
_ = tr.Insert([]string{http.MethodPut}, "/v1/create", &handler{})
|
||||
_, _, err := tr.Search(http.MethodPost, "/v1/create")
|
||||
if err != ErrMethodNotAllowed {
|
||||
t.Fatalf("route must be method not allowed: %v", err)
|
||||
}
|
||||
_, _, err = tr.Search(http.MethodPut, "/v1/create")
|
||||
if err != nil {
|
||||
t.Fatalf("route must be found: %v", err)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user