diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml index b05f2b8f6..db301e45b 100644 --- a/.github/workflows/go.yaml +++ b/.github/workflows/go.yaml @@ -18,7 +18,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.19.x + go-version: 1.21.x - uses: actions/cache@v1 with: @@ -34,7 +34,7 @@ jobs: strategy: fail-fast: false matrix: - go: [ '1.19.x', '1.20.x' ] + go: [ '1.21.x', '1.22.x', '1.23.x' ] platform: [ubuntu-latest, macos-latest] steps: - name: Checkout code into the Go module directory. diff --git a/examples/client/main.go b/examples/client/main.go index c614d90c3..d6dd67442 100644 --- a/examples/client/main.go +++ b/examples/client/main.go @@ -5,14 +5,12 @@ package main import ( "context" - "fmt" + "log/slog" "net/http" "os" "syscall" "time" - "github.com/go-kit/log" - "github.com/go-kit/log/level" grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/timeout" @@ -38,29 +36,18 @@ const ( targetGRPCAddr = "localhost:8080" ) -// interceptorLogger adapts go-kit logger to interceptor logger. +// interceptorLogger adapts slog logger to interceptor logger. // This code is simple enough to be copied and not imported. -func interceptorLogger(l log.Logger) logging.Logger { - return logging.LoggerFunc(func(_ context.Context, lvl logging.Level, msg string, fields ...any) { - largs := append([]any{"msg", msg}, fields...) - switch lvl { - case logging.LevelDebug: - _ = level.Debug(l).Log(largs...) - case logging.LevelInfo: - _ = level.Info(l).Log(largs...) - case logging.LevelWarn: - _ = level.Warn(l).Log(largs...) - case logging.LevelError: - _ = level.Error(l).Log(largs...) - default: - panic(fmt.Sprintf("unknown level %v", lvl)) - } +func interceptorLogger(l *slog.Logger) logging.Logger { + return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) { + l.Log(ctx, slog.Level(lvl), msg, fields...) }) } + func main() { // Setup logging. - logger := log.NewLogfmtLogger(os.Stderr) - rpcLogger := log.With(logger, "service", "gRPC/client", "component", component) + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{})) + rpcLogger := logger.With("service", "gRPC/client", "component", component) logTraceID := func(ctx context.Context) logging.Fields { if span := trace.SpanContextFromContext(ctx); span.IsSampled() { return logging.Fields{"traceID", span.TraceID().String()} @@ -86,7 +73,7 @@ func main() { // Set up OTLP tracing (stdout for debug). exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { - level.Error(logger).Log("err", err) + logger.Error("failed to init exporter", "err", err) os.Exit(1) } tp := sdktrace.NewTracerProvider( @@ -97,21 +84,20 @@ func main() { otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) defer func() { _ = exporter.Shutdown(context.Background()) }() - cc, err := grpc.Dial( + cc, err := grpc.NewClient( targetGRPCAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithStatsHandler(otelgrpc.NewClientHandler()), grpc.WithChainUnaryInterceptor( timeout.UnaryClientInterceptor(500*time.Millisecond), - otelgrpc.UnaryClientInterceptor(), clMetrics.UnaryClientInterceptor(grpcprom.WithExemplarFromContext(exemplarFromContext)), logging.UnaryClientInterceptor(interceptorLogger(rpcLogger), logging.WithFieldsFromContext(logTraceID))), grpc.WithChainStreamInterceptor( - otelgrpc.StreamClientInterceptor(), clMetrics.StreamClientInterceptor(grpcprom.WithExemplarFromContext(exemplarFromContext)), logging.StreamClientInterceptor(interceptorLogger(rpcLogger), logging.WithFieldsFromContext(logTraceID))), ) if err != nil { - level.Error(logger).Log("err", err) + logger.Error("failed to init gRPC client", "err", err) os.Exit(1) } @@ -149,18 +135,18 @@ func main() { }, )) httpSrv.Handler = m - level.Info(logger).Log("msg", "starting HTTP server", "addr", httpSrv.Addr) + logger.Info("starting HTTP server", "addr", httpSrv.Addr) return httpSrv.ListenAndServe() }, func(error) { if err := httpSrv.Close(); err != nil { - level.Error(logger).Log("msg", "failed to stop web server", "err", err) + logger.Error("failed to stop web server", "err", err) } }) g.Add(run.SignalHandler(context.Background(), syscall.SIGINT, syscall.SIGTERM)) if err := g.Run(); err != nil { - level.Error(logger).Log("err", err) + logger.Error("program interrupted", "err", err) os.Exit(1) } } diff --git a/examples/go.mod b/examples/go.mod index 9451f3639..8605bb075 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,43 +1,43 @@ module github.com/grpc-ecosystem/go-grpc-middleware/examples/v2 -go 1.19 +go 1.22 + +toolchain go1.23.1 require ( - github.com/go-kit/log v0.2.1 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 github.com/oklog/run v1.1.0 - github.com/prometheus/client_golang v1.14.1-0.20230317203157-0f80f4931424 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 - go.opentelemetry.io/otel v1.14.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 - go.opentelemetry.io/otel/sdk v1.14.0 - go.opentelemetry.io/otel/trace v1.14.0 - google.golang.org/grpc v1.61.1 + github.com/prometheus/client_golang v1.20.5 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 + go.opentelemetry.io/otel v1.31.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.31.0 + go.opentelemetry.io/otel/sdk v1.31.0 + go.opentelemetry.io/otel/trace v1.31.0 + google.golang.org/grpc v1.67.1 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kr/text v0.2.0 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.41.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect - go.opentelemetry.io/otel/metric v0.37.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/protobuf v1.32.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/stretchr/testify v1.9.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 0aed20605..677d7fced 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -1,82 +1,76 @@ cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.14.1-0.20230317203157-0f80f4931424 h1:KPi/Mi6oi7SsVSwg+vQQmTpZ5fsGgmDgosxwlG9Cqno= -github.com/prometheus/client_golang v1.14.1-0.20230317203157-0f80f4931424/go.mod h1:4E9gOZRxzfyVqC+DBecJiHCwtspNuF5t3xoPh1sdLf4= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.41.0 h1:npo01n6vUlRViIj5fgwiK8vlNIh8bnoxqh3gypKsyAw= -github.com/prometheus/common v0.41.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 h1:5jD3teb4Qh7mx/nfzq4jO2WFFpvXD0vYWFDrdvNWmXk= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhquXl5zTAkLLsZ5+MycAgX99SDsxGc8= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w= -go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs= -go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= -go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= -go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= -google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= -google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 h1:yMkBS9yViCc7U7yeLzJPM2XizlfdVvBRSmsQDWu6qc0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0/go.mod h1:n8MR6/liuGB5EmTETUBeU5ZgqMOlqKRxUaqPQBOANZ8= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.31.0 h1:UGZ1QwZWY67Z6BmckTU+9Rxn04m2bD3gD6Mk0OIOCPk= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.31.0/go.mod h1:fcwWuDuaObkkChiDlhEpSq9+X1C0omv+s5mBtToAQ64= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/server/main.go b/examples/server/main.go index 46edc98e1..65f138cdc 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -5,15 +5,13 @@ package main import ( "context" - "fmt" + "log/slog" "net" "net/http" "os" "runtime/debug" "syscall" - "github.com/go-kit/log" - "github.com/go-kit/log/level" grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth" @@ -43,30 +41,18 @@ const ( httpAddr = ":8081" ) -// interceptorLogger adapts go-kit logger to interceptor logger. +// interceptorLogger adapts slog logger to interceptor logger. // This code is simple enough to be copied and not imported. -func interceptorLogger(l log.Logger) logging.Logger { - return logging.LoggerFunc(func(_ context.Context, lvl logging.Level, msg string, fields ...any) { - largs := append([]any{"msg", msg}, fields...) - switch lvl { - case logging.LevelDebug: - _ = level.Debug(l).Log(largs...) - case logging.LevelInfo: - _ = level.Info(l).Log(largs...) - case logging.LevelWarn: - _ = level.Warn(l).Log(largs...) - case logging.LevelError: - _ = level.Error(l).Log(largs...) - default: - panic(fmt.Sprintf("unknown level %v", lvl)) - } +func interceptorLogger(l *slog.Logger) logging.Logger { + return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) { + l.Log(ctx, slog.Level(lvl), msg, fields...) }) } func main() { // Setup logging. - logger := log.NewLogfmtLogger(os.Stderr) - rpcLogger := log.With(logger, "service", "gRPC/server", "component", component) + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{})) + rpcLogger := logger.With("service", "gRPC/server", "component", component) logTraceID := func(ctx context.Context) logging.Fields { if span := trace.SpanContextFromContext(ctx); span.IsSampled() { return logging.Fields{"traceID", span.TraceID().String()} @@ -92,7 +78,7 @@ func main() { // Set up OTLP tracing (stdout for debug). exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { - level.Error(logger).Log("err", err) + logger.Error("failed to init exporter", "err", err) os.Exit(1) } tp := sdktrace.NewTracerProvider( @@ -129,21 +115,19 @@ func main() { }) grpcPanicRecoveryHandler := func(p any) (err error) { panicsTotal.Inc() - level.Error(rpcLogger).Log("msg", "recovered from panic", "panic", p, "stack", debug.Stack()) + rpcLogger.Error("recovered from panic", "panic", p, "stack", debug.Stack()) return status.Errorf(codes.Internal, "%s", p) } grpcSrv := grpc.NewServer( + grpc.StatsHandler(otelgrpc.NewServerHandler()), grpc.ChainUnaryInterceptor( - // Order matters e.g. tracing interceptor have to create span first for the later exemplars to work. - otelgrpc.UnaryServerInterceptor(), srvMetrics.UnaryServerInterceptor(grpcprom.WithExemplarFromContext(exemplarFromContext)), logging.UnaryServerInterceptor(interceptorLogger(rpcLogger), logging.WithFieldsFromContext(logTraceID)), selector.UnaryServerInterceptor(auth.UnaryServerInterceptor(authFn), selector.MatchFunc(allButHealthZ)), recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpcPanicRecoveryHandler)), ), grpc.ChainStreamInterceptor( - otelgrpc.StreamServerInterceptor(), srvMetrics.StreamServerInterceptor(grpcprom.WithExemplarFromContext(exemplarFromContext)), logging.StreamServerInterceptor(interceptorLogger(rpcLogger), logging.WithFieldsFromContext(logTraceID)), selector.StreamServerInterceptor(auth.StreamServerInterceptor(authFn), selector.MatchFunc(allButHealthZ)), @@ -160,7 +144,7 @@ func main() { if err != nil { return err } - level.Info(logger).Log("msg", "starting gRPC server", "addr", l.Addr().String()) + logger.Info("starting gRPC server", "addr", l.Addr().String()) return grpcSrv.Serve(l) }, func(err error) { grpcSrv.GracefulStop() @@ -179,18 +163,18 @@ func main() { }, )) httpSrv.Handler = m - level.Info(logger).Log("msg", "starting HTTP server", "addr", httpSrv.Addr) + logger.Info("starting HTTP server", "addr", httpSrv.Addr) return httpSrv.ListenAndServe() }, func(error) { if err := httpSrv.Close(); err != nil { - level.Error(logger).Log("msg", "failed to stop web server", "err", err) + logger.Error("failed to stop web server", "err", err) } }) g.Add(run.SignalHandler(context.Background(), syscall.SIGINT, syscall.SIGTERM)) if err := g.Run(); err != nil { - level.Error(logger).Log("err", err) + logger.Error("program interrupted", "err", err) os.Exit(1) } } diff --git a/go.mod b/go.mod index 543587882..b18206871 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,31 @@ module github.com/grpc-ecosystem/go-grpc-middleware/v2 -go 1.19 +go 1.21 require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1 github.com/bufbuild/protovalidate-go v0.2.1 github.com/stretchr/testify v1.8.4 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/net v0.21.0 - golang.org/x/oauth2 v0.16.0 - google.golang.org/grpc v1.61.1 - google.golang.org/protobuf v1.32.0 + golang.org/x/net v0.28.0 + golang.org/x/oauth2 v0.22.0 + google.golang.org/grpc v1.67.1 + google.golang.org/protobuf v1.34.2 ) require ( cloud.google.com/go/compute v1.23.4 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/cel-go v0.17.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8b76d10e7..49ccafa96 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wv cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/bufbuild/protovalidate-go v0.2.1 h1:pJr07sYhliyfj/STAM7hU4J3FKpVeLVKvOBmOTN8j+s= @@ -12,6 +14,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -20,8 +24,11 @@ github.com/google/cel-go v0.17.1 h1:s2151PDGy/eqpCI80/8dl4VL3xTkqI/YubXLXCFw0mw= github.com/google/cel-go v0.17.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= @@ -45,8 +52,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -56,6 +67,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -64,6 +77,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -73,17 +88,26 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= 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.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/interceptors/auth/metadata.go b/interceptors/auth/metadata.go index ce9c45ab8..676d7b9d7 100644 --- a/interceptors/auth/metadata.go +++ b/interceptors/auth/metadata.go @@ -7,12 +7,12 @@ import ( "context" "strings" - "github.com/grpc-ecosystem/go-grpc-middleware/v2/metadata" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) -var ( +const ( headerAuthorize = "authorization" ) @@ -22,11 +22,11 @@ var ( // case-insensitive format (see rfc2617, sec 1.2). If no such authorization is found, or the token // is of wrong scheme, an error with gRPC status `Unauthenticated` is returned. func AuthFromMD(ctx context.Context, expectedScheme string) (string, error) { - val := metadata.ExtractIncoming(ctx).Get(headerAuthorize) - if val == "" { + vals := metadata.ValueFromIncomingContext(ctx, headerAuthorize) + if len(vals) == 0 { return "", status.Error(codes.Unauthenticated, "Request unauthenticated with "+expectedScheme) } - scheme, token, found := strings.Cut(val, " ") + scheme, token, found := strings.Cut(vals[0], " ") if !found { return "", status.Error(codes.Unauthenticated, "Bad authorization string") } diff --git a/interceptors/client.go b/interceptors/client.go index 571e826e8..2b059015c 100644 --- a/interceptors/client.go +++ b/interceptors/client.go @@ -38,7 +38,7 @@ func StreamClientInterceptor(reportable ClientReportable) grpc.StreamClientInter reporter.PostCall(err, time.Since(r.startTime)) return nil, err } - return &monitoredClientStream{ClientStream: clientStream, startTime: r.startTime, reporter: reporter}, nil + return &monitoredClientStream{ClientStream: clientStream, startTime: r.startTime, hasServerStream: desc.ServerStreams, reporter: reporter}, nil } } @@ -46,8 +46,9 @@ func StreamClientInterceptor(reportable ClientReportable) grpc.StreamClientInter type monitoredClientStream struct { grpc.ClientStream - startTime time.Time - reporter Reporter + startTime time.Time + hasServerStream bool + reporter Reporter } func (s *monitoredClientStream) SendMsg(m any) error { @@ -62,13 +63,17 @@ func (s *monitoredClientStream) RecvMsg(m any) error { err := s.ClientStream.RecvMsg(m) s.reporter.PostMsgReceive(m, err, time.Since(start)) - if err == nil { - return nil - } - var postErr error - if err != io.EOF { - postErr = err + if s.hasServerStream { + if err == nil { + return nil + } + var postErr error + if err != io.EOF { + postErr = err + } + s.reporter.PostCall(postErr, time.Since(s.startTime)) + } else { + s.reporter.PostCall(err, time.Since(s.startTime)) } - s.reporter.PostCall(postErr, time.Since(s.startTime)) return err } diff --git a/interceptors/client_test.go b/interceptors/client_test.go index d8c1b5523..252cb0bb5 100644 --- a/interceptors/client_test.go +++ b/interceptors/client_test.go @@ -337,3 +337,26 @@ func (s *ClientInterceptorTestSuite) TestBiStreamingReporting() { postMsgSends: make([]error, 100), }}) } + +func (s *ClientInterceptorTestSuite) TestClientStream() { + ss, err := s.testClient.PingClientStream(s.ctx) + require.NoError(s.T(), err) + + defer func() { + _, _ = ss.CloseAndRecv() + }() + + for i := 0; i < 100; i++ { + require.NoError(s.T(), ss.Send(&testpb.PingClientStreamRequest{}), "sending shouldn't fail") + } + + _, err = ss.CloseAndRecv() + require.NoError(s.T(), err) + + s.mock.Equal(s.T(), []*mockReport{{ + CallMeta: CallMeta{Typ: ClientStream, Service: testpb.TestServiceFullName, Method: "PingClientStream"}, + postCalls: []error{nil}, + postMsgReceives: []error{nil}, + postMsgSends: make([]error, 100), + }}) +} diff --git a/interceptors/logging/examples/go.mod b/interceptors/logging/examples/go.mod index 984e9c48f..d97685e7d 100644 --- a/interceptors/logging/examples/go.mod +++ b/interceptors/logging/examples/go.mod @@ -1,32 +1,30 @@ module github.com/grpc-ecosystem/go-grpc-middleware/interceptors/logging/examples -go 1.19 +go 1.21 require ( github.com/go-kit/log v0.2.1 github.com/go-logr/logr v1.2.4 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0 - github.com/phuslu/log v1.0.83 github.com/rs/zerolog v1.29.0 github.com/sirupsen/logrus v1.9.0 go.uber.org/zap v1.24.0 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - google.golang.org/grpc v1.53.0 + google.golang.org/grpc v1.61.1 k8s.io/klog/v2 v2.90.1 ) require ( github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/net v0.14.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/protobuf v1.32.0 // indirect ) replace github.com/grpc-ecosystem/go-grpc-middleware/v2 => ../../../ diff --git a/interceptors/logging/examples/go.sum b/interceptors/logging/examples/go.sum index ff873eb00..75dd84e2a 100644 --- a/interceptors/logging/examples/go.sum +++ b/interceptors/logging/examples/go.sum @@ -1,4 +1,5 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -12,16 +13,15 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/phuslu/log v1.0.83 h1:zfqz5tfFPLF8w0jEscpDxE2aFg1Y1kcbORDPliKdIbU= -github.com/phuslu/log v1.0.83/go.mod h1:yAZh4pv6KxAsJDmJIcVSMxkMiUF7mJbpFN3vROkf0dc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -34,41 +34,37 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 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.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= 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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= diff --git a/interceptors/logging/examples/slog/example_test.go b/interceptors/logging/examples/slog/example_test.go index 0398b72d6..979305f41 100644 --- a/interceptors/logging/examples/slog/example_test.go +++ b/interceptors/logging/examples/slog/example_test.go @@ -5,10 +5,10 @@ package slog_test import ( "context" + "log/slog" "os" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" - "golang.org/x/exp/slog" "google.golang.org/grpc" ) @@ -21,7 +21,7 @@ func InterceptorLogger(l *slog.Logger) logging.Logger { } func ExampleInterceptorLogger() { - logger := slog.New(slog.NewTextHandler(os.Stderr)) + logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) opts := []logging.Option{ logging.WithLogOnEvents(logging.StartCall, logging.FinishCall), diff --git a/interceptors/logging/interceptors.go b/interceptors/logging/interceptors.go index 45a546b70..7e400dbfb 100644 --- a/interceptors/logging/interceptors.go +++ b/interceptors/logging/interceptors.go @@ -40,6 +40,13 @@ func (c *reporter) PostCall(err error, duration time.Duration) { fields = fields.AppendUnique(Fields{"grpc.code", code.String()}) if err != nil { fields = fields.AppendUnique(Fields{"grpc.error", fmt.Sprintf("%v", err)}) + if c.opts.errorToFieldsFunc != nil { + fields = fields.AppendUnique(c.opts.errorToFieldsFunc(err)) + } + } + if c.opts.fieldsFromCtxCallMetaFn != nil { + // fieldsFromCtxFn dups override the existing fields. + fields = c.opts.fieldsFromCtxCallMetaFn(c.ctx, c.CallMeta).AppendUnique(fields) } c.logger.Log(c.ctx, c.opts.levelFunc(code), "finished call", fields.AppendUnique(c.opts.durationFieldFunc(duration))...) } @@ -49,6 +56,13 @@ func (c *reporter) PostMsgSend(payload any, err error, duration time.Duration) { fields := c.fields.WithUnique(ExtractFields(c.ctx)) if err != nil { fields = fields.AppendUnique(Fields{"grpc.error", fmt.Sprintf("%v", err)}) + if c.opts.errorToFieldsFunc != nil { + fields = fields.AppendUnique(c.opts.errorToFieldsFunc(err)) + } + } + if c.opts.fieldsFromCtxCallMetaFn != nil { + // fieldsFromCtxFn dups override the existing fields. + fields = c.opts.fieldsFromCtxCallMetaFn(c.ctx, c.CallMeta).AppendUnique(fields) } if !c.startCallLogged && has(c.opts.loggableEvents, StartCall) { c.startCallLogged = true @@ -96,6 +110,13 @@ func (c *reporter) PostMsgReceive(payload any, err error, duration time.Duration fields := c.fields.WithUnique(ExtractFields(c.ctx)) if err != nil { fields = fields.AppendUnique(Fields{"grpc.error", fmt.Sprintf("%v", err)}) + if c.opts.errorToFieldsFunc != nil { + fields = fields.AppendUnique(c.opts.errorToFieldsFunc(err)) + } + } + if c.opts.fieldsFromCtxCallMetaFn != nil { + // fieldsFromCtxFn dups override the existing fields. + fields = c.opts.fieldsFromCtxCallMetaFn(c.ctx, c.CallMeta).AppendUnique(fields) } if !c.startCallLogged && has(c.opts.loggableEvents, StartCall) { c.startCallLogged = true diff --git a/interceptors/logging/interceptors_test.go b/interceptors/logging/interceptors_test.go index c137ef157..d40dbd655 100644 --- a/interceptors/logging/interceptors_test.go +++ b/interceptors/logging/interceptors_test.go @@ -11,6 +11,7 @@ import ( "io" "runtime" "sort" + "strconv" "strings" "sync" "testing" @@ -172,9 +173,14 @@ type loggingClientServerSuite struct { *baseLoggingSuite } -func customFields(_ context.Context) logging.Fields { +func customFields(ctx context.Context) logging.Fields { + var val string + n := testpb.ExtractCtxTestNumber(ctx) + if n != nil { + val = strconv.Itoa(*n) + } // Add custom fields. The second one overrides the first one. - return logging.Fields{"custom-field", "foo", "custom-field", "yolo"} + return logging.Fields{"custom-field", "foo", "custom-field", "yolo", "custom-ctx-field", val} } func TestSuite(t *testing.T) { @@ -199,9 +205,12 @@ func TestSuite(t *testing.T) { logging.StreamClientInterceptor(s.logger, logging.WithLevels(customClientCodeToLevel), logging.WithFieldsFromContext(customFields)), ), } + errorFields := func(err error) logging.Fields { + return testpb.ExtractErrorFields(err) + } s.InterceptorTestSuite.ServerOpts = []grpc.ServerOption{ - grpc.StreamInterceptor(logging.StreamServerInterceptor(s.logger, logging.WithLevels(customClientCodeToLevel), logging.WithFieldsFromContext(customFields))), - grpc.UnaryInterceptor(logging.UnaryServerInterceptor(s.logger, logging.WithLevels(customClientCodeToLevel), logging.WithFieldsFromContext(customFields))), + grpc.StreamInterceptor(logging.StreamServerInterceptor(s.logger, logging.WithLevels(customClientCodeToLevel), logging.WithFieldsFromContext(customFields), logging.WithErrorFields(errorFields))), + grpc.UnaryInterceptor(logging.UnaryServerInterceptor(s.logger, logging.WithLevels(customClientCodeToLevel), logging.WithFieldsFromContext(customFields), logging.WithErrorFields(errorFields))), } suite.Run(t, s) } @@ -232,6 +241,8 @@ func (s *loggingClientServerSuite) TestPing() { assert.Equal(s.T(), logging.LevelDebug, serverStartCallLogLine.lvl) assert.Equal(s.T(), "started call", serverStartCallLogLine.msg) _ = assertStandardFields(s.T(), logging.KindServerFieldValue, serverStartCallLogLine.fields, "Ping", interceptors.Unary) + // This field is zero initially, but will be updated by the service, which we should see after the call is finished + serverStartCallLogLine.fields.AssertField(s.T(), "custom-ctx-field", "0") serverFinishCallLogLine := lines[2] assert.Equal(s.T(), logging.LevelDebug, serverFinishCallLogLine.lvl) @@ -239,6 +250,8 @@ func (s *loggingClientServerSuite) TestPing() { serverFinishCallFields := assertStandardFields(s.T(), logging.KindServerFieldValue, serverFinishCallLogLine.fields, "Ping", interceptors.Unary) serverFinishCallFields.AssertFieldNotEmpty(s.T(), "peer.address"). AssertField(s.T(), "custom-field", "yolo"). + // should be updated from 0 to 42 + AssertField(s.T(), "custom-ctx-field", "42"). AssertFieldNotEmpty(s.T(), "grpc.start_time"). AssertFieldNotEmpty(s.T(), "grpc.request.deadline"). AssertField(s.T(), "grpc.code", "OK"). @@ -249,6 +262,8 @@ func (s *loggingClientServerSuite) TestPing() { assert.Equal(s.T(), "finished call", clientFinishCallLogLine.msg) clientFinishCallFields := assertStandardFields(s.T(), logging.KindClientFieldValue, clientFinishCallLogLine.fields, "Ping", interceptors.Unary) clientFinishCallFields.AssertField(s.T(), "custom-field", "yolo"). + // should be updated from 0 to 42 + AssertField(s.T(), "custom-ctx-field", "42"). AssertField(s.T(), "grpc.request.value", "something"). AssertFieldNotEmpty(s.T(), "grpc.start_time"). AssertFieldNotEmpty(s.T(), "grpc.request.deadline"). @@ -285,6 +300,8 @@ func (s *loggingClientServerSuite) TestPingList() { assert.Equal(s.T(), "finished call", serverFinishCallLogLine.msg) serverFinishCallFields := assertStandardFields(s.T(), logging.KindServerFieldValue, serverFinishCallLogLine.fields, "PingList", interceptors.ServerStream) serverFinishCallFields.AssertField(s.T(), "custom-field", "yolo"). + // should be updated from 0 to 42 + AssertField(s.T(), "custom-ctx-field", "42"). AssertFieldNotEmpty(s.T(), "peer.address"). AssertFieldNotEmpty(s.T(), "grpc.start_time"). AssertFieldNotEmpty(s.T(), "grpc.request.deadline"). @@ -297,6 +314,8 @@ func (s *loggingClientServerSuite) TestPingList() { clientFinishCallFields := assertStandardFields(s.T(), logging.KindClientFieldValue, clientFinishCallLogLine.fields, "PingList", interceptors.ServerStream) clientFinishCallFields.AssertFieldNotEmpty(s.T(), "grpc.start_time"). AssertField(s.T(), "custom-field", "yolo"). + // should be updated from 0 to 42 + AssertField(s.T(), "custom-ctx-field", "42"). AssertFieldNotEmpty(s.T(), "grpc.request.deadline"). AssertField(s.T(), "grpc.code", "OK"). AssertFieldNotEmpty(s.T(), "grpc.time_ms").AssertNoMoreTags(s.T()) @@ -344,23 +363,28 @@ func (s *loggingClientServerSuite) TestPingError_WithCustomLevels() { assert.Equal(t, "finished call", serverFinishCallLogLine.msg) serverFinishCallFields := assertStandardFields(t, logging.KindServerFieldValue, serverFinishCallLogLine.fields, "PingError", interceptors.Unary) serverFinishCallFields.AssertField(s.T(), "custom-field", "yolo"). + // should be updated from 0 to 42 + AssertField(s.T(), "custom-ctx-field", "42"). AssertFieldNotEmpty(t, "peer.address"). AssertFieldNotEmpty(t, "grpc.start_time"). AssertFieldNotEmpty(t, "grpc.request.deadline"). AssertField(t, "grpc.code", tcase.code.String()). AssertField(t, "grpc.error", fmt.Sprintf("rpc error: code = %s desc = Userspace error", tcase.code.String())). - AssertFieldNotEmpty(t, "grpc.time_ms").AssertNoMoreTags(t) + AssertField(t, "error-field", "plop"). + AssertFieldNotEmpty(s.T(), "grpc.time_ms").AssertNoMoreTags(s.T()) clientFinishCallLogLine := lines[0] assert.Equal(t, tcase.level, clientFinishCallLogLine.lvl) assert.Equal(t, "finished call", clientFinishCallLogLine.msg) clientFinishCallFields := assertStandardFields(t, logging.KindClientFieldValue, clientFinishCallLogLine.fields, "PingError", interceptors.Unary) clientFinishCallFields.AssertField(s.T(), "custom-field", "yolo"). + // should be updated from 0 to 42 + AssertField(s.T(), "custom-ctx-field", "42"). AssertFieldNotEmpty(t, "grpc.start_time"). AssertFieldNotEmpty(t, "grpc.request.deadline"). AssertField(t, "grpc.code", tcase.code.String()). AssertField(t, "grpc.error", fmt.Sprintf("rpc error: code = %s desc = Userspace error", tcase.code.String())). - AssertFieldNotEmpty(t, "grpc.time_ms").AssertNoMoreTags(t) + AssertFieldNotEmpty(s.T(), "grpc.time_ms").AssertNoMoreTags(s.T()) }) } } diff --git a/interceptors/logging/options.go b/interceptors/logging/options.go index 9f4a17364..7a43bbd09 100644 --- a/interceptors/logging/options.go +++ b/interceptors/logging/options.go @@ -57,6 +57,7 @@ var ( type options struct { levelFunc CodeToLevel loggableEvents []LoggableEvent + errorToFieldsFunc ErrorToFields codeFunc ErrorToCode durationFieldFunc DurationToFields timestampFormat string @@ -89,6 +90,9 @@ func evaluateClientOpt(opts []Option) *options { // DurationToFields function defines how to produce duration fields for logging. type DurationToFields func(duration time.Duration) Fields +// ErrorToFields function extract fields from error. +type ErrorToFields func(err error) Fields + // ErrorToCode function determines the error code of an error. // This makes using custom errors with grpc middleware easier. type ErrorToCode func(err error) codes.Code @@ -138,7 +142,11 @@ type ( fieldsFromCtxCallMetaFn func(ctx context.Context, c interceptors.CallMeta) Fields ) -// WithFieldsFromContext allows overriding existing or adding extra fields to all log messages per given context +// WithFieldsFromContext allows overriding existing or adding extra fields to all log messages per given context. +// If called multiple times, it overwrites the existing FieldsFromContext/WithFieldsFromContextAndCallMeta function. +// If you need to use multiple FieldsFromContext functions then you should combine them in a wrapper fieldsFromCtxFn. +// Only one of WithFieldsFromContextAndCallMeta or WithFieldsFromContext should +// be used, using both will result in the last one overwriting the previous. func WithFieldsFromContext(f fieldsFromCtxFn) Option { return func(o *options) { o.fieldsFromCtxCallMetaFn = func(ctx context.Context, _ interceptors.CallMeta) Fields { @@ -148,6 +156,10 @@ func WithFieldsFromContext(f fieldsFromCtxFn) Option { } // WithFieldsFromContextAndCallMeta allows overriding existing or adding extra fields to all log messages per given context and interceptor.CallMeta +// If called multiple times, it overwrites the existing FieldsFromContext/WithFieldsFromContextAndCallMeta function. +// If you need to use multiple WithFieldsFromContextAndCallMeta functions then you should combine them in a wrapper fieldsFromCtxCallMetaFn. +// Only one of WithFieldsFromContextAndCallMeta or WithFieldsFromContext should +// be used, using both will result in the last one overwriting the previous. func WithFieldsFromContextAndCallMeta(f fieldsFromCtxCallMetaFn) Option { return func(o *options) { o.fieldsFromCtxCallMetaFn = f @@ -161,6 +173,13 @@ func WithLogOnEvents(events ...LoggableEvent) Option { } } +// WithErrorFields allows to extract logging fields from an error. +func WithErrorFields(f ErrorToFields) Option { + return func(o *options) { + o.errorToFieldsFunc = f + } +} + // WithLevels customizes the function for mapping gRPC return codes and interceptor log level statements. func WithLevels(f CodeToLevel) Option { return func(o *options) { diff --git a/interceptors/protovalidate/options.go b/interceptors/protovalidate/options.go index 764b55e74..3eba92979 100644 --- a/interceptors/protovalidate/options.go +++ b/interceptors/protovalidate/options.go @@ -7,12 +7,13 @@ package protovalidate import ( - "golang.org/x/exp/slices" + "slices" + "google.golang.org/protobuf/reflect/protoreflect" ) type options struct { - ignoreMessages []protoreflect.MessageType + ignoreMessages []protoreflect.FullName } // An Option lets you add options to protovalidate interceptors using With* funcs. @@ -26,16 +27,24 @@ func evaluateOpts(opts []Option) *options { return optCopy } -// WithIgnoreMessages sets the messages that should be ignored by the validator. Use with -// caution and ensure validation is performed elsewhere. +// WithIgnoreMessages sets the messages that should be ignored by the +// validator. Message types are matched using their fully-qualified Protobuf +// names. +// +// Use with caution and ensure validation is performed elsewhere. func WithIgnoreMessages(msgs ...protoreflect.MessageType) Option { + names := make([]protoreflect.FullName, 0, len(msgs)) + for _, msg := range msgs { + names = append(names, msg.Descriptor().FullName()) + } + slices.Sort(names) return func(o *options) { - o.ignoreMessages = msgs + o.ignoreMessages = names } } -func (o *options) shouldIgnoreMessage(m protoreflect.MessageType) bool { - return slices.ContainsFunc(o.ignoreMessages, func(t protoreflect.MessageType) bool { - return m == t - }) +func (o *options) shouldIgnoreMessage(fqn protoreflect.FullName) bool { + // Names are sorted in WithIgnoreMessages, so we can use binary search. + _, found := slices.BinarySearch(o.ignoreMessages, fqn) + return found } diff --git a/interceptors/protovalidate/protovalidate.go b/interceptors/protovalidate/protovalidate.go index cf337db11..198442edb 100644 --- a/interceptors/protovalidate/protovalidate.go +++ b/interceptors/protovalidate/protovalidate.go @@ -15,81 +15,78 @@ import ( ) // UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages. +// If the request is invalid, clients may access a structured representation of the validation failure as an error detail. func UnaryServerInterceptor(validator *protovalidate.Validator, opts ...Option) grpc.UnaryServerInterceptor { + o := evaluateOpts(opts) + return func( ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (resp interface{}, err error) { - o := evaluateOpts(opts) - switch msg := req.(type) { - case proto.Message: - if o.shouldIgnoreMessage(msg.ProtoReflect().Type()) { - break - } - if err = validator.Validate(msg); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - default: - return nil, errors.New("unsupported message type") + if err := validateMsg(req, validator, o); err != nil { + return nil, err } - return handler(ctx, req) } } // StreamServerInterceptor returns a new streaming server interceptor that validates incoming messages. +// If the request is invalid, clients may access a structured representation of the validation failure as an error detail. func StreamServerInterceptor(validator *protovalidate.Validator, opts ...Option) grpc.StreamServerInterceptor { + o := evaluateOpts(opts) return func( srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler, ) error { - ctx := stream.Context() - - wrapped := wrapServerStream(stream) - wrapped.wrappedContext = ctx - wrapped.validator = validator - wrapped.options = evaluateOpts(opts) - - return handler(srv, wrapped) - } -} - -func (w *wrappedServerStream) RecvMsg(m interface{}) error { - if err := w.ServerStream.RecvMsg(m); err != nil { - return err - } - - msg := m.(proto.Message) - if w.options.shouldIgnoreMessage(msg.ProtoReflect().Type()) { - return nil + return handler(srv, &wrappedServerStream{ + ServerStream: stream, + validator: validator, + options: o, + }) } - if err := w.validator.Validate(msg); err != nil { - return status.Error(codes.InvalidArgument, err.Error()) - } - - return nil } // wrappedServerStream is a thin wrapper around grpc.ServerStream that allows modifying context. type wrappedServerStream struct { grpc.ServerStream - // wrappedContext is the wrapper's own Context. You can assign it. - wrappedContext context.Context validator *protovalidate.Validator options *options } -// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context() -func (w *wrappedServerStream) Context() context.Context { - return w.wrappedContext +func (w *wrappedServerStream) RecvMsg(m interface{}) error { + if err := w.ServerStream.RecvMsg(m); err != nil { + return err + } + return validateMsg(m, w.validator, w.options) } -// wrapServerStream returns a ServerStream that has the ability to overwrite context. -func wrapServerStream(stream grpc.ServerStream) *wrappedServerStream { - return &wrappedServerStream{ServerStream: stream, wrappedContext: stream.Context()} +func validateMsg(m interface{}, validator *protovalidate.Validator, opts *options) error { + msg, ok := m.(proto.Message) + if !ok { + return status.Errorf(codes.Internal, "unsupported message type: %T", m) + } + if opts.shouldIgnoreMessage(msg.ProtoReflect().Descriptor().FullName()) { + return nil + } + err := validator.Validate(msg) + if err == nil { + return nil + } + var valErr *protovalidate.ValidationError + if errors.As(err, &valErr) { + // Message is invalid. + st := status.New(codes.InvalidArgument, err.Error()) + ds, detErr := st.WithDetails(valErr.ToProto()) + if detErr != nil { + return st.Err() + } + return ds.Err() + } + // CEL expression doesn't compile or type-check. + return status.Error(codes.Internal, err.Error()) } diff --git a/interceptors/protovalidate/protovalidate_test.go b/interceptors/protovalidate/protovalidate_test.go index f626f395c..dcc2c8f75 100644 --- a/interceptors/protovalidate/protovalidate_test.go +++ b/interceptors/protovalidate/protovalidate_test.go @@ -9,16 +9,19 @@ import ( "net" "testing" + "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" "github.com/bufbuild/protovalidate-go" protovalidate_middleware "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/protovalidate" "github.com/grpc-ecosystem/go-grpc-middleware/v2/testing/testvalidate" testvalidatev1 "github.com/grpc-ecosystem/go-grpc-middleware/v2/testing/testvalidate/v1" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" ) @@ -31,25 +34,27 @@ func TestUnaryServerInterceptor(t *testing.T) { handler := func(ctx context.Context, req any) (any, error) { return "good", nil } + info := &grpc.UnaryServerInfo{FullMethod: "FakeMethod"} t.Run("valid_email", func(t *testing.T) { - info := &grpc.UnaryServerInfo{ - FullMethod: "FakeMethod", - } - resp, err := interceptor(context.TODO(), testvalidate.GoodUnaryRequest, info, handler) assert.Nil(t, err) assert.Equal(t, resp, "good") }) t.Run("invalid_email", func(t *testing.T) { - info := &grpc.UnaryServerInfo{ - FullMethod: "FakeMethod", - } - _, err = interceptor(context.TODO(), testvalidate.BadUnaryRequest, info, handler) - assert.Error(t, err) - assert.Equal(t, codes.InvalidArgument, status.Code(err)) + assertEqualViolation(t, &validate.Violation{ + FieldPath: "message", + ConstraintId: "string.email", + Message: "value must be a valid email address", + }, err) + }) + + t.Run("not_protobuf", func(t *testing.T) { + _, err = interceptor(context.Background(), "not protobuf", info, handler) + assert.EqualError(t, err, "rpc error: code = Internal desc = unsupported message type: string") + assert.Equal(t, codes.Internal, status.Code(err)) }) interceptor = protovalidate_middleware.UnaryServerInterceptor(validator, @@ -57,10 +62,6 @@ func TestUnaryServerInterceptor(t *testing.T) { ) t.Run("invalid_email_ignored", func(t *testing.T) { - info := &grpc.UnaryServerInfo{ - FullMethod: "FakeMethod", - } - resp, err := interceptor(context.TODO(), testvalidate.BadUnaryRequest, info, handler) assert.Nil(t, err) assert.Equal(t, resp, "good") @@ -69,12 +70,15 @@ func TestUnaryServerInterceptor(t *testing.T) { type server struct { testvalidatev1.UnimplementedTestValidateServiceServer + + called *bool } func (g *server) SendStream( _ *testvalidatev1.SendStreamRequest, stream testvalidatev1.TestValidateService_SendStreamServer, ) error { + *g.called = true if err := stream.Send(&testvalidatev1.SendStreamResponse{}); err != nil { return err } @@ -84,7 +88,7 @@ func (g *server) SendStream( const bufSize = 1024 * 1024 -func startGrpcServer(t *testing.T, ignoreMessages ...protoreflect.MessageType) *grpc.ClientConn { +func startGrpcServer(t *testing.T, called *bool, ignoreMessages ...protoreflect.MessageType) *grpc.ClientConn { lis := bufconn.Listen(bufSize) validator, err := protovalidate.New() @@ -97,7 +101,7 @@ func startGrpcServer(t *testing.T, ignoreMessages ...protoreflect.MessageType) * ), ), ) - testvalidatev1.RegisterTestValidateServiceServer(s, &server{}) + testvalidatev1.RegisterTestValidateServiceServer(s, &server{called: called}) go func() { if err = s.Serve(lis); err != nil { log.Fatalf("Server exited with error: %v", err) @@ -128,30 +132,42 @@ func startGrpcServer(t *testing.T, ignoreMessages ...protoreflect.MessageType) * func TestStreamServerInterceptor(t *testing.T) { t.Run("valid_email", func(t *testing.T) { + called := proto.Bool(false) client := testvalidatev1.NewTestValidateServiceClient( - startGrpcServer(t), + startGrpcServer(t, called), ) - _, err := client.SendStream(context.Background(), testvalidate.GoodStreamRequest) + out, err := client.SendStream(context.Background(), testvalidate.GoodStreamRequest) + assert.Nil(t, err) + + _, err = out.Recv() + t.Log(err) assert.Nil(t, err) + assert.True(t, *called) }) t.Run("invalid_email", func(t *testing.T) { + called := proto.Bool(false) client := testvalidatev1.NewTestValidateServiceClient( - startGrpcServer(t), + startGrpcServer(t, called), ) out, err := client.SendStream(context.Background(), testvalidate.BadStreamRequest) assert.Nil(t, err) _, err = out.Recv() - assert.Error(t, err) - assert.Equal(t, codes.InvalidArgument, status.Code(err)) + assertEqualViolation(t, &validate.Violation{ + FieldPath: "message", + ConstraintId: "string.email", + Message: "value must be a valid email address", + }, err) + assert.False(t, *called) }) t.Run("invalid_email_ignored", func(t *testing.T) { + called := proto.Bool(false) client := testvalidatev1.NewTestValidateServiceClient( - startGrpcServer(t, testvalidate.BadStreamRequest.ProtoReflect().Type()), + startGrpcServer(t, called, testvalidate.BadStreamRequest.ProtoReflect().Type()), ) out, err := client.SendStream(context.Background(), testvalidate.BadStreamRequest) @@ -159,5 +175,22 @@ func TestStreamServerInterceptor(t *testing.T) { _, err = out.Recv() assert.Nil(t, err) + assert.True(t, *called) }) } + +func assertEqualViolation(tb testing.TB, want *validate.Violation, got error) bool { + require.Error(tb, got) + st := status.Convert(got) + assert.Equal(tb, codes.InvalidArgument, st.Code()) + details := st.Proto().GetDetails() + require.Len(tb, details, 1) + gotpb, unwrapErr := details[0].UnmarshalNew() + require.Nil(tb, unwrapErr) + violations := &validate.Violations{ + Violations: []*validate.Violation{want}, + } + tb.Logf("got: %v", gotpb) + tb.Logf("want: %v", violations) + return assert.True(tb, proto.Equal(gotpb, violations)) +} diff --git a/interceptors/realip/realip.go b/interceptors/realip/realip.go index bd0f2d20d..364fec2c9 100644 --- a/interceptors/realip/realip.go +++ b/interceptors/realip/realip.go @@ -53,16 +53,13 @@ func ipInNets(ip netip.Addr, nets []netip.Prefix) bool { } func getHeader(ctx context.Context, key string) string { - md, ok := metadata.FromIncomingContext(ctx) - if !ok { - return "" - } + vals := metadata.ValueFromIncomingContext(ctx, key) - if md[strings.ToLower(key)] == nil { + if len(vals) == 0 { return "" } - return md[strings.ToLower(key)][0] + return vals[0] } func ipFromXForwardedFoR(trustedProxies []netip.Prefix, ips []string, idx int) netip.Addr { diff --git a/interceptors/retry/retry.go b/interceptors/retry/retry.go index 2b7708415..f0254f915 100644 --- a/interceptors/retry/retry.go +++ b/interceptors/retry/retry.go @@ -40,6 +40,9 @@ func UnaryClientInterceptor(optFuncs ...CallOption) grpc.UnaryClientInterceptor if err := waitRetryBackoff(attempt, parentCtx, callOpts); err != nil { return err } + if attempt > 0 { + callOpts.onRetryCallback(parentCtx, attempt, lastErr) + } callCtx, cancel := perCallContext(parentCtx, callOpts, attempt) defer cancel() // Clean up potential resources. lastErr = invoker(callCtx, method, req, reply, cc, grpcOpts...) @@ -47,7 +50,6 @@ func UnaryClientInterceptor(optFuncs ...CallOption) grpc.UnaryClientInterceptor if lastErr == nil { return nil } - callOpts.onRetryCallback(parentCtx, attempt, lastErr) if isContextError(lastErr) { if parentCtx.Err() != nil { logTrace(parentCtx, "grpc_retry attempt: %d, parent context error: %v", attempt, parentCtx.Err()) @@ -94,20 +96,23 @@ func StreamClientInterceptor(optFuncs ...CallOption) grpc.StreamClientIntercepto if err := waitRetryBackoff(attempt, parentCtx, callOpts); err != nil { return nil, err } + if attempt > 0 { + callOpts.onRetryCallback(parentCtx, attempt, lastErr) + } var newStreamer grpc.ClientStream - newStreamer, lastErr = streamer(parentCtx, desc, cc, method, grpcOpts...) + newStreamer, lastErr = streamer(perStreamContext(parentCtx, callOpts, attempt), desc, cc, method, grpcOpts...) if lastErr == nil { retryingStreamer := &serverStreamingRetryingStream{ ClientStream: newStreamer, callOpts: callOpts, parentCtx: parentCtx, streamerCall: func(ctx context.Context) (grpc.ClientStream, error) { - return streamer(ctx, desc, cc, method, grpcOpts...) + attempt++ + return streamer(perStreamContext(ctx, callOpts, attempt), desc, cc, method, grpcOpts...) }, } return retryingStreamer, nil } - callOpts.onRetryCallback(parentCtx, attempt, lastErr) if isContextError(lastErr) { if parentCtx.Err() != nil { logTrace(parentCtx, "grpc_retry attempt: %d, parent context error: %v", attempt, parentCtx.Err()) @@ -292,6 +297,15 @@ func perCallContext(parentCtx context.Context, callOpts *options, attempt uint) return ctx, cancel } +func perStreamContext(parentCtx context.Context, callOpts *options, attempt uint) context.Context { + ctx := parentCtx + if attempt > 0 && callOpts.includeHeader { + mdClone := metadata.ExtractOutgoing(ctx).Clone().Set(AttemptMetadataKey, fmt.Sprintf("%d", attempt)) + ctx = mdClone.ToOutgoing(ctx) + } + return ctx +} + func contextErrToGrpcErr(err error) error { switch err { case context.DeadlineExceeded: diff --git a/interceptors/retry/retry_test.go b/interceptors/retry/retry_test.go index 459c33270..59455ef66 100644 --- a/interceptors/retry/retry_test.go +++ b/interceptors/retry/retry_test.go @@ -6,6 +6,7 @@ package retry import ( "context" "io" + "strconv" "strings" "sync" "testing" @@ -17,6 +18,7 @@ import ( "github.com/stretchr/testify/suite" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) @@ -204,6 +206,21 @@ func (s *RetrySuite) TestUnary_OnRetryCallbackCalled() { require.EqualValues(s.T(), 2, retryCallbackCount, "two retry callbacks should be called") } +func (s *RetrySuite) TestUnary_OnRetryCallbackNotCalledOnNonRetriableError() { + retryCallbackCount := 0 + + s.srv.resetFailingConfiguration(3, codes.Internal, noSleep) // see retriable_errors + out, err := s.Client.Ping(s.SimpleCtx(), testpb.GoodPing, + WithOnRetryCallback(func(ctx context.Context, attempt uint, err error) { + retryCallbackCount++ + }), + ) + + require.Error(s.T(), err, "should result in an error") + require.Nil(s.T(), out, "out should be nil") + require.EqualValues(s.T(), 0, retryCallbackCount, "no retry callbacks should be called") +} + func (s *RetrySuite) TestServerStream_SucceedsOnRetriableError() { s.srv.resetFailingConfiguration(3, codes.DataLoss, noSleep) // see retriable_errors stream, err := s.Client.PingList(s.SimpleCtx(), testpb.GoodPingList) @@ -417,3 +434,73 @@ func TestJitterUp(t *testing.T) { assert.True(t, highCount != 0, "at least one sample should reach to >%s", high) assert.True(t, lowCount != 0, "at least one sample should to <%s", low) } + +type failingClientStream struct { + RecvMsgErr error +} + +func (s *failingClientStream) Header() (metadata.MD, error) { + return nil, nil +} + +func (s *failingClientStream) Trailer() metadata.MD { + return nil +} + +func (s *failingClientStream) CloseSend() error { + return nil +} + +func (s *failingClientStream) Context() context.Context { + return context.Background() +} + +func (s *failingClientStream) SendMsg(m any) error { + return nil +} + +func (s *failingClientStream) RecvMsg(m any) error { + return s.RecvMsgErr +} + +func TestStreamClientInterceptorAttemptMetadata(t *testing.T) { + retryCount := 5 + attempt := 0 + recvMsgErr := status.Error(codes.Unavailable, "unavailable") + + var testStreamer grpc.Streamer = func( + ctx context.Context, + desc *grpc.StreamDesc, + cc *grpc.ClientConn, + method string, + opts ...grpc.CallOption, + ) (grpc.ClientStream, error) { + if attempt > 0 { + md, ok := metadata.FromOutgoingContext(ctx) + require.True(t, ok) + + raw := md.Get(AttemptMetadataKey) + require.Len(t, raw, 1) + + attemptMetadataValue, err := strconv.Atoi(raw[0]) + require.NoError(t, err) + + require.Equal(t, attempt, attemptMetadataValue) + } + + attempt++ + + return &failingClientStream{ + RecvMsgErr: recvMsgErr, + }, nil + } + + streamClientInterceptor := StreamClientInterceptor(WithCodes(codes.Unavailable), WithMax(uint(retryCount))) + clientStream, err := streamClientInterceptor(context.Background(), &grpc.StreamDesc{}, nil, "some_method", testStreamer) + require.NoError(t, err) + + err = clientStream.RecvMsg(nil) + require.ErrorIs(t, err, recvMsgErr) + + require.Equal(t, retryCount, attempt) +} diff --git a/providers/prometheus/client_test.go b/providers/prometheus/client_test.go index 76dbd43db..71ebb62fe 100644 --- a/providers/prometheus/client_test.go +++ b/providers/prometheus/client_test.go @@ -114,3 +114,17 @@ func (s *ClientInterceptorTestSuite) TestWithSubsystem() { requireSubsystemName(s.T(), "subsystem1", clientMetrics.clientStartedCounter.WithLabelValues("unary", testpb.TestServiceFullName, "dummy")) requireHistSubsystemName(s.T(), "subsystem1", clientMetrics.clientHandledHistogram.WithLabelValues("unary", testpb.TestServiceFullName, "dummy")) } + +func (s *ClientInterceptorTestSuite) TestWithNamespace() { + counterOpts := []CounterOption{ + WithNamespace("namespace1"), + } + histOpts := []HistogramOption{ + WithHistogramNamespace("namespace1"), + } + clientCounterOpts := WithClientCounterOptions(counterOpts...) + clientMetrics := NewClientMetrics(clientCounterOpts, WithClientHandlingTimeHistogram(histOpts...)) + + requireNamespaceName(s.T(), "namespace1", clientMetrics.clientStartedCounter.WithLabelValues("unary", testpb.TestServiceFullName, "dummy")) + requireHistNamespaceName(s.T(), "namespace1", clientMetrics.clientHandledHistogram.WithLabelValues("unary", testpb.TestServiceFullName, "dummy")) +} diff --git a/providers/prometheus/go.mod b/providers/prometheus/go.mod index fee4a9450..daa28afea 100644 --- a/providers/prometheus/go.mod +++ b/providers/prometheus/go.mod @@ -1,13 +1,13 @@ module github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus -go 1.19 +go 1.21 require ( - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 - github.com/stretchr/testify v1.8.1 - google.golang.org/grpc v1.53.0 + github.com/stretchr/testify v1.8.4 + google.golang.org/grpc v1.63.2 ) @@ -15,16 +15,15 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/protobuf v1.28.1 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/providers/prometheus/go.sum b/providers/prometheus/go.sum index 770552037..f8a37dbac 100644 --- a/providers/prometheus/go.sum +++ b/providers/prometheus/go.sum @@ -52,14 +52,12 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -100,8 +98,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -113,7 +112,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -125,11 +125,10 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 h1:o95KDiV/b1xdkumY5YbLR0/n2+wBxUpgf3HgfKgTyLI= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3/go.mod h1:hTxjzRcX49ogbTGVJ1sM5mz5s+SSgiGIyL3jjPxl32E= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -162,7 +161,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -198,17 +196,11 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -281,18 +273,16 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -342,8 +332,8 @@ 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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= @@ -353,8 +343,8 @@ 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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= @@ -452,10 +442,9 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -468,10 +457,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -484,8 +471,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -498,7 +485,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/providers/prometheus/options.go b/providers/prometheus/options.go index bdd171e29..abc61a698 100644 --- a/providers/prometheus/options.go +++ b/providers/prometheus/options.go @@ -46,6 +46,13 @@ func WithSubsystem(subsystem string) CounterOption { } } +// WithNamespace allows you to add a Namespace to Counter metrics. +func WithNamespace(namespace string) CounterOption { + return func(o *prometheus.CounterOpts) { + o.Namespace = namespace + } +} + // A HistogramOption lets you add options to Histogram metrics using With* // funcs. type HistogramOption func(*prometheus.HistogramOpts) @@ -95,6 +102,13 @@ func WithHistogramSubsystem(subsystem string) HistogramOption { } } +// WithHistogramNamespace allows you to add a Namespace to histograms metrics. +func WithHistogramNamespace(namespace string) HistogramOption { + return func(o *prometheus.HistogramOpts) { + o.Namespace = namespace + } +} + func typeFromMethodInfo(mInfo *grpc.MethodInfo) grpcType { if !mInfo.IsClientStream && !mInfo.IsServerStream { return Unary diff --git a/providers/prometheus/server_test.go b/providers/prometheus/server_test.go index 422b2cfe2..038d390fb 100644 --- a/providers/prometheus/server_test.go +++ b/providers/prometheus/server_test.go @@ -259,6 +259,18 @@ func requireSubsystemName(t *testing.T, expect string, c prometheus.Collector) { t.Fail() } +func requireNamespaceName(t *testing.T, expect string, c prometheus.Collector) { + t.Helper() + metricFullName := reflect.ValueOf(*c.(prometheus.Metric).Desc()).FieldByName("fqName").String() + + if strings.Split(metricFullName, "_")[0] == expect { + return + } + + t.Errorf("expected %s value to start with %s; ", metricFullName, expect) + t.Fail() +} + func requireValue(t *testing.T, expect int, c prometheus.Collector) { t.Helper() v := int(testutil.ToFloat64(c)) @@ -283,6 +295,18 @@ func requireHistSubsystemName(t *testing.T, expect string, o prometheus.Observer t.Fail() } +func requireHistNamespaceName(t *testing.T, expect string, o prometheus.Observer) { + t.Helper() + metricFullName := reflect.ValueOf(*o.(prometheus.Metric).Desc()).FieldByName("fqName").String() + + if strings.Split(metricFullName, "_")[0] == expect { + return + } + + t.Errorf("expected %s value to start with %s; ", metricFullName, expect) + t.Fail() +} + func requireValueHistCount(t *testing.T, expect int, o prometheus.Observer) { t.Helper() v := int(toFloat64HistCount(o)) diff --git a/testing/testpb/interceptor_suite.go b/testing/testpb/interceptor_suite.go index fca3de4e7..91f81f733 100644 --- a/testing/testpb/interceptor_suite.go +++ b/testing/testpb/interceptor_suite.go @@ -11,6 +11,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "errors" "flag" "math/big" "net" @@ -20,8 +21,10 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" ) var ( @@ -136,8 +139,67 @@ func (s *InterceptorTestSuite) ServerAddr() string { return s.serverAddr } +type ctxTestNumber struct{} + +var ( + ctxTestNumberKey = &ctxTestNumber{} + zero = 0 +) + +func ExtractCtxTestNumber(ctx context.Context) *int { + if v, ok := ctx.Value(ctxTestNumberKey).(*int); ok { + return v + } + return &zero +} + +type wrappedErrFields struct { + wrappedErr error + fields []any +} + +func (err *wrappedErrFields) Unwrap() error { + return err.wrappedErr +} + +func (err *wrappedErrFields) Error() string { + // Ideally we print wrapped fields as well + return err.wrappedErr.Error() +} + +func (err *wrappedErrFields) GRPCStatus() *status.Status { + if s, ok := status.FromError(err.wrappedErr); ok { + return s + } + return status.New(codes.Unknown, err.Error()) +} + +func WrapFieldsInError(err error, fields []any) error { + return &wrappedErrFields{err, fields} +} + +func ExtractErrorFields(err error) []any { + var e *wrappedErrFields + ok := errors.As(err, &e) + if !ok { + return nil + } + return e.fields +} + +// UnaryServerInterceptor returns a new unary server interceptors that adds query information logging. +func UnaryServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + // newCtx := newContext(ctx, log, opts) + newCtx := ctx + resp, err := handler(newCtx, req) + return resp, err + } +} + func (s *InterceptorTestSuite) SimpleCtx() context.Context { ctx, cancel := context.WithTimeout(context.TODO(), 2*time.Second) + ctx = context.WithValue(ctx, ctxTestNumberKey, 1) s.cancels = append(s.cancels, cancel) return ctx } diff --git a/testing/testpb/pingservice.go b/testing/testpb/pingservice.go index 4c32abe30..a5d1090e6 100644 --- a/testing/testpb/pingservice.go +++ b/testing/testpb/pingservice.go @@ -20,7 +20,7 @@ const ( ListResponseCount = 100 ) -var TestServiceFullName = _TestService_serviceDesc.ServiceName +var TestServiceFullName = TestService_ServiceDesc.ServiceName // Interface implementation assert. var _ TestServiceServer = &TestPingService{} @@ -33,14 +33,19 @@ func (s *TestPingService) PingEmpty(_ context.Context, _ *PingEmptyRequest) (*Pi return &PingEmptyResponse{}, nil } -func (s *TestPingService) Ping(_ context.Context, ping *PingRequest) (*PingResponse, error) { +func (s *TestPingService) Ping(ctx context.Context, ping *PingRequest) (*PingResponse, error) { + // Modify the ctx value to verify the logger sees the value updated from the initial value + n := ExtractCtxTestNumber(ctx) + if n != nil { + *n = 42 + } // Send user trailers and headers. return &PingResponse{Value: ping.Value, Counter: 0}, nil } func (s *TestPingService) PingError(_ context.Context, ping *PingErrorRequest) (*PingErrorResponse, error) { code := codes.Code(ping.ErrorCodeReturned) - return nil, status.Error(code, "Userspace error") + return nil, WrapFieldsInError(status.Error(code, "Userspace error"), []any{"error-field", "plop"}) } func (s *TestPingService) PingList(ping *PingListRequest, stream TestService_PingListServer) error { @@ -75,3 +80,18 @@ func (s *TestPingService) PingStream(stream TestService_PingStreamServer) error } return nil } + +func (s *TestPingService) PingClientStream(stream TestService_PingClientStreamServer) error { + count := 0 + for { + _, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + count += 1 + } + return stream.SendAndClose(&PingClientStreamResponse{Counter: int32(count)}) +} diff --git a/testing/testpb/test.pb.go b/testing/testpb/test.pb.go index 83b5de05c..5c3cd96a5 100644 --- a/testing/testpb/test.pb.go +++ b/testing/testpb/test.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 -// protoc v4.22.0 +// protoc-gen-go v1.35.1 +// protoc v5.28.3 // source: test.proto package testpb @@ -29,11 +29,9 @@ type PingEmptyRequest struct { func (x *PingEmptyRequest) Reset() { *x = PingEmptyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingEmptyRequest) String() string { @@ -44,7 +42,7 @@ func (*PingEmptyRequest) ProtoMessage() {} func (x *PingEmptyRequest) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -67,11 +65,9 @@ type PingEmptyResponse struct { func (x *PingEmptyResponse) Reset() { *x = PingEmptyResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingEmptyResponse) String() string { @@ -82,7 +78,7 @@ func (*PingEmptyResponse) ProtoMessage() {} func (x *PingEmptyResponse) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -109,11 +105,9 @@ type PingRequest struct { func (x *PingRequest) Reset() { *x = PingRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingRequest) String() string { @@ -124,7 +118,7 @@ func (*PingRequest) ProtoMessage() {} func (x *PingRequest) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -171,11 +165,9 @@ type PingResponse struct { func (x *PingResponse) Reset() { *x = PingResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingResponse) String() string { @@ -186,7 +178,7 @@ func (*PingResponse) ProtoMessage() {} func (x *PingResponse) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -227,11 +219,9 @@ type PingErrorRequest struct { func (x *PingErrorRequest) Reset() { *x = PingErrorRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingErrorRequest) String() string { @@ -242,7 +232,7 @@ func (*PingErrorRequest) ProtoMessage() {} func (x *PingErrorRequest) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -289,11 +279,9 @@ type PingErrorResponse struct { func (x *PingErrorResponse) Reset() { *x = PingErrorResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingErrorResponse) String() string { @@ -304,7 +292,7 @@ func (*PingErrorResponse) ProtoMessage() {} func (x *PingErrorResponse) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -345,11 +333,9 @@ type PingListRequest struct { func (x *PingListRequest) Reset() { *x = PingListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingListRequest) String() string { @@ -360,7 +346,7 @@ func (*PingListRequest) ProtoMessage() {} func (x *PingListRequest) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -407,11 +393,9 @@ type PingListResponse struct { func (x *PingListResponse) Reset() { *x = PingListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingListResponse) String() string { @@ -422,7 +406,7 @@ func (*PingListResponse) ProtoMessage() {} func (x *PingListResponse) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -463,11 +447,9 @@ type PingStreamRequest struct { func (x *PingStreamRequest) Reset() { *x = PingStreamRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingStreamRequest) String() string { @@ -478,7 +460,7 @@ func (*PingStreamRequest) ProtoMessage() {} func (x *PingStreamRequest) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -525,11 +507,9 @@ type PingStreamResponse struct { func (x *PingStreamResponse) Reset() { *x = PingStreamResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_test_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_test_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingStreamResponse) String() string { @@ -540,7 +520,7 @@ func (*PingStreamResponse) ProtoMessage() {} func (x *PingStreamResponse) ProtoReflect() protoreflect.Message { mi := &file_test_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -569,6 +549,112 @@ func (x *PingStreamResponse) GetCounter() int32 { return 0 } +type PingClientStreamRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + SleepTimeMs int32 `protobuf:"varint,2,opt,name=sleep_time_ms,json=sleepTimeMs,proto3" json:"sleep_time_ms,omitempty"` + ErrorCodeReturned uint32 `protobuf:"varint,3,opt,name=error_code_returned,json=errorCodeReturned,proto3" json:"error_code_returned,omitempty"` +} + +func (x *PingClientStreamRequest) Reset() { + *x = PingClientStreamRequest{} + mi := &file_test_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingClientStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingClientStreamRequest) ProtoMessage() {} + +func (x *PingClientStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_test_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingClientStreamRequest.ProtoReflect.Descriptor instead. +func (*PingClientStreamRequest) Descriptor() ([]byte, []int) { + return file_test_proto_rawDescGZIP(), []int{10} +} + +func (x *PingClientStreamRequest) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *PingClientStreamRequest) GetSleepTimeMs() int32 { + if x != nil { + return x.SleepTimeMs + } + return 0 +} + +func (x *PingClientStreamRequest) GetErrorCodeReturned() uint32 { + if x != nil { + return x.ErrorCodeReturned + } + return 0 +} + +type PingClientStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Counter int32 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"` +} + +func (x *PingClientStreamResponse) Reset() { + *x = PingClientStreamResponse{} + mi := &file_test_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingClientStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingClientStreamResponse) ProtoMessage() {} + +func (x *PingClientStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_test_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingClientStreamResponse.ProtoReflect.Descriptor instead. +func (*PingClientStreamResponse) Descriptor() ([]byte, []int) { + return file_test_proto_rawDescGZIP(), []int{11} +} + +func (x *PingClientStreamResponse) GetCounter() int32 { + if x != nil { + return x.Counter + } + return 0 +} + var File_test_proto protoreflect.FileDescriptor var file_test_proto_rawDesc = []byte{ @@ -624,37 +710,56 @@ var file_test_proto_rawDesc = []byte{ 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x32, 0xc6, 0x03, 0x0a, 0x0b, 0x54, - 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x50, 0x69, - 0x6e, 0x67, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, - 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x58, 0x0a, 0x09, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x08, 0x50, 0x69, 0x6e, - 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, + 0x05, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x17, 0x50, + 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x22, 0x0a, 0x0d, + 0x73, 0x6c, 0x65, 0x65, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0b, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, + 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, + 0x22, 0x34, 0x0a, 0x18, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x32, 0xb7, 0x04, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, + 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x49, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x09, 0x50, + 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, + 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x08, 0x50, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, + 0x74, 0x12, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, + 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, - 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x30, 0x01, 0x12, 0x5f, 0x0a, 0x0a, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x12, 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, - 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, - 0x01, 0x30, 0x01, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5f, + 0x0a, 0x0a, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x24, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, + 0x6f, 0x0a, 0x10, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, + 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, + 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -669,35 +774,39 @@ func file_test_proto_rawDescGZIP() []byte { return file_test_proto_rawDescData } -var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 10) -var file_test_proto_goTypes = []interface{}{ - (*PingEmptyRequest)(nil), // 0: testing.testpb.v1.PingEmptyRequest - (*PingEmptyResponse)(nil), // 1: testing.testpb.v1.PingEmptyResponse - (*PingRequest)(nil), // 2: testing.testpb.v1.PingRequest - (*PingResponse)(nil), // 3: testing.testpb.v1.PingResponse - (*PingErrorRequest)(nil), // 4: testing.testpb.v1.PingErrorRequest - (*PingErrorResponse)(nil), // 5: testing.testpb.v1.PingErrorResponse - (*PingListRequest)(nil), // 6: testing.testpb.v1.PingListRequest - (*PingListResponse)(nil), // 7: testing.testpb.v1.PingListResponse - (*PingStreamRequest)(nil), // 8: testing.testpb.v1.PingStreamRequest - (*PingStreamResponse)(nil), // 9: testing.testpb.v1.PingStreamResponse +var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_test_proto_goTypes = []any{ + (*PingEmptyRequest)(nil), // 0: testing.testpb.v1.PingEmptyRequest + (*PingEmptyResponse)(nil), // 1: testing.testpb.v1.PingEmptyResponse + (*PingRequest)(nil), // 2: testing.testpb.v1.PingRequest + (*PingResponse)(nil), // 3: testing.testpb.v1.PingResponse + (*PingErrorRequest)(nil), // 4: testing.testpb.v1.PingErrorRequest + (*PingErrorResponse)(nil), // 5: testing.testpb.v1.PingErrorResponse + (*PingListRequest)(nil), // 6: testing.testpb.v1.PingListRequest + (*PingListResponse)(nil), // 7: testing.testpb.v1.PingListResponse + (*PingStreamRequest)(nil), // 8: testing.testpb.v1.PingStreamRequest + (*PingStreamResponse)(nil), // 9: testing.testpb.v1.PingStreamResponse + (*PingClientStreamRequest)(nil), // 10: testing.testpb.v1.PingClientStreamRequest + (*PingClientStreamResponse)(nil), // 11: testing.testpb.v1.PingClientStreamResponse } var file_test_proto_depIdxs = []int32{ - 0, // 0: testing.testpb.v1.TestService.PingEmpty:input_type -> testing.testpb.v1.PingEmptyRequest - 2, // 1: testing.testpb.v1.TestService.Ping:input_type -> testing.testpb.v1.PingRequest - 4, // 2: testing.testpb.v1.TestService.PingError:input_type -> testing.testpb.v1.PingErrorRequest - 6, // 3: testing.testpb.v1.TestService.PingList:input_type -> testing.testpb.v1.PingListRequest - 8, // 4: testing.testpb.v1.TestService.PingStream:input_type -> testing.testpb.v1.PingStreamRequest - 1, // 5: testing.testpb.v1.TestService.PingEmpty:output_type -> testing.testpb.v1.PingEmptyResponse - 3, // 6: testing.testpb.v1.TestService.Ping:output_type -> testing.testpb.v1.PingResponse - 5, // 7: testing.testpb.v1.TestService.PingError:output_type -> testing.testpb.v1.PingErrorResponse - 7, // 8: testing.testpb.v1.TestService.PingList:output_type -> testing.testpb.v1.PingListResponse - 9, // 9: testing.testpb.v1.TestService.PingStream:output_type -> testing.testpb.v1.PingStreamResponse - 5, // [5:10] is the sub-list for method output_type - 0, // [0:5] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: testing.testpb.v1.TestService.PingEmpty:input_type -> testing.testpb.v1.PingEmptyRequest + 2, // 1: testing.testpb.v1.TestService.Ping:input_type -> testing.testpb.v1.PingRequest + 4, // 2: testing.testpb.v1.TestService.PingError:input_type -> testing.testpb.v1.PingErrorRequest + 6, // 3: testing.testpb.v1.TestService.PingList:input_type -> testing.testpb.v1.PingListRequest + 8, // 4: testing.testpb.v1.TestService.PingStream:input_type -> testing.testpb.v1.PingStreamRequest + 10, // 5: testing.testpb.v1.TestService.PingClientStream:input_type -> testing.testpb.v1.PingClientStreamRequest + 1, // 6: testing.testpb.v1.TestService.PingEmpty:output_type -> testing.testpb.v1.PingEmptyResponse + 3, // 7: testing.testpb.v1.TestService.Ping:output_type -> testing.testpb.v1.PingResponse + 5, // 8: testing.testpb.v1.TestService.PingError:output_type -> testing.testpb.v1.PingErrorResponse + 7, // 9: testing.testpb.v1.TestService.PingList:output_type -> testing.testpb.v1.PingListResponse + 9, // 10: testing.testpb.v1.TestService.PingStream:output_type -> testing.testpb.v1.PingStreamResponse + 11, // 11: testing.testpb.v1.TestService.PingClientStream:output_type -> testing.testpb.v1.PingClientStreamResponse + 6, // [6:12] is the sub-list for method output_type + 0, // [0:6] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_test_proto_init() } @@ -705,135 +814,13 @@ func file_test_proto_init() { if File_test_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingEmptyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingEmptyResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingErrorRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingErrorResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingStreamRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_test_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingStreamResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_test_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 12, NumExtensions: 0, NumServices: 1, }, diff --git a/testing/testpb/test_grpc.pb.go b/testing/testpb/test_grpc.pb.go index effb0e2a4..adfabc857 100644 --- a/testing/testpb/test_grpc.pb.go +++ b/testing/testpb/test_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: test.proto package testpb @@ -12,7 +16,17 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + TestService_PingEmpty_FullMethodName = "/testing.testpb.v1.TestService/PingEmpty" + TestService_Ping_FullMethodName = "/testing.testpb.v1.TestService/Ping" + TestService_PingError_FullMethodName = "/testing.testpb.v1.TestService/PingError" + TestService_PingList_FullMethodName = "/testing.testpb.v1.TestService/PingList" + TestService_PingStream_FullMethodName = "/testing.testpb.v1.TestService/PingStream" + TestService_PingClientStream_FullMethodName = "/testing.testpb.v1.TestService/PingClientStream" +) // TestServiceClient is the client API for TestService service. // @@ -21,8 +35,9 @@ type TestServiceClient interface { PingEmpty(ctx context.Context, in *PingEmptyRequest, opts ...grpc.CallOption) (*PingEmptyResponse, error) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) PingError(ctx context.Context, in *PingErrorRequest, opts ...grpc.CallOption) (*PingErrorResponse, error) - PingList(ctx context.Context, in *PingListRequest, opts ...grpc.CallOption) (TestService_PingListClient, error) - PingStream(ctx context.Context, opts ...grpc.CallOption) (TestService_PingStreamClient, error) + PingList(ctx context.Context, in *PingListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[PingListResponse], error) + PingStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[PingStreamRequest, PingStreamResponse], error) + PingClientStream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[PingClientStreamRequest, PingClientStreamResponse], error) } type testServiceClient struct { @@ -34,8 +49,9 @@ func NewTestServiceClient(cc grpc.ClientConnInterface) TestServiceClient { } func (c *testServiceClient) PingEmpty(ctx context.Context, in *PingEmptyRequest, opts ...grpc.CallOption) (*PingEmptyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(PingEmptyResponse) - err := c.cc.Invoke(ctx, "/testing.testpb.v1.TestService/PingEmpty", in, out, opts...) + err := c.cc.Invoke(ctx, TestService_PingEmpty_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -43,8 +59,9 @@ func (c *testServiceClient) PingEmpty(ctx context.Context, in *PingEmptyRequest, } func (c *testServiceClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(PingResponse) - err := c.cc.Invoke(ctx, "/testing.testpb.v1.TestService/Ping", in, out, opts...) + err := c.cc.Invoke(ctx, TestService_Ping_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -52,20 +69,22 @@ func (c *testServiceClient) Ping(ctx context.Context, in *PingRequest, opts ...g } func (c *testServiceClient) PingError(ctx context.Context, in *PingErrorRequest, opts ...grpc.CallOption) (*PingErrorResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(PingErrorResponse) - err := c.cc.Invoke(ctx, "/testing.testpb.v1.TestService/PingError", in, out, opts...) + err := c.cc.Invoke(ctx, TestService_PingError_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *testServiceClient) PingList(ctx context.Context, in *PingListRequest, opts ...grpc.CallOption) (TestService_PingListClient, error) { - stream, err := c.cc.NewStream(ctx, &_TestService_serviceDesc.Streams[0], "/testing.testpb.v1.TestService/PingList", opts...) +func (c *testServiceClient) PingList(ctx context.Context, in *PingListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[PingListResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[0], TestService_PingList_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &testServicePingListClient{stream} + x := &grpc.GenericClientStream[PingListRequest, PingListResponse]{ClientStream: stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } @@ -75,89 +94,92 @@ func (c *testServiceClient) PingList(ctx context.Context, in *PingListRequest, o return x, nil } -type TestService_PingListClient interface { - Recv() (*PingListResponse, error) - grpc.ClientStream -} - -type testServicePingListClient struct { - grpc.ClientStream -} - -func (x *testServicePingListClient) Recv() (*PingListResponse, error) { - m := new(PingListResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type TestService_PingListClient = grpc.ServerStreamingClient[PingListResponse] -func (c *testServiceClient) PingStream(ctx context.Context, opts ...grpc.CallOption) (TestService_PingStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &_TestService_serviceDesc.Streams[1], "/testing.testpb.v1.TestService/PingStream", opts...) +func (c *testServiceClient) PingStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[PingStreamRequest, PingStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[1], TestService_PingStream_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &testServicePingStreamClient{stream} + x := &grpc.GenericClientStream[PingStreamRequest, PingStreamResponse]{ClientStream: stream} return x, nil } -type TestService_PingStreamClient interface { - Send(*PingStreamRequest) error - Recv() (*PingStreamResponse, error) - grpc.ClientStream -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type TestService_PingStreamClient = grpc.BidiStreamingClient[PingStreamRequest, PingStreamResponse] -type testServicePingStreamClient struct { - grpc.ClientStream -} - -func (x *testServicePingStreamClient) Send(m *PingStreamRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *testServicePingStreamClient) Recv() (*PingStreamResponse, error) { - m := new(PingStreamResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { +func (c *testServiceClient) PingClientStream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[PingClientStreamRequest, PingClientStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[2], TestService_PingClientStream_FullMethodName, cOpts...) + if err != nil { return nil, err } - return m, nil + x := &grpc.GenericClientStream[PingClientStreamRequest, PingClientStreamResponse]{ClientStream: stream} + return x, nil } +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type TestService_PingClientStreamClient = grpc.ClientStreamingClient[PingClientStreamRequest, PingClientStreamResponse] + // TestServiceServer is the server API for TestService service. // All implementations must embed UnimplementedTestServiceServer -// for forward compatibility +// for forward compatibility. type TestServiceServer interface { PingEmpty(context.Context, *PingEmptyRequest) (*PingEmptyResponse, error) Ping(context.Context, *PingRequest) (*PingResponse, error) PingError(context.Context, *PingErrorRequest) (*PingErrorResponse, error) - PingList(*PingListRequest, TestService_PingListServer) error - PingStream(TestService_PingStreamServer) error + PingList(*PingListRequest, grpc.ServerStreamingServer[PingListResponse]) error + PingStream(grpc.BidiStreamingServer[PingStreamRequest, PingStreamResponse]) error + PingClientStream(grpc.ClientStreamingServer[PingClientStreamRequest, PingClientStreamResponse]) error mustEmbedUnimplementedTestServiceServer() } -// UnimplementedTestServiceServer must be embedded to have forward compatible implementations. -type UnimplementedTestServiceServer struct { -} +// UnimplementedTestServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedTestServiceServer struct{} -func (*UnimplementedTestServiceServer) PingEmpty(context.Context, *PingEmptyRequest) (*PingEmptyResponse, error) { +func (UnimplementedTestServiceServer) PingEmpty(context.Context, *PingEmptyRequest) (*PingEmptyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PingEmpty not implemented") } -func (*UnimplementedTestServiceServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { +func (UnimplementedTestServiceServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") } -func (*UnimplementedTestServiceServer) PingError(context.Context, *PingErrorRequest) (*PingErrorResponse, error) { +func (UnimplementedTestServiceServer) PingError(context.Context, *PingErrorRequest) (*PingErrorResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PingError not implemented") } -func (*UnimplementedTestServiceServer) PingList(*PingListRequest, TestService_PingListServer) error { +func (UnimplementedTestServiceServer) PingList(*PingListRequest, grpc.ServerStreamingServer[PingListResponse]) error { return status.Errorf(codes.Unimplemented, "method PingList not implemented") } -func (*UnimplementedTestServiceServer) PingStream(TestService_PingStreamServer) error { +func (UnimplementedTestServiceServer) PingStream(grpc.BidiStreamingServer[PingStreamRequest, PingStreamResponse]) error { return status.Errorf(codes.Unimplemented, "method PingStream not implemented") } -func (*UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {} +func (UnimplementedTestServiceServer) PingClientStream(grpc.ClientStreamingServer[PingClientStreamRequest, PingClientStreamResponse]) error { + return status.Errorf(codes.Unimplemented, "method PingClientStream not implemented") +} +func (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {} +func (UnimplementedTestServiceServer) testEmbeddedByValue() {} -func RegisterTestServiceServer(s *grpc.Server, srv TestServiceServer) { - s.RegisterService(&_TestService_serviceDesc, srv) +// UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to TestServiceServer will +// result in compilation errors. +type UnsafeTestServiceServer interface { + mustEmbedUnimplementedTestServiceServer() +} + +func RegisterTestServiceServer(s grpc.ServiceRegistrar, srv TestServiceServer) { + // If the following call pancis, it indicates UnimplementedTestServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&TestService_ServiceDesc, srv) } func _TestService_PingEmpty_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { @@ -170,7 +192,7 @@ func _TestService_PingEmpty_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/testing.testpb.v1.TestService/PingEmpty", + FullMethod: TestService_PingEmpty_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(TestServiceServer).PingEmpty(ctx, req.(*PingEmptyRequest)) @@ -188,7 +210,7 @@ func _TestService_Ping_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/testing.testpb.v1.TestService/Ping", + FullMethod: TestService_Ping_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(TestServiceServer).Ping(ctx, req.(*PingRequest)) @@ -206,7 +228,7 @@ func _TestService_PingError_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/testing.testpb.v1.TestService/PingError", + FullMethod: TestService_PingError_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(TestServiceServer).PingError(ctx, req.(*PingErrorRequest)) @@ -219,49 +241,30 @@ func _TestService_PingList_Handler(srv interface{}, stream grpc.ServerStream) er if err := stream.RecvMsg(m); err != nil { return err } - return srv.(TestServiceServer).PingList(m, &testServicePingListServer{stream}) + return srv.(TestServiceServer).PingList(m, &grpc.GenericServerStream[PingListRequest, PingListResponse]{ServerStream: stream}) } -type TestService_PingListServer interface { - Send(*PingListResponse) error - grpc.ServerStream -} - -type testServicePingListServer struct { - grpc.ServerStream -} - -func (x *testServicePingListServer) Send(m *PingListResponse) error { - return x.ServerStream.SendMsg(m) -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type TestService_PingListServer = grpc.ServerStreamingServer[PingListResponse] func _TestService_PingStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TestServiceServer).PingStream(&testServicePingStreamServer{stream}) + return srv.(TestServiceServer).PingStream(&grpc.GenericServerStream[PingStreamRequest, PingStreamResponse]{ServerStream: stream}) } -type TestService_PingStreamServer interface { - Send(*PingStreamResponse) error - Recv() (*PingStreamRequest, error) - grpc.ServerStream -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type TestService_PingStreamServer = grpc.BidiStreamingServer[PingStreamRequest, PingStreamResponse] -type testServicePingStreamServer struct { - grpc.ServerStream +func _TestService_PingClientStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(TestServiceServer).PingClientStream(&grpc.GenericServerStream[PingClientStreamRequest, PingClientStreamResponse]{ServerStream: stream}) } -func (x *testServicePingStreamServer) Send(m *PingStreamResponse) error { - return x.ServerStream.SendMsg(m) -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type TestService_PingClientStreamServer = grpc.ClientStreamingServer[PingClientStreamRequest, PingClientStreamResponse] -func (x *testServicePingStreamServer) Recv() (*PingStreamRequest, error) { - m := new(PingStreamRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -var _TestService_serviceDesc = grpc.ServiceDesc{ +// TestService_ServiceDesc is the grpc.ServiceDesc for TestService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var TestService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "testing.testpb.v1.TestService", HandlerType: (*TestServiceServer)(nil), Methods: []grpc.MethodDesc{ @@ -290,6 +293,11 @@ var _TestService_serviceDesc = grpc.ServiceDesc{ ServerStreams: true, ClientStreams: true, }, + { + StreamName: "PingClientStream", + Handler: _TestService_PingClientStream_Handler, + ClientStreams: true, + }, }, Metadata: "test.proto", } diff --git a/testing/testpb/v1/test.proto b/testing/testpb/v1/test.proto index 64bc4bd83..9c9b9787f 100644 --- a/testing/testpb/v1/test.proto +++ b/testing/testpb/v1/test.proto @@ -54,6 +54,16 @@ message PingStreamResponse { int32 counter = 2; } +message PingClientStreamRequest { + string value = 1; + int32 sleep_time_ms = 2; + uint32 error_code_returned = 3; +} + +message PingClientStreamResponse { + int32 counter = 1; +} + service TestService { rpc PingEmpty(PingEmptyRequest) returns (PingEmptyResponse) {} @@ -65,4 +75,6 @@ service TestService { rpc PingStream(stream PingStreamRequest) returns (stream PingStreamResponse) {} + rpc PingClientStream(stream PingClientStreamRequest) returns (PingClientStreamResponse) {} + }