Repository: go-kratos/kratos
Pull request #2248 (2022-08-01 18:27:41)

build(deps): bump google.golang.org/protobuf from 1.28.0 to 1.28.1 in /contrib/opensergo
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.28.0 to 1.28.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/protocolbuffers/protobuf-go/releases">google.golang.org/protobuf's releases</a>.</em></p>
<blockquote>
<h2>v1.28.1</h2>
<p>This release contains protoc-gen-go binaries for arm64.</p>
<p>Notable changes since <a href="https://github.com/protocolbuffers/protobuf-go/releases/tag/v1.28.0">v1.28.0</a>:</p>
<ul>
<li><a href="https://golang.org/cl/418677">CL/418677</a>: internal/impl: improve MessageInfo.New performance</li>
<li><a href="https://golang.org/cl/411377">CL/411377</a>: proto: short-circuit Equal when inputs are identical</li>
<li><a href="https://golang.org/cl/419714">CL/419714</a>: all: Add prebuild binaries for arm64</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/6875c3d7242d1a3db910ce8a504f124cb840c23a"><code>6875c3d</code></a> all: release v1.28.1</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/881da6ece0696714305aee39afcac17b6abe8e00"><code>881da6e</code></a> all: Add prebuild binaries for arm64</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/2a74a0e82391d1fc344067bc6bfc4647cd8ae7d9"><code>2a74a0e</code></a> A+C: delete AUTHORS and CONTRIBUTORS</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/de9682ad1656cd1ee6808865f7a42f5a5d79eb73"><code>de9682a</code></a> internal/impl: improve MessageInfo.New performance</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/b0a944684d78a6b7c1f2bb6864fa910385d5b97a"><code>b0a9446</code></a> all: reformat with go1.19 gofmt</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/c1bbc5d45b2b8a056496c3db183b24e7f9a22ff1"><code>c1bbc5d</code></a> all: make integration test work on darwin/arm64</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/5f429f7042ff6743d1cd695281802b8c9b8d9395"><code>5f429f7</code></a> proto: fix compilation failure in tests</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/fc44d00d5a99973a6deb0863d6aaa7446c016066"><code>fc44d00</code></a> proto: use reflect.Ptr for backward compatibility</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/380c339ec12310c04cd1c399669ab0bce57b6cd6"><code>380c339</code></a> proto: short-circuit Equal when inputs are identical</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go/commit/784c4825545540dc41a1dc85715d3251903bc8ce"><code>784c482</code></a> all: remove shorthand import aliases</li>
<li>Additional commits viewable in <a href="https://github.com/protocolbuffers/protobuf-go/compare/v1.28.0...v1.28.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/protobuf&package-manager=go_modules&previous-version=1.28.0&new-version=1.28.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

