Repository: go-kratos/kratos
Pull request #2679 (2023-02-23 10:25:16)

build(deps): bump golang.org/x/text from 0.3.7 to 0.3.8 in /contrib/polaris
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.7 to 0.3.8.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/text/commit/434eadcdbc3b0256971992e8c70027278364c72c"><code>434eadc</code></a> language: reject excessively large Accept-Language strings</li>
<li><a href="https://github.com/golang/text/commit/23407e72ed5b895a2dfd230aec777f4fbe026d6a"><code>23407e7</code></a> go.mod: ignore cyclic dependency for tagging</li>
<li><a href="https://github.com/golang/text/commit/b18d3dd8a4b426ebedcf279b593e85ac4985b9d3"><code>b18d3dd</code></a> secure/precis: replace bytes.Compare with bytes.Equal</li>
<li><a href="https://github.com/golang/text/commit/795e854ff348c9cac4fd0033ce04c417705dd0bb"><code>795e854</code></a> all: replace io/ioutil with io and os package</li>
<li><a href="https://github.com/golang/text/commit/b0ca10ff35f1325c7d0ac7830fe3f036bd72d8f9"><code>b0ca10f</code></a> internal/language: bump script types to uint16 and update registry</li>
<li><a href="https://github.com/golang/text/commit/ba9b0e1d4b03523c708709935fbc961124b6967b"><code>ba9b0e1</code></a> go.mod: update x/tools to HEAD</li>
<li><a href="https://github.com/golang/text/commit/d03b41800055b01e3895b1e047af09733c93bf63"><code>d03b418</code></a> A+C: delete AUTHORS and CONTRIBUTORS</li>
<li><a href="https://github.com/golang/text/commit/b4bca84b03619dba00657375259024a7f8ae6712"><code>b4bca84</code></a> language/display: fix Tag method comment</li>
<li><a href="https://github.com/golang/text/commit/ea49e3e2d5b3f1518081d8bc53ffefc8bc60ecec"><code>ea49e3e</code></a> go.mod: update x/tools to HEAD</li>
<li><a href="https://github.com/golang/text/commit/78819d01d041a94e055bbaa2d95e5e4d49e8f8a0"><code>78819d0</code></a> go.mod: update to golang.org/x/text v0.1.10</li>
<li>Additional commits viewable in <a href="https://github.com/golang/text/compare/v0.3.7...v0.3.8">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/text&package-manager=go_modules&previous-version=0.3.7&new-version=0.3.8)](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)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/go-kratos/kratos/network/alerts).

</details>


Patch:
diff --git a/contrib/polaris/go.mod b/contrib/polaris/go.mod
index 3f2e6be7..64f1e76c 100644
--- a/contrib/polaris/go.mod
+++ b/contrib/polaris/go.mod
@@ -34,8 +34,8 @@ require (
 	go.uber.org/zap v1.21.0 // indirect
 	golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
 	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
-	golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
-	golang.org/x/text v0.3.7 // indirect
+	golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
+	golang.org/x/text v0.3.8 // indirect
 	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
 	google.golang.org/grpc v1.46.2 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/contrib/polaris/go.sum b/contrib/polaris/go.sum
index 1bc3ea2e..db66d830 100644
--- a/contrib/polaris/go.sum
+++ b/contrib/polaris/go.sum
@@ -400,8 +400,9 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -411,8 +412,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/middleware/recovery/recovery.go b/middleware/recovery/recovery.go
index 66dcec18..53e67f81 100644
--- a/middleware/recovery/recovery.go
+++ b/middleware/recovery/recovery.go
@@ -3,12 +3,16 @@ package recovery
 import (
 	"context"
 	"runtime"
+	"time"
 
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/middleware"
 )
 
+// Latency is recovery latency context key
+type Latency struct{}
+
 // ErrUnknownRequest is unknown request error.
 var ErrUnknownRequest = errors.InternalServer("UNKNOWN", "unknown request error")
 
@@ -41,13 +45,14 @@ func Recovery(opts ...Option) middleware.Middleware {
 	}
 	return func(handler middleware.Handler) middleware.Handler {
 		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
+			startTime := time.Now()
 			defer func() {
 				if rerr := recover(); rerr != nil {
 					buf := make([]byte, 64<<10) //nolint:gomnd
 					n := runtime.Stack(buf, false)
 					buf = buf[:n]
 					log.Context(ctx).Errorf("%v: %+v\n%s\n", rerr, req, buf)
-
+					ctx = context.WithValue(ctx, Latency{}, time.Since(startTime).Seconds())
 					err = op.handler(ctx, req, rerr)
 				}
 			}()
diff --git a/transport/grpc/client.go b/transport/grpc/client.go
index 5062286e..b2b5c0c2 100644
--- a/transport/grpc/client.go
+++ b/transport/grpc/client.go
@@ -146,16 +146,22 @@ func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.Clien
 	ints := []grpc.UnaryClientInterceptor{
 		unaryClientInterceptor(options.middleware, options.timeout, options.filters),
 	}
+	sints := []grpc.StreamClientInterceptor{
+		streamClientInterceptor(options.filters),
+	}
+
 	if len(options.ints) > 0 {
 		ints = append(ints, options.ints...)
 	}
+	if len(options.streamInts) > 0 {
+		sints = append(sints, options.streamInts...)
+	}
 	grpcOpts := []grpc.DialOption{
 		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%s":{}}]}`, options.balancerName)),
 		grpc.WithChainUnaryInterceptor(ints...),
+		grpc.WithChainStreamInterceptor(sints...),
 	}
-	if len(options.streamInts) > 0 {
-		grpcOpts = append(grpcOpts, grpc.WithChainStreamInterceptor(options.streamInts...))
-	}
+
 	if options.discovery != nil {
 		grpcOpts = append(grpcOpts,
 			grpc.WithResolvers(
@@ -211,3 +217,17 @@ func unaryClientInterceptor(ms []middleware.Middleware, timeout time.Duration, f
 		return err
 	}
 }
+
+func streamClientInterceptor(filters []selector.NodeFilter) grpc.StreamClientInterceptor {
+	return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { // nolint
+		ctx = transport.NewClientContext(ctx, &Transport{
+			endpoint:    cc.Target(),
+			operation:   method,
+			reqHeader:   headerCarrier{},
+			nodeFilters: filters,
+		})
+		var p selector.Peer
+		ctx = selector.NewPeerContext(ctx, &p)
+		return streamer(ctx, desc, cc, method, opts...)
+	}
+}


Test patch:
diff --git a/middleware/recovery/recovery_test.go b/middleware/recovery/recovery_test.go
index cf4a7fbb..b20b5652 100644
--- a/middleware/recovery/recovery_test.go
+++ b/middleware/recovery/recovery_test.go
@@ -18,7 +18,13 @@ func TestOnce(t *testing.T) {
 	next := func(ctx context.Context, req interface{}) (interface{}, error) {
 		panic("panic reason")
 	}
-	_, e := Recovery()(next)(context.Background(), "panic")
+	_, e := Recovery(WithHandler(func(ctx context.Context, _, err interface{}) error {
+		_, ok := ctx.Value(Latency{}).(float64)
+		if !ok {
+			t.Errorf("not latency")
+		}
+		return errors.InternalServer("RECOVERY", fmt.Sprintf("panic triggered: %v", err))
+	}))(next)(context.Background(), "panic")
 	t.Logf("succ and reason is %v", e)
 }