diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d2a527c6b..ebd64e90b 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -44,7 +44,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Go - uses: actions/setup-go@v3.3.0 + uses: actions/setup-go@v3.3.1 with: go-version: ${{ matrix.go }} diff --git a/api/metadata/server.go b/api/metadata/server.go index 3600fc14e..b1c4c17b2 100644 --- a/api/metadata/server.go +++ b/api/metadata/server.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "sort" "sync" "google.golang.org/grpc" @@ -115,6 +116,8 @@ func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*Li reply.Methods = append(reply.Methods, fmt.Sprintf("/%s/%s", name, method)) } } + sort.Strings(reply.Services) + sort.Strings(reply.Methods) return reply, nil } diff --git a/cmd/kratos/internal/base/vcs_url.go b/cmd/kratos/internal/base/vcs_url.go index ef76db30f..6d3aef12a 100644 --- a/cmd/kratos/internal/base/vcs_url.go +++ b/cmd/kratos/internal/base/vcs_url.go @@ -8,7 +8,7 @@ import ( ) var ( - scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`) + scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`) scheme = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"} ) diff --git a/cmd/kratos/internal/change/get.go b/cmd/kratos/internal/change/get.go index 18e02072a..32046d1ea 100644 --- a/cmd/kratos/internal/change/get.go +++ b/cmd/kratos/internal/change/get.go @@ -43,7 +43,7 @@ func (g *GithubAPI) GetReleaseInfo(version string) ReleaseInfo { if version != "latest" { api = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version) } - resp, code := requestGithubAPI(api, "GET", nil, g.Token) + resp, code := requestGithubAPI(api, http.MethodGet, nil, g.Token) if code != http.StatusOK { printGithubErrorInfo(resp) } @@ -63,7 +63,7 @@ func (g *GithubAPI) GetCommitsInfo() []CommitInfo { var list []CommitInfo for { url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits?pre_page=%d&page=%d&since=%s", g.Owner, g.Repo, prePage, page, info.PublishedAt) - resp, code := requestGithubAPI(url, "GET", nil, g.Token) + resp, code := requestGithubAPI(url, http.MethodGet, nil, g.Token) if code != http.StatusOK { printGithubErrorInfo(resp) } diff --git a/cmd/kratos/version.go b/cmd/kratos/version.go index a616f7153..5ccc1597e 100644 --- a/cmd/kratos/version.go +++ b/cmd/kratos/version.go @@ -1,4 +1,4 @@ package main // release is the current kratos tool version. -const release = "v2.5.1" +const release = "v2.5.2" diff --git a/cmd/protoc-gen-go-errors/version.go b/cmd/protoc-gen-go-errors/version.go index 8061323f7..e9c17d212 100644 --- a/cmd/protoc-gen-go-errors/version.go +++ b/cmd/protoc-gen-go-errors/version.go @@ -1,4 +1,4 @@ package main // release is the current protoc-gen-go-errors version. -const release = "v2.5.1" +const release = "v2.5.2" diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go index d88277227..1c9298bf7 100644 --- a/cmd/protoc-gen-go-http/http.go +++ b/cmd/protoc-gen-go-http/http.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "net/http" "os" "regexp" "strings" @@ -85,7 +86,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated sd.Methods = append(sd.Methods, buildHTTPRule(g, method, rule)) } else if !omitempty { path := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name()) - sd.Methods = append(sd.Methods, buildMethodDesc(g, method, "POST", path)) + sd.Methods = append(sd.Methods, buildMethodDesc(g, method, http.MethodPost, path)) } } if len(sd.Methods) != 0 { @@ -119,19 +120,19 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati switch pattern := rule.Pattern.(type) { case *annotations.HttpRule_Get: path = pattern.Get - method = "GET" + method = http.MethodGet case *annotations.HttpRule_Put: path = pattern.Put - method = "PUT" + method = http.MethodPut case *annotations.HttpRule_Post: path = pattern.Post - method = "POST" + method = http.MethodPost case *annotations.HttpRule_Delete: path = pattern.Delete - method = "DELETE" + method = http.MethodDelete case *annotations.HttpRule_Patch: path = pattern.Patch - method = "PATCH" + method = http.MethodPatch case *annotations.HttpRule_Custom: path = pattern.Custom.Path method = pattern.Custom.Kind @@ -139,7 +140,7 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati body = rule.Body responseBody = rule.ResponseBody md := buildMethodDesc(g, m, method, path) - if method == "GET" || method == "DELETE" { + if method == http.MethodGet || method == http.MethodDelete { if body != "" { _, _ = fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: %s %s body should not be declared.\n", method, path) } @@ -213,7 +214,7 @@ func buildPathVars(path string) (res map[string]*string) { if strings.HasSuffix(path, "/") { fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: Path %s should not end with \"/\" \n", path) } - pattern := regexp.MustCompile(`(?i){([a-z\.0-9_\s]*)=?([^{}]*)}`) + pattern := regexp.MustCompile(`(?i){([a-z.0-9_\s]*)=?([^{}]*)}`) matches := pattern.FindAllStringSubmatch(path, -1) res = make(map[string]*string, len(matches)) for _, m := range matches { diff --git a/cmd/protoc-gen-go-http/version.go b/cmd/protoc-gen-go-http/version.go index 25b73c2fe..7d929e189 100644 --- a/cmd/protoc-gen-go-http/version.go +++ b/cmd/protoc-gen-go-http/version.go @@ -1,4 +1,4 @@ package main // release is the current protoc-gen-go-http version. -const release = "v2.5.1" +const release = "v2.5.2" diff --git a/contrib/config/apollo/README.md b/contrib/config/apollo/README.md index c03cff0fd..a8eea4932 100644 --- a/contrib/config/apollo/README.md +++ b/contrib/config/apollo/README.md @@ -97,5 +97,4 @@ config := map[string]interface{}{ } } } -_ = config ``` diff --git a/contrib/config/apollo/apollo.go b/contrib/config/apollo/apollo.go index 259ed1a90..bd96ef11d 100644 --- a/contrib/config/apollo/apollo.go +++ b/contrib/config/apollo/apollo.go @@ -3,15 +3,14 @@ package apollo import ( "strings" - "github.com/go-kratos/kratos/v2/config" - "github.com/go-kratos/kratos/v2/log" - "github.com/apolloconfig/agollo/v4" "github.com/apolloconfig/agollo/v4/constant" apolloConfig "github.com/apolloconfig/agollo/v4/env/config" "github.com/apolloconfig/agollo/v4/extension" + "github.com/go-kratos/kratos/v2/config" "github.com/go-kratos/kratos/v2/encoding" + "github.com/go-kratos/kratos/v2/log" ) type apollo struct { diff --git a/contrib/config/apollo/watcher.go b/contrib/config/apollo/watcher.go index 94ef2ef0b..ea5ef1083 100644 --- a/contrib/config/apollo/watcher.go +++ b/contrib/config/apollo/watcher.go @@ -4,12 +4,11 @@ import ( "context" "strings" - "github.com/go-kratos/kratos/v2/encoding" + "github.com/apolloconfig/agollo/v4/storage" "github.com/go-kratos/kratos/v2/config" + "github.com/go-kratos/kratos/v2/encoding" "github.com/go-kratos/kratos/v2/log" - - "github.com/apolloconfig/agollo/v4/storage" ) type watcher struct { diff --git a/contrib/config/consul/README.md b/contrib/config/consul/README.md index a3d39a18a..9dc5a0666 100644 --- a/contrib/config/consul/README.md +++ b/contrib/config/consul/README.md @@ -2,20 +2,21 @@ ```go import ( - "github.com/go-kratos/kratos/contrib/config/consul/v2" "github.com/hashicorp/consul/api" + + "github.com/go-kratos/kratos/contrib/config/consul/v2" ) -func main() { +func main() { consulClient, err := api.NewClient(&api.Config{ - Address: "127.0.0.1:8500", + Address: "127.0.0.1:8500", }) if err != nil { panic(err) } cs, err := consul.New(consulClient, consul.WithPath("app/cart/configs/")) - //consul中需要标注文件后缀,kratos读取配置需要适配文件后缀 - //The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration. + // consul中需要标注文件后缀,kratos读取配置需要适配文件后缀 + // The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration. if err != nil { panic(err) } diff --git a/contrib/config/etcd/README.md b/contrib/config/etcd/README.md index d76687458..131619c1a 100644 --- a/contrib/config/etcd/README.md +++ b/contrib/config/etcd/README.md @@ -4,10 +4,11 @@ import ( "log" - cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2" - "github.com/go-kratos/kratos/v2/config" clientv3 "go.etcd.io/etcd/client/v3" "google.golang.org/grpc" + + cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2" + "github.com/go-kratos/kratos/v2/config" ) // create an etcd client @@ -30,12 +31,16 @@ if err != nil { c := config.New(config.WithSource(source)) defer c.Close() +// load sources before get +if err := c.Load(); err != nil { + log.Fatalln(err) +} + // acquire config value foo, err := c.Value("/app-config").String() if err != nil { - log.Println(err) + log.Fatalln(err) } -println(foo) +log.Println(foo) ``` - diff --git a/contrib/config/kubernetes/config_test.go b/contrib/config/kubernetes/config_test.go index 6cdb1c98c..b110b634d 100644 --- a/contrib/config/kubernetes/config_test.go +++ b/contrib/config/kubernetes/config_test.go @@ -8,14 +8,14 @@ import ( "strings" "testing" - "github.com/go-kratos/kratos/v2/config" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" + + "github.com/go-kratos/kratos/v2/config" ) const ( diff --git a/contrib/config/nacos/README.md b/contrib/config/nacos/README.md index 71f186bf6..fa54caf07 100644 --- a/contrib/config/nacos/README.md +++ b/contrib/config/nacos/README.md @@ -2,9 +2,10 @@ ```go import ( - kconfig "github.com/go-kratos/kratos/v2/config" "github.com/nacos-group/nacos-sdk-go/clients" "github.com/nacos-group/nacos-sdk-go/common/constant" + + kconfig "github.com/go-kratos/kratos/v2/config" ) diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod index 7890e0587..6917f24a4 100644 --- a/contrib/config/nacos/go.mod +++ b/contrib/config/nacos/go.mod @@ -5,6 +5,9 @@ go 1.16 require ( github.com/go-kratos/kratos/v2 v2.4.0 github.com/nacos-group/nacos-sdk-go v1.0.9 +) + +require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contrib/config/polaris/README.md b/contrib/config/polaris/README.md index 4c2694c47..b39e78f22 100644 --- a/contrib/config/polaris/README.md +++ b/contrib/config/polaris/README.md @@ -2,24 +2,23 @@ ```go import ( - "log" - - "github.com/polarismesh/polaris-go" - "github.com/go-kratos/kratos/contrib/config/polaris/v2" + "log" + + "github.com/polarismesh/polaris-go" + + "github.com/go-kratos/kratos/contrib/config/polaris/v2" ) func main() { + configApi, err := polaris.NewConfigAPI() + if err != nil { + log.Fatalln(err) + } - configApi, err := polaris.NewConfigAPI() - if err != nil { - log.Fatalln(err) - } - - source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml")) - - if err != nil { - log.Fatalln(err) - } - source.Load() + source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml")) + if err != nil { + log.Fatalln(err) + } + source.Load() } ``` diff --git a/contrib/config/polaris/config.go b/contrib/config/polaris/config.go index c3c39ecee..288db4383 100644 --- a/contrib/config/polaris/config.go +++ b/contrib/config/polaris/config.go @@ -6,9 +6,9 @@ import ( "path/filepath" "strings" - "github.com/go-kratos/kratos/v2/config" - "github.com/polarismesh/polaris-go" + + "github.com/go-kratos/kratos/v2/config" ) // Option is polaris config option. diff --git a/contrib/config/polaris/watcher.go b/contrib/config/polaris/watcher.go index dcd890556..703055508 100644 --- a/contrib/config/polaris/watcher.go +++ b/contrib/config/polaris/watcher.go @@ -5,11 +5,11 @@ import ( "path/filepath" "strings" - "github.com/go-kratos/kratos/v2/config" - "github.com/go-kratos/kratos/v2/log" - "github.com/polarismesh/polaris-go" "github.com/polarismesh/polaris-go/pkg/model" + + "github.com/go-kratos/kratos/v2/config" + "github.com/go-kratos/kratos/v2/log" ) type Watcher struct { @@ -28,7 +28,7 @@ func getFullPath(namespace string, fileGroup string, fileName string) string { return fmt.Sprintf("%s/%s/%s", namespace, fileGroup, fileName) } -func recieve(event model.ConfigFileChangeEvent) { +func receive(event model.ConfigFileChangeEvent) { meta := event.ConfigFileMetadata ec := eventChanMap[getFullPath(meta.GetNamespace(), meta.GetFileGroup(), meta.GetFileName())] defer func() { @@ -42,7 +42,7 @@ func recieve(event model.ConfigFileChangeEvent) { } func newWatcher(configFile polaris.ConfigFile) *Watcher { - configFile.AddChangeListener(recieve) + configFile.AddChangeListener(receive) fullPath := getFullPath(configFile.GetNamespace(), configFile.GetFileGroup(), configFile.GetFileName()) if _, ok := eventChanMap[fullPath]; !ok { diff --git a/contrib/encoding/msgpack/go.mod b/contrib/encoding/msgpack/go.mod index 5b6a1f7e9..7548f1744 100644 --- a/contrib/encoding/msgpack/go.mod +++ b/contrib/encoding/msgpack/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/vmihailenco/msgpack/v5 v5.3.5 ) diff --git a/contrib/log/aliyun/aliyun.go b/contrib/log/aliyun/aliyun.go index 351de69d9..836960e06 100644 --- a/contrib/log/aliyun/aliyun.go +++ b/contrib/log/aliyun/aliyun.go @@ -16,6 +16,7 @@ import ( // Logger see more detail https://github.com/aliyun/aliyun-log-go-sdk type Logger interface { log.Logger + GetProducer() *producer.Producer Close() error } @@ -81,22 +82,16 @@ func (a *aliyunLog) Close() error { } func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error { - buf := level.String() - levelTitle := "level" - - contents := make([]*sls.LogContent, 0) + contents := make([]*sls.LogContent, 0, len(keyvals)/2+1) contents = append(contents, &sls.LogContent{ - Key: &levelTitle, - Value: &buf, + Key: newString(level.Key()), + Value: newString(level.String()), }) - for i := 0; i < len(keyvals); i += 2 { - key := toString(keyvals[i]) - value := toString(keyvals[i+1]) contents = append(contents, &sls.LogContent{ - Key: &key, - Value: &value, + Key: newString(toString(keyvals[i])), + Value: newString(toString(keyvals[i+1])), }) } @@ -104,9 +99,7 @@ func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error { Time: proto.Uint32(uint32(time.Now().Unix())), Contents: contents, } - - err := a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst) - return err + return a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst) } // NewAliyunLog new a aliyun logger with options. @@ -128,6 +121,11 @@ func NewAliyunLog(options ...Option) Logger { } } +// newString string convert to *string +func newString(s string) *string { + return &s +} + // toString convert any type to string func toString(v interface{}) string { var key string @@ -138,23 +136,23 @@ func toString(v interface{}) string { case float64: key = strconv.FormatFloat(v, 'f', -1, 64) case float32: - key = strconv.FormatFloat(float64(v), 'f', -1, 64) + key = strconv.FormatFloat(float64(v), 'f', -1, 32) case int: key = strconv.Itoa(v) case uint: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int8: key = strconv.Itoa(int(v)) case uint8: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int16: key = strconv.Itoa(int(v)) case uint16: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int32: key = strconv.Itoa(int(v)) case uint32: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int64: key = strconv.FormatInt(v, 10) case uint64: diff --git a/contrib/log/aliyun/aliyun_test.go b/contrib/log/aliyun/aliyun_test.go index e8e2624f0..c4bfde480 100644 --- a/contrib/log/aliyun/aliyun_test.go +++ b/contrib/log/aliyun/aliyun_test.go @@ -2,6 +2,7 @@ package aliyun import ( "math" + "reflect" "testing" "github.com/go-kratos/kratos/v2/log" @@ -99,34 +100,44 @@ func TestLog(t *testing.T) { } } +func TestNewString(t *testing.T) { + ptr := newString("") + if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr { + t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind) + } +} + func TestToString(t *testing.T) { tests := []struct { - in interface{} - out string + name string + in interface{} + out string }{ - {math.MaxFloat64, "17976931348623157000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000" + - "0000000000000000000000000000000"}, - {math.MaxFloat32, "340282346638528860000000000000000000000"}, - {1<<((32<<(^uint(0)>>63))-1) - 1, "9223372036854775807"}, - {uint(1<<(32<<(^uint(0)>>63)) - 1), "-1"}, - {math.MaxInt8, "127"}, - {math.MaxUint8, "255"}, - {math.MaxInt16, "32767"}, - {math.MaxUint16, "65535"}, - {math.MaxInt32, "2147483647"}, - {math.MaxUint32, "4294967295"}, - {math.MaxInt64, "9223372036854775807"}, - {uint64(math.MaxUint64), "18446744073709551615"}, - {"abc", "abc"}, - {false, "false"}, - {[]byte("abc"), "abc"}, + {"float64", 6.66, "6.66"}, + {"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll + {"float32", float32(6.66), "6.66"}, + {"max float32", math.MaxFloat32, "340282346638528860000000000000000000000"}, + {"int", int(math.MaxInt64), "9223372036854775807"}, + {"uint", uint(math.MaxUint64), "18446744073709551615"}, + {"int8", math.MaxInt8, "127"}, + {"uint8", math.MaxUint8, "255"}, + {"int16", math.MaxInt16, "32767"}, + {"uint16", math.MaxUint16, "65535"}, + {"int32", math.MaxInt32, "2147483647"}, + {"uint32", math.MaxUint32, "4294967295"}, + {"int64", math.MaxInt64, "9223372036854775807"}, + {"uint64", uint64(math.MaxUint64), "18446744073709551615"}, + {"string", "abc", "abc"}, + {"bool", false, "false"}, + {"[]byte", []byte("abc"), "abc"}, + {"struct", struct{ Name string }{}, `{"Name":""}`}, } for _, test := range tests { - if toString(test.in) != test.out { - t.Fatalf("want: %s, got: %s", test.out, toString(test.in)) - } + t.Run(test.name, func(t *testing.T) { + out := toString(test.in) + if test.out != out { + t.Fatalf("want: %s, got: %s", test.out, out) + } + }) } } diff --git a/contrib/log/aliyun/go.mod b/contrib/log/aliyun/go.mod index 73edfb732..83029a5d4 100644 --- a/contrib/log/aliyun/go.mod +++ b/contrib/log/aliyun/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/aliyun/aliyun-log-go-sdk v0.1.37 - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 google.golang.org/protobuf v1.28.1 ) diff --git a/contrib/log/fluent/fluent_test.go b/contrib/log/fluent/fluent_test.go index 5b7b3e171..41f7080d3 100644 --- a/contrib/log/fluent/fluent_test.go +++ b/contrib/log/fluent/fluent_test.go @@ -11,18 +11,23 @@ import ( ) func TestMain(m *testing.M) { + listener := func(ln net.Listener) { + conn, err := ln.Accept() + if err != nil { + return + } + defer conn.Close() + _, err = io.ReadAll(conn) + if err != nil { + return + } + } + if ln, err := net.Listen("tcp", ":24224"); err == nil { defer ln.Close() go func() { for { - conn, err := ln.Accept() - if err != nil { - return - } - defer conn.Close() - if _, err = io.ReadAll(conn); err != nil { - continue - } + listener(ln) } }() } diff --git a/contrib/log/fluent/go.mod b/contrib/log/fluent/go.mod index 8b3a4efcd..cd2e6ff99 100644 --- a/contrib/log/fluent/go.mod +++ b/contrib/log/fluent/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/fluent/fluent-logger-golang v1.9.0 - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/kr/pretty v0.3.0 // indirect github.com/tinylib/msgp v1.1.6 // indirect ) diff --git a/contrib/log/logrus/go.mod b/contrib/log/logrus/go.mod index 5d923e1cf..75465145e 100644 --- a/contrib/log/logrus/go.mod +++ b/contrib/log/logrus/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/logrus/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/sirupsen/logrus v1.8.1 ) diff --git a/contrib/log/tencent/go.mod b/contrib/log/tencent/go.mod index d5a758f03..b102d7259 100644 --- a/contrib/log/tencent/go.mod +++ b/contrib/log/tencent/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2 google.golang.org/protobuf v1.28.0 ) diff --git a/contrib/log/tencent/tencent.go b/contrib/log/tencent/tencent.go index 8becf7883..3016926e0 100644 --- a/contrib/log/tencent/tencent.go +++ b/contrib/log/tencent/tencent.go @@ -14,8 +14,8 @@ import ( type Logger interface { log.Logger - GetProducer() *cls.AsyncProducerClient + GetProducer() *cls.AsyncProducerClient Close() error } @@ -66,25 +66,20 @@ func WithAccessSecret(as string) Option { type Option func(cls *options) func (log *tencentLog) Close() error { - err := log.producer.Close(5000) - return err + return log.producer.Close(5000) } func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error { - buf := level.String() - levelTitle := "level" - contents := make([]*cls.Log_Content, 0) + contents := make([]*cls.Log_Content, 0, len(keyvals)/2+1) contents = append(contents, &cls.Log_Content{ - Key: &levelTitle, - Value: &buf, + Key: newString(level.Key()), + Value: newString(level.String()), }) for i := 0; i < len(keyvals); i += 2 { - key := toString(keyvals[i]) - value := toString(keyvals[i+1]) contents = append(contents, &cls.Log_Content{ - Key: &key, - Value: &value, + Key: newString(toString(keyvals[i])), + Value: newString(toString(keyvals[i+1])), }) } @@ -92,8 +87,7 @@ func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error { Time: proto.Int64(time.Now().Unix()), Contents: contents, } - err := log.producer.SendLog(log.opts.topicID, logInst, nil) - return err + return log.producer.SendLog(log.opts.topicID, logInst, nil) } func NewLogger(options ...Option) (Logger, error) { @@ -115,6 +109,10 @@ func NewLogger(options ...Option) (Logger, error) { }, nil } +func newString(s string) *string { + return &s +} + // toString convert any type to string func toString(v interface{}) string { var key string @@ -125,23 +123,23 @@ func toString(v interface{}) string { case float64: key = strconv.FormatFloat(v, 'f', -1, 64) case float32: - key = strconv.FormatFloat(float64(v), 'f', -1, 64) + key = strconv.FormatFloat(float64(v), 'f', -1, 32) case int: key = strconv.Itoa(v) case uint: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int8: key = strconv.Itoa(int(v)) case uint8: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int16: key = strconv.Itoa(int(v)) case uint16: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int32: key = strconv.Itoa(int(v)) case uint32: - key = strconv.Itoa(int(v)) + key = strconv.FormatUint(uint64(v), 10) case int64: key = strconv.FormatInt(v, 10) case uint64: diff --git a/contrib/log/tencent/tencent_test.go b/contrib/log/tencent/tencent_test.go index b37c1b22c..76bc13bdd 100644 --- a/contrib/log/tencent/tencent_test.go +++ b/contrib/log/tencent/tencent_test.go @@ -1,6 +1,8 @@ package tencent import ( + "math" + "reflect" "testing" "github.com/go-kratos/kratos/v2/log" @@ -101,3 +103,45 @@ func TestLog(t *testing.T) { t.Errorf("Log() returns error:%v", err) } } + +func TestNewString(t *testing.T) { + ptr := newString("") + if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr { + t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind) + } +} + +func TestToString(t *testing.T) { + tests := []struct { + name string + in interface{} + out string + }{ + {"float64", 6.66, "6.66"}, + {"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll + {"float32", float32(6.66), "6.66"}, + {"max float32", math.MaxFloat32, "340282346638528860000000000000000000000"}, + {"int", int(math.MaxInt64), "9223372036854775807"}, + {"uint", uint(math.MaxUint64), "18446744073709551615"}, + {"int8", math.MaxInt8, "127"}, + {"uint8", math.MaxUint8, "255"}, + {"int16", math.MaxInt16, "32767"}, + {"uint16", math.MaxUint16, "65535"}, + {"int32", math.MaxInt32, "2147483647"}, + {"uint32", math.MaxUint32, "4294967295"}, + {"int64", math.MaxInt64, "9223372036854775807"}, + {"uint64", uint64(math.MaxUint64), "18446744073709551615"}, + {"string", "abc", "abc"}, + {"bool", false, "false"}, + {"[]byte", []byte("abc"), "abc"}, + {"struct", struct{ Name string }{}, `{"Name":""}`}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + out := toString(test.in) + if test.out != out { + t.Fatalf("want: %s, got: %s", test.out, out) + } + }) + } +} diff --git a/contrib/log/zap/go.mod b/contrib/log/zap/go.mod index 8f8d5a9a8..ad54dd222 100644 --- a/contrib/log/zap/go.mod +++ b/contrib/log/zap/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/zap/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 go.uber.org/zap v1.23.0 ) diff --git a/contrib/metrics/datadog/go.mod b/contrib/metrics/datadog/go.mod index 78f500398..42d434532 100644 --- a/contrib/metrics/datadog/go.mod +++ b/contrib/metrics/datadog/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/DataDog/datadog-go v4.8.3+incompatible github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 ) replace github.com/go-kratos/kratos/v2 => ../../../ diff --git a/contrib/metrics/prometheus/go.mod b/contrib/metrics/prometheus/go.mod index 462f13f17..4a31ccadd 100644 --- a/contrib/metrics/prometheus/go.mod +++ b/contrib/metrics/prometheus/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/metrics/prometheus/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/prometheus/client_golang v1.12.2 github.com/prometheus/common v0.37.0 ) diff --git a/contrib/opensergo/go.mod b/contrib/opensergo/go.mod index 1c96a2713..683f7850d 100644 --- a/contrib/opensergo/go.mod +++ b/contrib/opensergo/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/opensergo/v2 go 1.17 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/opensergo/opensergo-go v0.0.0-20220331070310-e5b01fee4d1c golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd diff --git a/contrib/opensergo/opensergo.go b/contrib/opensergo/opensergo.go index 112c0babe..e8f38c7bf 100644 --- a/contrib/opensergo/opensergo.go +++ b/contrib/opensergo/opensergo.go @@ -3,6 +3,7 @@ package opensergo import ( "encoding/json" "net" + "net/http" "net/url" "os" "strconv" @@ -186,15 +187,15 @@ func listDescriptors() (services []*v1.ServiceDescriptor, types []*v1.TypeDescri func HTTPPatternInfo(pattern interface{}) (method string, path string) { switch p := pattern.(type) { case *annotations.HttpRule_Get: - return "GET", p.Get + return http.MethodGet, p.Get case *annotations.HttpRule_Post: - return "POST", p.Post + return http.MethodPost, p.Post case *annotations.HttpRule_Delete: - return "DELETE", p.Delete + return http.MethodDelete, p.Delete case *annotations.HttpRule_Patch: - return "PATCH", p.Patch + return http.MethodPatch, p.Patch case *annotations.HttpRule_Put: - return "PUT", p.Put + return http.MethodPut, p.Put case *annotations.HttpRule_Custom: return p.Custom.Kind, p.Custom.Path default: diff --git a/contrib/opensergo/opensergo_test.go b/contrib/opensergo/opensergo_test.go index b63430e20..70ffef8fc 100644 --- a/contrib/opensergo/opensergo_test.go +++ b/contrib/opensergo/opensergo_test.go @@ -2,6 +2,7 @@ package opensergo import ( "net" + "net/http" "os" "path/filepath" "reflect" @@ -195,7 +196,7 @@ func TestHTTPPatternInfo(t *testing.T) { args: args{ pattern: &annotations.HttpRule_Get{Get: "/foo"}, }, - wantMethod: "GET", + wantMethod: http.MethodGet, wantPath: "/foo", }, { @@ -203,7 +204,7 @@ func TestHTTPPatternInfo(t *testing.T) { args: args{ pattern: &annotations.HttpRule_Post{Post: "/foo"}, }, - wantMethod: "POST", + wantMethod: http.MethodPost, wantPath: "/foo", }, { @@ -211,7 +212,7 @@ func TestHTTPPatternInfo(t *testing.T) { args: args{ pattern: &annotations.HttpRule_Put{Put: "/foo"}, }, - wantMethod: "PUT", + wantMethod: http.MethodPut, wantPath: "/foo", }, { @@ -219,7 +220,7 @@ func TestHTTPPatternInfo(t *testing.T) { args: args{ pattern: &annotations.HttpRule_Delete{Delete: "/foo"}, }, - wantMethod: "DELETE", + wantMethod: http.MethodDelete, wantPath: "/foo", }, { @@ -227,7 +228,7 @@ func TestHTTPPatternInfo(t *testing.T) { args: args{ pattern: &annotations.HttpRule_Patch{Patch: "/foo"}, }, - wantMethod: "PATCH", + wantMethod: http.MethodPatch, wantPath: "/foo", }, { diff --git a/contrib/registry/consul/go.mod b/contrib/registry/consul/go.mod index e78723c70..db17f9cc5 100644 --- a/contrib/registry/consul/go.mod +++ b/contrib/registry/consul/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/consul/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/hashicorp/consul/api v1.14.0 ) diff --git a/contrib/registry/consul/registry.go b/contrib/registry/consul/registry.go index d1c47d774..b2f2a3fe7 100644 --- a/contrib/registry/consul/registry.go +++ b/contrib/registry/consul/registry.go @@ -7,14 +7,14 @@ import ( "sync/atomic" "time" - "github.com/go-kratos/kratos/v2/registry" - "github.com/hashicorp/consul/api" + + "github.com/go-kratos/kratos/v2/registry" ) var ( - _ registry.Registrar = &Registry{} - _ registry.Discovery = &Registry{} + _ registry.Registrar = (*Registry)(nil) + _ registry.Discovery = (*Registry)(nil) ) // Option is consul registry option. diff --git a/contrib/registry/discovery/go.mod b/contrib/registry/discovery/go.mod index 40b61cb01..55728f7c3 100644 --- a/contrib/registry/discovery/go.mod +++ b/contrib/registry/discovery/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/discovery/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/go-resty/resty/v2 v2.7.0 github.com/pkg/errors v0.9.1 ) diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod index 1976385e1..c4c072ecb 100644 --- a/contrib/registry/etcd/go.mod +++ b/contrib/registry/etcd/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/etcd/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 go.etcd.io/etcd/client/v3 v3.5.4 google.golang.org/grpc v1.46.2 ) diff --git a/contrib/registry/etcd/registry.go b/contrib/registry/etcd/registry.go index 5592f62d2..ca858c993 100644 --- a/contrib/registry/etcd/registry.go +++ b/contrib/registry/etcd/registry.go @@ -12,8 +12,8 @@ import ( ) var ( - _ registry.Registrar = &Registry{} - _ registry.Discovery = &Registry{} + _ registry.Registrar = (*Registry)(nil) + _ registry.Discovery = (*Registry)(nil) ) // Option is etcd registry option. diff --git a/contrib/registry/eureka/client.go b/contrib/registry/eureka/client.go index f2b4e96f3..ab9eb30d2 100644 --- a/contrib/registry/eureka/client.go +++ b/contrib/registry/eureka/client.go @@ -14,14 +14,14 @@ import ( ) const ( - statusUp = "UP" - statusDown = "DOWN" - statusOutOfServeice = "OUT_OF_SERVICE" - heartbeatRetry = 3 - maxIdleConns = 100 - heartbeatTime = 10 - httpTimeout = 3 - refreshTime = 30 + statusUp = "UP" + statusDown = "DOWN" + statusOutOfService = "OUT_OF_SERVICE" + heartbeatRetry = 3 + maxIdleConns = 100 + heartbeatTime = 10 + httpTimeout = 3 + refreshTime = 30 ) type Endpoint struct { @@ -153,7 +153,7 @@ func NewClient(urls []string, opts ...ClientOption) *Client { func (e *Client) FetchApps(ctx context.Context) []Application { var m ApplicationsRootResponse - if err := e.do(ctx, "GET", []string{"apps"}, nil, &m); err != nil { + if err := e.do(ctx, http.MethodGet, []string{"apps"}, nil, &m); err != nil { return nil } @@ -161,7 +161,7 @@ func (e *Client) FetchApps(ctx context.Context) []Application { } func (e *Client) FetchAppInstances(ctx context.Context, appID string) (m Application, err error) { - err = e.do(ctx, "GET", []string{"apps", appID}, nil, &m) + err = e.do(ctx, http.MethodGet, []string{"apps", appID}, nil, &m) return } @@ -174,21 +174,21 @@ func (e *Client) FetchAppUpInstances(ctx context.Context, appID string) []Instan } func (e *Client) FetchAppInstance(ctx context.Context, appID string, instanceID string) (m Instance, err error) { - err = e.do(ctx, "GET", []string{"apps", appID, instanceID}, nil, &m) + err = e.do(ctx, http.MethodGet, []string{"apps", appID, instanceID}, nil, &m) return } func (e *Client) FetchInstance(ctx context.Context, instanceID string) (m Instance, err error) { - err = e.do(ctx, "GET", []string{"instances", instanceID}, nil, &m) + err = e.do(ctx, http.MethodGet, []string{"instances", instanceID}, nil, &m) return } func (e *Client) Out(ctx context.Context, appID, instanceID string) error { - return e.do(ctx, "PUT", []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusOutOfServeice)}, nil, nil) + return e.do(ctx, http.MethodPut, []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusOutOfService)}, nil, nil) } func (e *Client) Down(ctx context.Context, appID, instanceID string) error { - return e.do(ctx, "PUT", []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusDown)}, nil, nil) + return e.do(ctx, http.MethodPut, []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusDown)}, nil, nil) } func (e *Client) FetchAllUpInstances(ctx context.Context) []Instance { @@ -200,7 +200,7 @@ func (e *Client) Register(ctx context.Context, ep Endpoint) error { } func (e *Client) Deregister(ctx context.Context, appID, instanceID string) error { - if err := e.do(ctx, "DELETE", []string{"apps", appID, instanceID}, nil, nil); err != nil { + if err := e.do(ctx, http.MethodDelete, []string{"apps", appID, instanceID}, nil, nil); err != nil { return err } go e.cancelHeartbeat(appID) @@ -239,7 +239,7 @@ func (e *Client) registerEndpoint(ctx context.Context, ep Endpoint) error { if err != nil { return err } - return e.do(ctx, "POST", []string{"apps", ep.AppID}, bytes.NewReader(body), nil) + return e.do(ctx, http.MethodPost, []string{"apps", ep.AppID}, bytes.NewReader(body), nil) } func (e *Client) Heartbeat(ep Endpoint) { @@ -257,7 +257,7 @@ func (e *Client) Heartbeat(ep Endpoint) { case <-e.keepalive[ep.AppID]: return case <-ticker.C: - if err := e.do(e.ctx, "PUT", []string{"apps", ep.AppID, ep.InstanceID}, nil, nil); err != nil { + if err := e.do(e.ctx, http.MethodPut, []string{"apps", ep.AppID, ep.InstanceID}, nil, nil); err != nil { if retryCount++; retryCount > heartbeatRetry { _ = e.registerEndpoint(e.ctx, ep) retryCount = 0 @@ -268,8 +268,8 @@ func (e *Client) Heartbeat(ep Endpoint) { } func (e *Client) cancelHeartbeat(appID string) { - defer e.lock.Unlock() e.lock.Lock() + defer e.lock.Unlock() if ch, ok := e.keepalive[appID]; ok { ch <- struct{}{} } @@ -307,39 +307,50 @@ func (e *Client) buildAPI(currentTimes int, params ...string) string { return strings.Join(params, "/") } -func (e *Client) do(ctx context.Context, method string, params []string, input io.Reader, output interface{}) error { - for i := 0; i < e.maxRetry; i++ { - request, err := http.NewRequest(method, e.buildAPI(i, params...), input) +func (e *Client) request(ctx context.Context, method string, params []string, input io.Reader, output interface{}, i int) (bool, error) { + request, err := http.NewRequestWithContext(ctx, method, e.buildAPI(i, params...), input) + if err != nil { + return false, err + } + request.Header.Add("User-Agent", "go-eureka-client") + request.Header.Add("Accept", "application/json;charset=UTF-8") + request.Header.Add("Content-Type", "application/json;charset=UTF-8") + resp, err := e.client.Do(request) + if err != nil { + return true, err + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + + if output != nil && resp.StatusCode/100 == 2 { + data, err := io.ReadAll(resp.Body) if err != nil { - return err + return false, err } - request = request.WithContext(ctx) - request.Header.Add("User-Agent", "go-eureka-client") - request.Header.Add("Accept", "application/json;charset=UTF-8") - request.Header.Add("Content-Type", "application/json;charset=UTF-8") - resp, err := e.client.Do(request) + err = json.Unmarshal(data, output) if err != nil { - continue - } - defer func() { - _, _ = io.Copy(io.Discard, resp.Body) - resp.Body.Close() - }() - - if output != nil && resp.StatusCode/100 == 2 { - data, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - if err = json.Unmarshal(data, output); err != nil { - return err - } + return false, err } + } - if resp.StatusCode >= http.StatusBadRequest { - return fmt.Errorf("response Error %d", resp.StatusCode) - } + if resp.StatusCode >= http.StatusBadRequest { + return false, fmt.Errorf("response Error %d", resp.StatusCode) + } + return false, nil +} + +func (e *Client) do(ctx context.Context, method string, params []string, input io.Reader, output interface{}) error { + for i := 0; i < e.maxRetry; i++ { + retry, err := e.request(ctx, method, params, input, output, i) + if retry { + continue + } + if err != nil { + return err + } return nil } return fmt.Errorf("retry after %d times", e.maxRetry) diff --git a/contrib/registry/eureka/register.go b/contrib/registry/eureka/register.go index 9588df641..242ec9105 100644 --- a/contrib/registry/eureka/register.go +++ b/contrib/registry/eureka/register.go @@ -11,8 +11,8 @@ import ( ) var ( - _ registry.Registrar = &Registry{} - _ registry.Discovery = &Registry{} + _ registry.Registrar = (*Registry)(nil) + _ registry.Discovery = (*Registry)(nil) ) type Option func(o *Registry) diff --git a/contrib/registry/kubernetes/go.mod b/contrib/registry/kubernetes/go.mod index 3f20affb1..21517f5fb 100644 --- a/contrib/registry/kubernetes/go.mod +++ b/contrib/registry/kubernetes/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/json-iterator/go v1.1.12 k8s.io/api v0.24.3 k8s.io/apimachinery v0.24.3 diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod index d6048dfc0..75f673346 100644 --- a/contrib/registry/nacos/go.mod +++ b/contrib/registry/nacos/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/nacos/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/nacos-group/nacos-sdk-go v1.0.9 ) diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod index 306fe9275..f70157cca 100644 --- a/contrib/registry/polaris/go.mod +++ b/contrib/registry/polaris/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/polaris/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/polarismesh/polaris-go v1.1.0 ) diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod index 09c35a1b9..719a78de0 100644 --- a/contrib/registry/zookeeper/go.mod +++ b/contrib/registry/zookeeper/go.mod @@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/zookeeper/v2 go 1.16 require ( - github.com/go-kratos/kratos/v2 v2.5.1 + github.com/go-kratos/kratos/v2 v2.5.2 github.com/go-zookeeper/zk v1.0.3 golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 ) diff --git a/contrib/registry/zookeeper/register.go b/contrib/registry/zookeeper/register.go index 771a5bbc4..8f21745d1 100644 --- a/contrib/registry/zookeeper/register.go +++ b/contrib/registry/zookeeper/register.go @@ -12,8 +12,8 @@ import ( ) var ( - _ registry.Registrar = &Registry{} - _ registry.Discovery = &Registry{} + _ registry.Registrar = (*Registry)(nil) + _ registry.Discovery = (*Registry)(nil) ) // Option is etcd registry option. diff --git a/log/level.go b/log/level.go index 22f41c787..1a9664236 100644 --- a/log/level.go +++ b/log/level.go @@ -21,6 +21,10 @@ const ( LevelFatal ) +func (l Level) Key() string { + return LevelKey +} + func (l Level) String() string { switch l { case LevelDebug: diff --git a/log/level_test.go b/log/level_test.go index d36882912..193503c68 100644 --- a/log/level_test.go +++ b/log/level_test.go @@ -2,6 +2,12 @@ package log import "testing" +func TestLevel_Key(t *testing.T) { + if LevelInfo.Key() != LevelKey { + t.Errorf("want: %s, got: %s", LevelKey, LevelInfo.Key()) + } +} + func TestLevel_String(t *testing.T) { tests := []struct { name string diff --git a/middleware/auth/jwt/jwt_test.go b/middleware/auth/jwt/jwt_test.go index 188744b01..711757bcf 100644 --- a/middleware/auth/jwt/jwt_test.go +++ b/middleware/auth/jwt/jwt_test.go @@ -254,7 +254,7 @@ func TestServer(t *testing.T) { } if test.exceptErr == nil { if testToken == nil { - t.Errorf("except testToken not nil, but got nil") + t.Fatal("except testToken not nil, but got nil") } _, ok := testToken.(jwt.MapClaims) if !ok { @@ -493,3 +493,26 @@ func TestClientMissKey(t *testing.T) { } }) } + +func TestNewContextAndFromContext(t *testing.T) { + tests := []struct { + name string + claims jwt.MapClaims + }{ + {"val not nil", jwt.MapClaims{"name": "kratos"}}, + {"val nil", nil}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ctx := NewContext(context.Background(), test.claims) + + claims, ok := FromContext(ctx) + if !ok { + t.Fatal("ctx not found authKey{}") + } + if !reflect.DeepEqual(test.claims, claims) { + t.Errorf(`want: %s, got: %v`, test.claims, claims) + } + }) + } +} diff --git a/middleware/logging/logging_test.go b/middleware/logging/logging_test.go index 6ad1a02c9..431d89014 100644 --- a/middleware/logging/logging_test.go +++ b/middleware/logging/logging_test.go @@ -111,7 +111,7 @@ func (d *dummyStringer) String() string { return "my value" } -func Test_extractArgs(t *testing.T) { +func TestExtractArgs(t *testing.T) { if extractArgs(&dummyStringer{field: ""}) != "my value" { t.Errorf(`The stringified dummyStringer structure must be equal to "my value", %v given`, extractArgs(&dummyStringer{field: ""})) } @@ -120,3 +120,30 @@ func Test_extractArgs(t *testing.T) { t.Errorf(`The stringified dummy structure must be equal to "&{field:value}", %v given`, extractArgs(&dummy{field: "value"})) } } + +func TestExtractError(t *testing.T) { + tests := []struct { + name string + err error + wantLevel log.Level + wantErrStr string + }{ + { + "no error", nil, log.LevelInfo, "", + }, + { + "error", errors.New("test error"), log.LevelError, "test error", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + level, errStr := extractError(test.err) + if level != test.wantLevel { + t.Errorf("want: %d, got: %d", test.wantLevel, level) + } + if errStr != test.wantErrStr { + t.Errorf("want: %s, got: %s", test.wantErrStr, errStr) + } + }) + } +} diff --git a/middleware/metadata/metadata.go b/middleware/metadata/metadata.go index 5c29189f9..da9e43a96 100644 --- a/middleware/metadata/metadata.go +++ b/middleware/metadata/metadata.go @@ -51,16 +51,19 @@ func Server(opts ...Option) middleware.Middleware { } return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (reply interface{}, err error) { - if tr, ok := transport.FromServerContext(ctx); ok { - md := options.md.Clone() - header := tr.RequestHeader() - for _, k := range header.Keys() { - if options.hasPrefix(k) { - md.Set(k, header.Get(k)) - } + tr, ok := transport.FromServerContext(ctx) + if !ok { + return handler(ctx, req) + } + + md := options.md.Clone() + header := tr.RequestHeader() + for _, k := range header.Keys() { + if options.hasPrefix(k) { + md.Set(k, header.Get(k)) } - ctx = metadata.NewServerContext(ctx, md) } + ctx = metadata.NewServerContext(ctx, md) return handler(ctx, req) } } @@ -76,25 +79,28 @@ func Client(opts ...Option) middleware.Middleware { } return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (reply interface{}, err error) { - if tr, ok := transport.FromClientContext(ctx); ok { - header := tr.RequestHeader() - // x-md-local- - for k, v := range options.md { + tr, ok := transport.FromClientContext(ctx) + if !ok { + return handler(ctx, req) + } + + header := tr.RequestHeader() + // x-md-local- + for k, v := range options.md { + header.Set(k, v) + } + if md, ok := metadata.FromClientContext(ctx); ok { + for k, v := range md { header.Set(k, v) } - if md, ok := metadata.FromClientContext(ctx); ok { - for k, v := range md { + } + // x-md-global- + if md, ok := metadata.FromServerContext(ctx); ok { + for k, v := range md { + if options.hasPrefix(k) { header.Set(k, v) } } - // x-md-global- - if md, ok := metadata.FromServerContext(ctx); ok { - for k, v := range md { - if options.hasPrefix(k) { - header.Set(k, v) - } - } - } } return handler(ctx, req) } diff --git a/middleware/metadata/metadata_test.go b/middleware/metadata/metadata_test.go index e46a94f50..b083f9c10 100644 --- a/middleware/metadata/metadata_test.go +++ b/middleware/metadata/metadata_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "net/http" + "reflect" "testing" "github.com/go-kratos/kratos/v2/metadata" @@ -33,15 +34,18 @@ func (tr *testTransport) Operation() string { return "" } func (tr *testTransport) RequestHeader() transport.Header { return tr.header } func (tr *testTransport) ReplyHeader() transport.Header { return tr.header } +var ( + globalKey = "x-md-global-key" + globalValue = "global-value" + localKey = "x-md-local-key" + localValue = "local-value" + customKey = "x-md-local-custom" + customValue = "custom-value" + constKey = "x-md-local-const" + constValue = "x-md-local-const" +) + func TestSever(t *testing.T) { - var ( - globalKey = "x-md-global-key" - globalValue = "global-value" - localKey = "x-md-local-key" - localValue = "local-value" - constKey = "x-md-local-const" - constValue = "x-md-local-const" - ) hs := func(ctx context.Context, in interface{}) (interface{}, error) { md, ok := metadata.FromServerContext(ctx) if !ok { @@ -75,16 +79,6 @@ func TestSever(t *testing.T) { } func TestClient(t *testing.T) { - var ( - globalKey = "x-md-global-key" - globalValue = "global-value" - localKey = "x-md-local-key" - localValue = "local-value" - customKey = "x-md-local-custom" - customValue = "custom-value" - constKey = "x-md-local-const" - constValue = "x-md-local-const" - ) hs := func(ctx context.Context, in interface{}) (interface{}, error) { tr, ok := transport.FromClientContext(ctx) if !ok { @@ -127,13 +121,52 @@ func TestClient(t *testing.T) { } } -func Test_WithPropagatedPrefix(t *testing.T) { - o := &options{ +func TestWithConstants(t *testing.T) { + md := metadata.Metadata{ + constKey: constValue, + } + options := &options{ + md: metadata.Metadata{ + "override": "override", + }, + } + + WithConstants(md)(options) + if !reflect.DeepEqual(md, options.md) { + t.Errorf("want: %v, got: %v", md, options.md) + } +} + +func TestOptions_WithPropagatedPrefix(t *testing.T) { + options := &options{ prefix: []string{"override"}, } - WithPropagatedPrefix("something", "another")(o) + prefixes := []string{"something", "another"} - if len(o.prefix) != 2 { + WithPropagatedPrefix(prefixes...)(options) + if !reflect.DeepEqual(prefixes, options.prefix) { t.Error("The prefix must be overridden.") } } + +func TestOptions_hasPrefix(t *testing.T) { + tests := []struct { + name string + options *options + key string + exists bool + }{ + {"exists key upper", &options{prefix: []string{"prefix"}}, "PREFIX_true", true}, + {"exists key lower", &options{prefix: []string{"prefix"}}, "prefix_true", true}, + {"not exists key upper", &options{prefix: []string{"prefix"}}, "false_PREFIX", false}, + {"not exists key lower", &options{prefix: []string{"prefix"}}, "false_prefix", false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + exists := test.options.hasPrefix(test.key) + if test.exists != exists { + t.Errorf("key: '%sr', not exists prefixs: %v", test.key, test.options.prefix) + } + }) + } +} diff --git a/selector/node/ewma/node.go b/selector/node/ewma/node.go index 4fed4aaa2..3b8d2a02c 100644 --- a/selector/node/ewma/node.go +++ b/selector/node/ewma/node.go @@ -4,6 +4,7 @@ import ( "container/list" "context" "math" + "net" "sync" "sync/atomic" "time" @@ -158,8 +159,9 @@ func (n *Node) Pick() selector.DoneFunc { if n.errHandler != nil && n.errHandler(di.Err) { success = 0 } + var netErr net.Error if errors.Is(context.DeadlineExceeded, di.Err) || errors.Is(context.Canceled, di.Err) || - errors.IsServiceUnavailable(di.Err) || errors.IsGatewayTimeout(di.Err) { + errors.IsServiceUnavailable(di.Err) || errors.IsGatewayTimeout(di.Err) || errors.As(di.Err, &netErr) { success = 0 } } diff --git a/selector/node/ewma/node_test.go b/selector/node/ewma/node_test.go index feac09f28..d930495c3 100644 --- a/selector/node/ewma/node_test.go +++ b/selector/node/ewma/node_test.go @@ -2,6 +2,7 @@ package ewma import ( "context" + "net" "reflect" "testing" "time" @@ -100,11 +101,15 @@ func TestDirectErrorHandler(t *testing.T) { Endpoints: []string{"http://127.0.0.1:9090"}, Metadata: map[string]string{"weight": "10"}, })) - + errs := []error{ + context.DeadlineExceeded, + context.Canceled, + net.ErrClosed, + } for i := 0; i < 5; i++ { var err error if i != 0 { - err = context.DeadlineExceeded + err = errs[i%len(errs)] } done := wn.Pick() if done == nil { diff --git a/transport/grpc/balancer.go b/transport/grpc/balancer.go index 948b736bb..f42dc23bd 100644 --- a/transport/grpc/balancer.go +++ b/transport/grpc/balancer.go @@ -1,13 +1,13 @@ package grpc import ( - "github.com/go-kratos/kratos/v2/registry" - "github.com/go-kratos/kratos/v2/selector" - "github.com/go-kratos/kratos/v2/transport" - "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/base" "google.golang.org/grpc/metadata" + + "github.com/go-kratos/kratos/v2/registry" + "github.com/go-kratos/kratos/v2/selector" + "github.com/go-kratos/kratos/v2/transport" ) const ( @@ -15,8 +15,8 @@ const ( ) var ( - _ base.PickerBuilder = &balancerBuilder{} - _ balancer.Picker = &balancerPicker{} + _ base.PickerBuilder = (*balancerBuilder)(nil) + _ balancer.Picker = (*balancerPicker)(nil) ) func init() { diff --git a/transport/http/binding/bind_test.go b/transport/http/binding/bind_test.go index 20aadba7f..6cd8b6d5a 100644 --- a/transport/http/binding/bind_test.go +++ b/transport/http/binding/bind_test.go @@ -96,7 +96,7 @@ func TestBindForm(t *testing.T) { { name: "error not nil", args: args{ - req: &http.Request{Method: "POST"}, + req: &http.Request{Method: http.MethodPost}, target: &p1, }, wantErr: true, @@ -106,7 +106,7 @@ func TestBindForm(t *testing.T) { name: "error is nil", args: args{ req: &http.Request{ - Method: "POST", + Method: http.MethodPost, Header: http.Header{"Content-Type": {"application/x-www-form-urlencoded; param=value"}}, Body: io.NopCloser(strings.NewReader("name=kratos&url=https://go-kratos.dev/")), }, @@ -119,7 +119,7 @@ func TestBindForm(t *testing.T) { name: "error BadRequest", args: args{ req: &http.Request{ - Method: "POST", + Method: http.MethodPost, Header: http.Header{"Content-Type": {"application/x-www-form-urlencoded; param=value"}}, Body: io.NopCloser(strings.NewReader("age=a")), }, diff --git a/transport/http/client_test.go b/transport/http/client_test.go index ab8031dd5..9a0dd7829 100644 --- a/transport/http/client_test.go +++ b/transport/http/client_test.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "log" + "net/http" nethttp "net/http" "reflect" "strconv" @@ -348,18 +349,18 @@ func TestNewClient(t *testing.T) { t.Error(err) } - err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{}) + err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{}) if err == nil { t.Error("err should not be equal to nil") } - err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{needErr: true}) + err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{needErr: true}) if err == nil { t.Error("err should be equal to callOption err") } client.opts.encoder = func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) { return nil, errors.New("mock test encoder error") } - err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}) + err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}) if err == nil { t.Error("err should be equal to encoder error") } diff --git a/transport/http/context_test.go b/transport/http/context_test.go index daccccd95..6cae1b9ad 100644 --- a/transport/http/context_test.go +++ b/transport/http/context_test.go @@ -30,7 +30,7 @@ func TestContextHeader(t *testing.T) { func TestContextForm(t *testing.T) { w := wrapper{ router: testRouter, - req: &http.Request{Header: map[string][]string{"name": {"kratos"}}, Method: "POST"}, + req: &http.Request{Header: map[string][]string{"name": {"kratos"}}, Method: http.MethodPost}, res: nil, w: responseWriter{}, } @@ -54,7 +54,7 @@ func TestContextForm(t *testing.T) { func TestContextQuery(t *testing.T) { w := wrapper{ router: testRouter, - req: &http.Request{URL: &url.URL{Scheme: "https", Host: "github.com", Path: "go-kratos/kratos", RawQuery: "page=1"}, Method: "POST"}, + req: &http.Request{URL: &url.URL{Scheme: "https", Host: "github.com", Path: "go-kratos/kratos", RawQuery: "page=1"}, Method: http.MethodPost}, res: nil, w: responseWriter{}, } @@ -65,7 +65,7 @@ func TestContextQuery(t *testing.T) { } func TestContextRequest(t *testing.T) { - req := &http.Request{Method: "POST"} + req := &http.Request{Method: http.MethodPost} w := wrapper{ router: testRouter, req: req, @@ -82,7 +82,7 @@ func TestContextResponse(t *testing.T) { res := httptest.NewRecorder() w := wrapper{ router: &Router{srv: &Server{enc: DefaultResponseEncoder}}, - req: &http.Request{Method: "POST"}, + req: &http.Request{Method: http.MethodPost}, res: res, w: responseWriter{200, res}, } @@ -173,7 +173,7 @@ func TestContextResponseReturn(t *testing.T) { func TestContextCtx(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - req := &http.Request{Method: "POST"} + req := &http.Request{Method: http.MethodPost} req = req.WithContext(ctx) w := wrapper{ router: testRouter, diff --git a/transport/http/redirect_test.go b/transport/http/redirect_test.go index b98bf4f0b..879966a4b 100644 --- a/transport/http/redirect_test.go +++ b/transport/http/redirect_test.go @@ -1,6 +1,7 @@ package http import ( + "net/http" "net/http/httptest" "testing" ) @@ -10,7 +11,7 @@ func TestRedirect(t *testing.T) { redirectURL = "/redirect" redirectCode = 302 ) - r := httptest.NewRequest("POST", "/test", nil) + r := httptest.NewRequest(http.MethodPost, "/test", nil) w := httptest.NewRecorder() _ = DefaultResponseEncoder(w, r, NewRedirect(redirectURL, redirectCode)) diff --git a/transport/http/router_test.go b/transport/http/router_test.go index ad37831d1..747ebf059 100644 --- a/transport/http/router_test.go +++ b/transport/http/router_test.go @@ -136,7 +136,7 @@ func testRoute(t *testing.T, srv *Server) { t.Fatalf("got %s want bar", u.Name) } // PUT - req, _ := http.NewRequest("PUT", base+"/users", strings.NewReader(`{"name":"bar"}`)) + req, _ := http.NewRequest(http.MethodPut, base+"/users", strings.NewReader(`{"name":"bar"}`)) req.Header.Set("Content-Type", appJSONStr) resp, err = http.DefaultClient.Do(req) if err != nil { @@ -157,7 +157,7 @@ func testRoute(t *testing.T, srv *Server) { t.Fatalf("got %s want bar", u.Name) } // OPTIONS - req, _ = http.NewRequest("OPTIONS", base+"/users", nil) + req, _ = http.NewRequest(http.MethodOptions, base+"/users", nil) resp, err = http.DefaultClient.Do(req) if err != nil { t.Fatal(err) @@ -166,7 +166,7 @@ func testRoute(t *testing.T, srv *Server) { if resp.StatusCode != 200 { t.Fatalf("code: %d", resp.StatusCode) } - if resp.Header.Get("Access-Control-Allow-Methods") != "OPTIONS" { + if resp.Header.Get("Access-Control-Allow-Methods") != http.MethodOptions { t.Fatal("cors failed") } } diff --git a/transport/http/server.go b/transport/http/server.go index b756a0f80..165bb99bc 100644 --- a/transport/http/server.go +++ b/transport/http/server.go @@ -128,6 +128,13 @@ func Listener(lis net.Listener) ServerOption { } } +// PathPrefix with mux's PathPrefix, router will replaced by a subrouter that start with prefix. +func PathPrefix(prefix string) ServerOption { + return func(s *Server) { + s.router = s.router.PathPrefix(prefix).Subrouter() + } +} + // Server is an HTTP server wrapper. type Server struct { *http.Server @@ -162,11 +169,12 @@ func NewServer(opts ...ServerOption) *Server { enc: DefaultResponseEncoder, ene: DefaultErrorEncoder, strictSlash: true, + router: mux.NewRouter(), } for _, o := range opts { o(srv) } - srv.router = mux.NewRouter().StrictSlash(srv.strictSlash) + srv.router.StrictSlash(srv.strictSlash) srv.router.NotFoundHandler = http.DefaultServeMux srv.router.MethodNotAllowedHandler = http.DefaultServeMux srv.router.Use(srv.filter()) diff --git a/transport/http/server_test.go b/transport/http/server_test.go index ff9b3918c..22865fc33 100644 --- a/transport/http/server_test.go +++ b/transport/http/server_test.go @@ -117,8 +117,8 @@ func testAccept(t *testing.T, srv *Server) { path string contentType string }{ - {"GET", "/errors/cause", "application/json"}, - {"GET", "/errors/cause", "application/proto"}, + {http.MethodGet, "/errors/cause", "application/json"}, + {http.MethodGet, "/errors/cause", "application/proto"}, } e, err := srv.Endpoint() if err != nil { @@ -154,7 +154,7 @@ func testHeader(t *testing.T, srv *Server) { t.Errorf("expected nil got %v", err) } reqURL := fmt.Sprintf(e.String() + "/index") - req, err := http.NewRequest("GET", reqURL, nil) + req, err := http.NewRequest(http.MethodGet, reqURL, nil) if err != nil { t.Errorf("expected nil got %v", err) } @@ -172,21 +172,21 @@ func testClient(t *testing.T, srv *Server) { path string code int }{ - {"GET", "/index", http.StatusOK}, - {"PUT", "/index", http.StatusOK}, - {"POST", "/index", http.StatusOK}, - {"PATCH", "/index", http.StatusOK}, - {"DELETE", "/index", http.StatusOK}, + {http.MethodGet, "/index", http.StatusOK}, + {http.MethodPut, "/index", http.StatusOK}, + {http.MethodPost, "/index", http.StatusOK}, + {http.MethodPatch, "/index", http.StatusOK}, + {http.MethodDelete, "/index", http.StatusOK}, - {"GET", "/index/1", http.StatusOK}, - {"PUT", "/index/1", http.StatusOK}, - {"POST", "/index/1", http.StatusOK}, - {"PATCH", "/index/1", http.StatusOK}, - {"DELETE", "/index/1", http.StatusOK}, + {http.MethodGet, "/index/1", http.StatusOK}, + {http.MethodPut, "/index/1", http.StatusOK}, + {http.MethodPost, "/index/1", http.StatusOK}, + {http.MethodPatch, "/index/1", http.StatusOK}, + {http.MethodDelete, "/index/1", http.StatusOK}, - {"GET", "/index/notfound", http.StatusNotFound}, - {"GET", "/errors/cause", http.StatusBadRequest}, - {"GET", "/test/prefix/123111", http.StatusOK}, + {http.MethodGet, "/index/notfound", http.StatusNotFound}, + {http.MethodGet, "/errors/cause", http.StatusBadRequest}, + {http.MethodGet, "/test/prefix/123111", http.StatusOK}, } e, err := srv.Endpoint() if err != nil { @@ -273,7 +273,7 @@ func BenchmarkServer(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { var res testData - err := client.Invoke(context.Background(), "POST", "/index", nil, &res) + err := client.Invoke(context.Background(), http.MethodPost, "/index", nil, &res) if err != nil { b.Errorf("expected nil got %v", err) } diff --git a/version.go b/version.go index 2c8d6f462..e130ae2cc 100644 --- a/version.go +++ b/version.go @@ -1,4 +1,4 @@ package kratos // Release is the current kratos version. -const Release = "v2.5.1" +const Release = "v2.5.2"