codecov-commenter: # [Codecov](https://codecov.io/gh/go-kratos/kratos/pull/2248?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) Report
> Merging [#2248](https://codecov.io/gh/go-kratos/kratos/pull/2248?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (f5d7831) into [main](https://codecov.io/gh/go-kratos/kratos/commit/fea863e7837e808af0a1918cd1f8927fa76585aa?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (fea863e) will **decrease** coverage by `0.05%`.
> The diff coverage is `n/a`.

```diff
@@            Coverage Diff             @@
##             main    #2248      +/-   ##
==========================================
- Coverage   85.61%   85.56%   -0.06%     
==========================================
  Files          87       87              
  Lines        3789     3789              
==========================================
- Hits         3244     3242       -2     
- Misses        378      380       +2     
  Partials      167      167              
```


| [Impacted Files](https://codecov.io/gh/go-kratos/kratos/pull/2248?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) | Coverage Δ | |
|---|---|---|
| [internal/context/context.go](https://codecov.io/gh/go-kratos/kratos/pull/2248/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos#diff-aW50ZXJuYWwvY29udGV4dC9jb250ZXh0Lmdv) | `97.01% <0.00%> (-2.99%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos).


Patch:
diff --git a/README.md b/README.md
index f4023812..815be2fc 100644
--- a/README.md
+++ b/README.md
@@ -90,7 +90,6 @@ If you discover a security vulnerability within Kratos, please send an e-mail to
 - [Wechat Group](https://github.com/go-kratos/kratos/issues/682)
 - [Discord Group](https://discord.gg/BWzJsUJ)
 - [go-kratos.dev](https://go-kratos.dev/en)
-- QQ Group: 716486124
 
 ## Contributors
 
diff --git a/api/metadata/server.go b/api/metadata/server.go
index 3438d132..50f90f61 100644
--- a/api/metadata/server.go
+++ b/api/metadata/server.go
@@ -105,7 +105,10 @@ func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*Li
 	if err := s.load(); err != nil {
 		return nil, err
 	}
-	reply := new(ListServicesReply)
+	reply := &ListServicesReply{
+		Services: make([]string, 0, len(s.services)),
+		Methods:  make([]string, 0, len(s.methods)),
+	}
 	for name := range s.services {
 		reply.Services = append(reply.Services, name)
 	}
diff --git a/cmd/kratos/internal/base/repo.go b/cmd/kratos/internal/base/repo.go
index 55b12ac0..bdcb3f01 100644
--- a/cmd/kratos/internal/base/repo.go
+++ b/cmd/kratos/internal/base/repo.go
@@ -3,13 +3,15 @@ package base
 import (
 	"context"
 	"fmt"
-	stdurl "net/url"
+	"net"
 	"os"
 	"os/exec"
 	"path"
 	"strings"
 )
 
+var unExpandVarPath = []string{"~", ".", ".."}
+
 // Repo is git repository manager.
 type Repo struct {
 	url    string
@@ -18,27 +20,21 @@ type Repo struct {
 }
 
 func repoDir(url string) string {
-	if !strings.Contains(url, "//") {
-		url = "//" + url
-	}
-	if strings.HasPrefix(url, "//git@") {
-		url = "ssh:" + url
-	} else if strings.HasPrefix(url, "//") {
-		url = "https:" + url
+	vcsURL, err := ParseVCSUrl(url)
+	if err != nil {
+		return url
 	}
-	u, err := stdurl.Parse(url)
-	if err == nil {
-		url = fmt.Sprintf("%s://%s%s", u.Scheme, u.Hostname(), u.Path)
+	// check host contains port
+	host, _, err := net.SplitHostPort(vcsURL.Host)
+	if err != nil {
+		host = vcsURL.Host
 	}
-	var start int
-	start = strings.Index(url, "//")
-	if start == -1 {
-		start = strings.Index(url, ":") + 1
-	} else {
-		start += 2
+	for _, p := range unExpandVarPath {
+		host = strings.TrimLeft(host, p)
 	}
-	end := strings.LastIndex(url, "/")
-	return url[start:end]
+	dir := path.Base(path.Dir(vcsURL.Path))
+	url = fmt.Sprintf("%s/%s", host, dir)
+	return url
 }
 
 // NewRepo new a repository manager.
diff --git a/cmd/kratos/internal/base/vcs_url.go b/cmd/kratos/internal/base/vcs_url.go
new file mode 100644
index 00000000..ef76db30
--- /dev/null
+++ b/cmd/kratos/internal/base/vcs_url.go
@@ -0,0 +1,58 @@
+package base
+
+import (
+	"errors"
+	"net/url"
+	"regexp"
+	"strings"
+)
+
+var (
+	scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
+	scheme      = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
+)
+
+// ParseVCSUrl ref https://github.com/golang/go/blob/master/src/cmd/go/internal/vcs/vcs.go
+// see https://go-review.googlesource.com/c/go/+/12226/
+// git url define https://git-scm.com/docs/git-clone#_git_urls
+func ParseVCSUrl(repo string) (*url.URL, error) {
+	var (
+		repoURL *url.URL
+		err     error
+	)
+
+	if m := scpSyntaxRe.FindStringSubmatch(repo); m != nil {
+		// Match SCP-like syntax and convert it to a URL.
+		// Eg, "git@github.com:user/repo" becomes
+		// "ssh://git@github.com/user/repo".
+		repoURL = &url.URL{
+			Scheme: "ssh",
+			User:   url.User(m[1]),
+			Host:   m[2],
+			Path:   m[3],
+		}
+	} else {
+		if !strings.Contains(repo, "//") {
+			repo = "//" + repo
+		}
+		if strings.HasPrefix(repo, "//git@") {
+			repo = "ssh:" + repo
+		} else if strings.HasPrefix(repo, "//") {
+			repo = "https:" + repo
+		}
+		repoURL, err = url.Parse(repo)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Iterate over insecure schemes too, because this function simply
+	// reports the state of the repo. If we can't see insecure schemes then
+	// we can't report the actual repo URL.
+	for _, s := range scheme {
+		if repoURL.Scheme == s {
+			return repoURL, nil
+		}
+	}
+	return nil, errors.New("unable to parse repo url")
+}
diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go
index 3eb91c06..cebbb6b1 100644
--- a/cmd/protoc-gen-go-http/http.go
+++ b/cmd/protoc-gen-go-http/http.go
@@ -213,9 +213,9 @@ 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)
 	}
-	res = make(map[string]*string)
 	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 {
 		name := strings.TrimSpace(m[1])
 		if len(name) > 1 && len(m[2]) > 0 {
diff --git a/config/env/env.go b/config/env/env.go
index 6c104f1c..30e011b9 100644
--- a/config/env/env.go
+++ b/config/env/env.go
@@ -8,11 +8,11 @@ import (
 )
 
 type env struct {
-	prefixs []string
+	prefixes []string
 }
 
-func NewSource(prefixs ...string) config.Source {
-	return &env{prefixs: prefixs}
+func NewSource(prefixes ...string) config.Source {
+	return &env{prefixes: prefixes}
 }
 
 func (e *env) Load() (kv []*config.KeyValue, err error) {
@@ -29,8 +29,8 @@ func (e *env) load(envStrings []string) []*config.KeyValue {
 			v = subs[1]
 		}
 
-		if len(e.prefixs) > 0 {
-			p, ok := matchPrefix(e.prefixs, k)
+		if len(e.prefixes) > 0 {
+			p, ok := matchPrefix(e.prefixes, k)
 			if !ok || len(p) == len(k) {
 				continue
 			}
diff --git a/config/value.go b/config/value.go
index 805f155e..46417e77 100644
--- a/config/value.go
+++ b/config/value.go
@@ -93,9 +93,9 @@ func (v *atomicValue) Slice() ([]Value, error) {
 
 func (v *atomicValue) Map() (map[string]Value, error) {
 	if vals, ok := v.Load().(map[string]interface{}); ok {
-		m := make(map[string]Value)
+		m := make(map[string]Value, len(vals))
 		for key, val := range vals {
-			a := &atomicValue{}
+			a := new(atomicValue)
 			a.Store(val)
 			m[key] = a
 		}
diff --git a/contrib/log/zap/go.mod b/contrib/log/zap/go.mod
index 192127ee..0a8e74f6 100644
--- a/contrib/log/zap/go.mod
+++ b/contrib/log/zap/go.mod
@@ -4,7 +4,7 @@ go 1.16
 
 require (
 	github.com/go-kratos/kratos/v2 v2.5.0
-	go.uber.org/zap v1.22.0
+	go.uber.org/zap v1.23.0
 )
 
 replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/log/zap/go.sum b/contrib/log/zap/go.sum
index 1a82a384..5c9de790 100644
--- a/contrib/log/zap/go.sum
+++ b/contrib/log/zap/go.sum
@@ -72,11 +72,13 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
 github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -90,8 +92,8 @@ go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
-go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
+go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
+go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
diff --git a/contrib/opensergo/go.mod b/contrib/opensergo/go.mod
index beba8f7f..0b920de4 100644
--- a/contrib/opensergo/go.mod
+++ b/contrib/opensergo/go.mod
@@ -8,7 +8,7 @@ require (
 	golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
 	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd
 	google.golang.org/grpc v1.46.2
-	google.golang.org/protobuf v1.28.0
+	google.golang.org/protobuf v1.28.1
 )
 
 require (
diff --git a/contrib/opensergo/go.sum b/contrib/opensergo/go.sum
index f894f6ff..aa486a6f 100644
--- a/contrib/opensergo/go.sum
+++ b/contrib/opensergo/go.sum
@@ -167,8 +167,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/contrib/registry/consul/client.go b/contrib/registry/consul/client.go
index 80ea383a..1b39975a 100644
--- a/contrib/registry/consul/client.go
+++ b/contrib/registry/consul/client.go
@@ -29,6 +29,8 @@ type Client struct {
 	heartbeat bool
 	// deregisterCriticalServiceAfter time interval in seconds
 	deregisterCriticalServiceAfter int
+	// serviceChecks  user custom checks
+	serviceChecks api.AgentServiceChecks
 }
 
 // NewClient creates consul client
@@ -95,7 +97,7 @@ func (c *Client) Service(ctx context.Context, service string, index uint64, pass
 
 // Register register service instance to consul
 func (c *Client) Register(_ context.Context, svc *registry.ServiceInstance, enableHealthCheck bool) error {
-	addresses := make(map[string]api.ServiceAddress)
+	addresses := make(map[string]api.ServiceAddress, len(svc.Endpoints))
 	checkAddresses := make([]string, 0, len(svc.Endpoints))
 	for _, endpoint := range svc.Endpoints {
 		raw, err := url.Parse(endpoint)
@@ -139,6 +141,9 @@ func (c *Client) Register(_ context.Context, svc *registry.ServiceInstance, enab
 		})
 	}
 
+	// custom checks
+	asr.Checks = append(asr.Checks, c.serviceChecks...)
+
 	err := c.cli.Agent().ServiceRegister(asr)
 	if err != nil {
 		return err
diff --git a/contrib/registry/consul/registry.go b/contrib/registry/consul/registry.go
index 9da95d77..d1c47d77 100644
--- a/contrib/registry/consul/registry.go
+++ b/contrib/registry/consul/registry.go
@@ -63,6 +63,15 @@ func WithDeregisterCriticalServiceAfter(interval int) Option {
 	}
 }
 
+// WithServiceCheck with service checks
+func WithServiceCheck(checks ...*api.AgentServiceCheck) Option {
+	return func(o *Registry) {
+		if o.cli != nil {
+			o.cli.serviceChecks = checks
+		}
+	}
+}
+
 // Config is consul registry config
 type Config struct {
 	*api.Config
diff --git a/contrib/registry/discovery/discovery.go b/contrib/registry/discovery/discovery.go
index f6df56dc..dfff0a97 100644
--- a/contrib/registry/discovery/discovery.go
+++ b/contrib/registry/discovery/discovery.go
@@ -439,7 +439,7 @@ func (r *Resolve) fetch(ctx context.Context) (ins *disInstancesInfo, ok bool) {
 		ins = new(disInstancesInfo)
 		ins.LastTs = appIns.LastTs
 		ins.Scheduler = appIns.Scheduler
-		ins.Instances = make(map[string][]*discoveryInstance)
+		ins.Instances = make(map[string][]*discoveryInstance, len(appIns.Instances))
 		for zone, in := range appIns.Instances {
 			ins.Instances[zone] = in
 		}
diff --git a/internal/host/host.go b/internal/host/host.go
index d5cc7ffa..bf204eed 100644
--- a/internal/host/host.go
+++ b/internal/host/host.go
@@ -50,16 +50,13 @@ func Extract(hostPort string, lis net.Listener) (string, error) {
 	if err != nil {
 		return "", err
 	}
-	lowest := int(^uint(0) >> 1)
+	minIndex := int(^uint(0) >> 1)
 	var result net.IP
 	for _, iface := range ifaces {
 		if (iface.Flags & net.FlagUp) == 0 {
 			continue
 		}
-		if iface.Index < lowest || result == nil {
-			lowest = iface.Index
-		}
-		if result != nil {
+		if iface.Index >= minIndex && result != nil {
 			continue
 		}
 		addrs, err := iface.Addrs()
@@ -77,7 +74,9 @@ func Extract(hostPort string, lis net.Listener) (string, error) {
 				continue
 			}
 			if isValidIP(ip.String()) {
+				minIndex = iface.Index
 				result = ip
+				break
 			}
 		}
 	}
diff --git a/middleware/tracing/tracer.go b/middleware/tracing/tracer.go
index 48d4eaa1..cf9115bb 100644
--- a/middleware/tracing/tracer.go
+++ b/middleware/tracing/tracer.go
@@ -24,6 +24,7 @@ type Tracer struct {
 func NewTracer(kind trace.SpanKind, opts ...Option) *Tracer {
 	op := options{
 		propagator: propagation.NewCompositeTextMapPropagator(Metadata{}, propagation.Baggage{}, propagation.TraceContext{}),
+		tracerName: "kratos",
 	}
 	for _, o := range opts {
 		o(&op)
@@ -34,9 +35,9 @@ func NewTracer(kind trace.SpanKind, opts ...Option) *Tracer {
 
 	switch kind {
 	case trace.SpanKindClient:
-		return &Tracer{tracer: otel.Tracer("kratos"), kind: kind, opt: &op}
+		return &Tracer{tracer: otel.Tracer(op.tracerName), kind: kind, opt: &op}
 	case trace.SpanKindServer:
-		return &Tracer{tracer: otel.Tracer("kratos"), kind: kind, opt: &op}
+		return &Tracer{tracer: otel.Tracer(op.tracerName), kind: kind, opt: &op}
 	default:
 		panic(fmt.Sprintf("unsupported span kind: %v", kind))
 	}
diff --git a/middleware/tracing/tracing.go b/middleware/tracing/tracing.go
index c04b13d0..167725f4 100644
--- a/middleware/tracing/tracing.go
+++ b/middleware/tracing/tracing.go
@@ -15,6 +15,7 @@ import (
 type Option func(*options)
 
 type options struct {
+	tracerName     string
 	tracerProvider trace.TracerProvider
 	propagator     propagation.TextMapPropagator
 }
@@ -34,6 +35,13 @@ func WithTracerProvider(provider trace.TracerProvider) Option {
 	}
 }
 
+// WithTracerName with tracer name
+func WithTracerName(tracerName string) Option {
+	return func(opts *options) {
+		opts.tracerName = tracerName
+	}
+}
+
 // Server returns a new server middleware for OpenTelemetry.
 func Server(opts ...Option) middleware.Middleware {
 	tracer := NewTracer(trace.SpanKindServer, opts...)
diff --git a/transport/grpc/balancer.go b/transport/grpc/balancer.go
index bd50f098..2047eb0d 100644
--- a/transport/grpc/balancer.go
+++ b/transport/grpc/balancer.go
@@ -40,7 +40,7 @@ func (b *balancerBuilder) Build(info base.PickerBuildInfo) balancer.Picker {
 		// Block the RPC until a new picker is available via UpdateState().
 		return base.NewErrPicker(balancer.ErrNoSubConnAvailable)
 	}
-	nodes := make([]selector.Node, 0)
+	nodes := make([]selector.Node, 0, len(info.ReadySCs))
 	for conn, info := range info.ReadySCs {
 		ins, _ := info.Address.Attributes.Value("rawServiceInstance").(*registry.ServiceInstance)
 		nodes = append(nodes, &grpcNode{
diff --git a/transport/grpc/client.go b/transport/grpc/client.go
index a1424d20..da6ceb02 100644
--- a/transport/grpc/client.go
+++ b/transport/grpc/client.go
@@ -10,7 +10,7 @@ import (
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-kratos/kratos/v2/selector"
-	"github.com/go-kratos/kratos/v2/selector/p2c"
+	"github.com/go-kratos/kratos/v2/selector/wrr"
 	"github.com/go-kratos/kratos/v2/transport"
 	"github.com/go-kratos/kratos/v2/transport/grpc/resolver/discovery"
 
@@ -25,7 +25,7 @@ import (
 
 func init() {
 	if selector.GlobalSelector() == nil {
-		selector.SetGlobalSelector(p2c.NewBuilder())
+		selector.SetGlobalSelector(wrr.NewBuilder())
 	}
 }
 
diff --git a/transport/http/client.go b/transport/http/client.go
index 79ac4f91..c0ad5ee3 100644
--- a/transport/http/client.go
+++ b/transport/http/client.go
@@ -16,13 +16,13 @@ import (
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-kratos/kratos/v2/selector"
-	"github.com/go-kratos/kratos/v2/selector/p2c"
+	"github.com/go-kratos/kratos/v2/selector/wrr"
 	"github.com/go-kratos/kratos/v2/transport"
 )
 
 func init() {
 	if selector.GlobalSelector() == nil {
-		selector.SetGlobalSelector(p2c.NewBuilder())
+		selector.SetGlobalSelector(wrr.NewBuilder())
 	}
 }
 


Test patch:
diff --git a/cmd/kratos/internal/base/repo_test.go b/cmd/kratos/internal/base/repo_test.go
index 15ed33c8..dfcdbb93 100644
--- a/cmd/kratos/internal/base/repo_test.go
+++ b/cmd/kratos/internal/base/repo_test.go
@@ -7,7 +7,37 @@ import (
 )
 
 func TestRepo(t *testing.T) {
-	os.RemoveAll("/tmp/test_repo")
+	urls := []string{
+		// ssh://[user@]host.xz[:port]/path/to/repo.git/
+		"ssh://git@github.com:7875/go-kratos/kratos.git",
+		// git://host.xz[:port]/path/to/repo.git/
+		"git://github.com:7875/go-kratos/kratos.git",
+		// http[s]://host.xz[:port]/path/to/repo.git/
+		"https://github.com:7875/go-kratos/kratos.git",
+		// ftp[s]://host.xz[:port]/path/to/repo.git/
+		"ftps://github.com:7875/go-kratos/kratos.git",
+		//[user@]host.xz:path/to/repo.git/
+		"git@github.com:go-kratos/kratos.git",
+		// ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
+		"ssh://git@github.com:7875/go-kratos/kratos.git",
+		// git://host.xz[:port]/~[user]/path/to/repo.git/
+		"git://github.com:7875/go-kratos/kratos.git",
+		//[user@]host.xz:/~[user]/path/to/repo.git/
+		"git@github.com:go-kratos/kratos.git",
+		///path/to/repo.git/
+		"//github.com/go-kratos/kratos.git",
+		// file:///path/to/repo.git/
+		"file://./github.com/go-kratos/kratos.git",
+	}
+	for _, url := range urls {
+		dir := repoDir(url)
+		if dir != "github.com/go-kratos" && dir != "/go-kratos" {
+			t.Fatal(url, "repoDir test failed", dir)
+		}
+	}
+}
+
+func TestRepoClone(t *testing.T) {
 	r := NewRepo("https://github.com/go-kratos/service-layout.git", "")
 	if err := r.Clone(context.Background()); err != nil {
 		t.Fatal(err)
@@ -15,19 +45,7 @@ func TestRepo(t *testing.T) {
 	if err := r.CopyTo(context.Background(), "/tmp/test_repo", "github.com/go-kratos/kratos-layout", nil); err != nil {
 		t.Fatal(err)
 	}
-	urls := []string{
-		"ssh://git@gitlab.xxx.com:1234/foo/bar.git",
-		"ssh://gitlab.xxx.com:1234/foo/bar.git",
-		"//git@gitlab.xxx.com:1234/foo/bar.git",
-		"git@gitlab.xxx.com:1234/foo/bar.git",
-		"gitlab.xxx.com:1234/foo/bar.git",
-		"gitlab.xxx.com/foo/bar.git",
-		"gitlab.xxx.com/foo/bar",
-	}
-	for _, url := range urls {
-		dir := repoDir(url)
-		if dir != "gitlab.xxx.com/foo" {
-			t.Fatal("repoDir test failed", dir)
-		}
-	}
+	t.Cleanup(func() {
+		os.RemoveAll("/tmp/test_repo")
+	})
 }
diff --git a/cmd/kratos/internal/base/vcs_url_test.go b/cmd/kratos/internal/base/vcs_url_test.go
new file mode 100644
index 00000000..09b8d568
--- /dev/null
+++ b/cmd/kratos/internal/base/vcs_url_test.go
@@ -0,0 +1,55 @@
+package base
+
+import (
+	"net"
+	"strings"
+	"testing"
+)
+
+func TestParseVCSUrl(t *testing.T) {
+	repos := []string{
+		// ssh://[user@]host.xz[:port]/path/to/repo.git/
+		"ssh://git@github.com:7875/go-kratos/kratos.git",
+		// git://host.xz[:port]/path/to/repo.git/
+		"git://github.com:7875/go-kratos/kratos.git",
+		// http[s]://host.xz[:port]/path/to/repo.git/
+		"https://github.com:7875/go-kratos/kratos.git",
+		// ftp[s]://host.xz[:port]/path/to/repo.git/
+		"ftps://github.com:7875/go-kratos/kratos.git",
+		//[user@]host.xz:path/to/repo.git/
+		"git@github.com:go-kratos/kratos.git",
+		// ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
+		"ssh://git@github.com:7875/go-kratos/kratos.git",
+		// git://host.xz[:port]/~[user]/path/to/repo.git/
+		"git://github.com:7875/go-kratos/kratos.git",
+		//[user@]host.xz:/~[user]/path/to/repo.git/
+		"git@github.com:go-kratos/kratos.git",
+		///path/to/repo.git/
+		"~/go-kratos/kratos.git",
+		// file:///path/to/repo.git/
+		"file://~/go-kratos/kratos.git",
+	}
+	for _, repo := range repos {
+		url, err := ParseVCSUrl(repo)
+		if err != nil {
+			t.Fatal(repo, err)
+		}
+		urlPath := strings.TrimLeft(url.Path, "/")
+		if urlPath != "go-kratos/kratos.git" {
+			t.Fatal(repo, "parse url failed", urlPath)
+		}
+	}
+}
+
+func TestParseSsh(t *testing.T) {
+	repo := "ssh://git@github.com:7875/go-kratos/kratos.git"
+	url, err := ParseVCSUrl(repo)
+	if err != nil {
+		t.Fatal(err)
+	}
+	host, _, err := net.SplitHostPort(url.Host)
+	if err != nil {
+		host = url.Host
+	}
+	t.Log(host, url.Path)
+}
diff --git a/config/env/env_test.go b/config/env/env_test.go
index 6574c1d8..72fcff31 100644
--- a/config/env/env_test.go
+++ b/config/env/env_test.go
@@ -261,7 +261,7 @@ func TestEnvWithoutPrefix(t *testing.T) {
 
 func Test_env_load(t *testing.T) {
 	type fields struct {
-		prefixs []string
+		prefixes []string
 	}
 	type args struct {
 		envStrings []string
@@ -275,7 +275,7 @@ func Test_env_load(t *testing.T) {
 		{
 			name: "without prefixes",
 			fields: fields{
-				prefixs: nil,
+				prefixes: nil,
 			},
 			args: args{
 				envStrings: []string{
@@ -294,7 +294,7 @@ func Test_env_load(t *testing.T) {
 		{
 			name: "empty prefix",
 			fields: fields{
-				prefixs: []string{""},
+				prefixes: []string{""},
 			},
 			args: args{
 				envStrings: []string{
@@ -313,7 +313,7 @@ func Test_env_load(t *testing.T) {
 		{
 			name: "underscore prefix",
 			fields: fields{
-				prefixs: []string{"_"},
+				prefixes: []string{"_"},
 			},
 			args: args{
 				envStrings: []string{
@@ -332,7 +332,7 @@ func Test_env_load(t *testing.T) {
 		{
 			name: "with prefixes",
 			fields: fields{
-				prefixs: []string{"KRATOS_", "FOO"},
+				prefixes: []string{"KRATOS_", "FOO"},
 			},
 			args: args{
 				envStrings: []string{
@@ -351,7 +351,7 @@ func Test_env_load(t *testing.T) {
 		{
 			name: "should not panic #1",
 			fields: fields{
-				prefixs: []string{"FOO"},
+				prefixes: []string{"FOO"},
 			},
 			args: args{
 				envStrings: []string{
@@ -364,7 +364,7 @@ func Test_env_load(t *testing.T) {
 		{
 			name: "should not panic #2",
 			fields: fields{
-				prefixs: []string{"FOO=1"},
+				prefixes: []string{"FOO=1"},
 			},
 			args: args{
 				envStrings: []string{
@@ -377,7 +377,7 @@ func Test_env_load(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			e := &env{
-				prefixs: tt.fields.prefixs,
+				prefixes: tt.fields.prefixes,
 			}
 			got := e.load(tt.args.envStrings)
 			if !reflect.DeepEqual(tt.want, got) {
@@ -419,8 +419,8 @@ func Test_matchPrefix(t *testing.T) {
 }
 
 func Test_env_watch(t *testing.T) {
-	prefixs := []string{"BAR", "FOO"}
-	source := NewSource(prefixs...)
+	prefixes := []string{"BAR", "FOO"}
+	source := NewSource(prefixes...)
 	w, err := source.Watch()
 	if err != nil {
 		t.Errorf("expect no err, got %v", err)
diff --git a/selector/selector_test.go b/selector/selector_test.go
index f7c1f1bc..bcc08264 100644
--- a/selector/selector_test.go
+++ b/selector/selector_test.go
@@ -12,6 +12,8 @@ import (
 	"github.com/go-kratos/kratos/v2/registry"
 )
 
+var errNodeNotMatch = errors.New("node is not match")
+
 type mockWeightedNode struct {
 	Node
 
@@ -80,6 +82,18 @@ func (b *mockBalancer) Pick(ctx context.Context, nodes []WeightedNode) (selected
 	return
 }
 
+type mockMustErrorBalancerBuilder struct{}
+
+func (b *mockMustErrorBalancerBuilder) Build() Balancer {
+	return &mockMustErrorBalancer{}
+}
+
+type mockMustErrorBalancer struct{}
+
+func (b *mockMustErrorBalancer) Pick(ctx context.Context, nodes []WeightedNode) (selected WeightedNode, done DoneFunc, err error) {
+	return nil, nil, errNodeNotMatch
+}
+
 func TestDefault(t *testing.T) {
 	builder := DefaultBuilder{
 		Node:     &mockWeightedNodeBuilder{},
@@ -107,6 +121,7 @@ func TestDefault(t *testing.T) {
 			Endpoints: []string{"http://127.0.0.1:9090"},
 			Metadata:  map[string]string{"weight": "10"},
 		}))
+
 	selector.Apply(nodes)
 	n, done, err := selector.Select(context.Background(), WithNodeFilter(mockFilter("v2.0.0")))
 	if err != nil {
@@ -121,6 +136,9 @@ func TestDefault(t *testing.T) {
 	if !reflect.DeepEqual("v2.0.0", n.Version()) {
 		t.Errorf("expect %v, got %v", "v2.0.0", n.Version())
 	}
+	if n.Scheme() == "" {
+		t.Errorf("expect %v, got %v", "", n.Scheme())
+	}
 	if n.Address() == "" {
 		t.Errorf("expect %v, got %v", "", n.Address())
 	}
@@ -135,6 +153,21 @@ func TestDefault(t *testing.T) {
 	}
 	done(context.Background(), DoneInfo{})
 
+	// peer in ctx
+	ctx := NewPeerContext(context.Background(), &Peer{
+		Node: mockWeightedNode{},
+	})
+	n, done, err = selector.Select(ctx)
+	if err != nil {
+		t.Errorf("expect %v, got %v", ErrNoAvailable, err)
+	}
+	if done == nil {
+		t.Errorf("expect %v, got %v", nil, done)
+	}
+	if n == nil {
+		t.Errorf("expect %v, got %v", nil, n)
+	}
+
 	// no v3.0.0 instance
 	n, done, err = selector.Select(context.Background(), WithNodeFilter(mockFilter("v3.0.0")))
 	if !errors.Is(ErrNoAvailable, err) {
@@ -172,4 +205,87 @@ func TestDefault(t *testing.T) {
 	if n != nil {
 		t.Errorf("expect %v, got %v", nil, n)
 	}
+
+	// without node_filters
+	n, done, err = selector.Select(context.Background())
+	if !errors.Is(ErrNoAvailable, err) {
+		t.Errorf("expect %v, got %v", ErrNoAvailable, err)
+	}
+	if done != nil {
+		t.Errorf("expect %v, got %v", nil, done)
+	}
+	if n != nil {
+		t.Errorf("expect %v, got %v", nil, n)
+	}
+}
+
+func TestWithoutApply(t *testing.T) {
+	builder := DefaultBuilder{
+		Node:     &mockWeightedNodeBuilder{},
+		Balancer: &mockBalancerBuilder{},
+	}
+	selector := builder.Build()
+	n, done, err := selector.Select(context.Background())
+	if !errors.Is(ErrNoAvailable, err) {
+		t.Errorf("expect %v, got %v", ErrNoAvailable, err)
+	}
+	if done != nil {
+		t.Errorf("expect %v, got %v", nil, done)
+	}
+	if n != nil {
+		t.Errorf("expect %v, got %v", nil, n)
+	}
+}
+
+func TestNoPick(t *testing.T) {
+	builder := DefaultBuilder{
+		Node:     &mockWeightedNodeBuilder{},
+		Balancer: &mockMustErrorBalancerBuilder{},
+	}
+	var nodes []Node
+	nodes = append(nodes, NewNode(
+		"http",
+		"127.0.0.1:8080",
+		&registry.ServiceInstance{
+			ID:        "127.0.0.1:8080",
+			Name:      "helloworld",
+			Version:   "v2.0.0",
+			Endpoints: []string{"http://127.0.0.1:8080"},
+			Metadata:  map[string]string{"weight": "10"},
+		}))
+	nodes = append(nodes, NewNode(
+		"http",
+		"127.0.0.1:9090",
+		&registry.ServiceInstance{
+			ID:        "127.0.0.1:9090",
+			Name:      "helloworld",
+			Version:   "v1.0.0",
+			Endpoints: []string{"http://127.0.0.1:9090"},
+			Metadata:  map[string]string{"weight": "10"},
+		}))
+	selector := builder.Build()
+	selector.Apply(nodes)
+	n, done, err := selector.Select(context.Background())
+	if !errors.Is(errNodeNotMatch, err) {
+		t.Errorf("expect %v, got %v", errNodeNotMatch, err)
+	}
+	if done != nil {
+		t.Errorf("expect %v, got %v", nil, done)
+	}
+	if n != nil {
+		t.Errorf("expect %v, got %v", nil, n)
+	}
+}
+
+func TestGolobal(t *testing.T) {
+	builder := DefaultBuilder{
+		Node:     &mockWeightedNodeBuilder{},
+		Balancer: &mockBalancerBuilder{},
+	}
+	SetGlobalSelector(&builder)
+
+	gBuilder := GlobalSelector()
+	if gBuilder == nil {
+		t.Errorf("expect %v, got %v", nil, gBuilder)
+	}
 }