grpc-xds/greeter-go/pkg/greeter/intermediary.go (66 lines of code) (raw):

// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package greeter import ( "context" "fmt" "github.com/go-logr/logr" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc/codes" helloworldpb "google.golang.org/grpc/examples/helloworld/helloworld" "google.golang.org/grpc/status" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "github.com/googlecloudplatform/solutions-workshops/grpc-xds/greeter-go/pkg/logging" ) // intermediaryService implements helloworld.Greeter. type intermediaryService struct { helloworldpb.UnimplementedGreeterServer logger logr.Logger name string greeterClient *Client } func NewIntermediaryService(ctx context.Context, name string, greeterClient *Client) helloworldpb.GreeterServer { return &intermediaryService{ logger: logging.FromContext(ctx), name: name, greeterClient: greeterClient, } } func (s *intermediaryService) SayHello(ctx context.Context, request *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) { s.logger.V(2).Info("Received request, forwarding to the next hop", "name", request.Name) intermediaryMessage, err := s.greeterClient.SayHello(ctx, request.GetName()) if err != nil { logGreeterError(s.logger, err, "Greeting request failed, returning error code internal") st, errSt := createStatus(codes.Internal, "greeter request failed") if errSt != nil { // Should not happen s.logger.Error(errSt, "Could not append ErrorInfo to Status") } return nil, st.Err() } return &helloworldpb.HelloReply{Message: fmt.Sprintf("%s, via %s", intermediaryMessage, s.name)}, nil } func logGreeterError(logger logr.Logger, err error, message string, keysAndValues ...interface{}) { s, ok := status.FromError(err) if !ok { logger.Error(err, message, keysAndValues...) return } keysAndValues = append(keysAndValues, "code", s.Code().String(), "message", s.Message()) for _, detail := range s.Details() { if message, ok := detail.(proto.Message); ok { messageJSONBytes, err := protojson.Marshal(message) if err != nil { logger.Error(err, "Could not marshal status detail to JSON") } else { // Log error detail if we can marshal it to JSON key := string(message.ProtoReflect().Descriptor().Name()) keysAndValues = append(keysAndValues, key, string(messageJSONBytes)) } } } logger.Error(err, message, keysAndValues...) } func createStatus(code codes.Code, message string) (*status.Status, error) { st := status.New(code, message) return st.WithDetails(&errdetails.ErrorInfo{ Reason: code.String(), Domain: "greeter.example.com", }) }