package service import ( "context" "encoding/json" "fmt" "git.hlsq.asia/alex/proto/proto/rs/rscommon" "git.hlsq.asia/alex/service-common/log" "git.hlsq.asia/alex/service-common/net/http/httpresp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" otelcodes "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "strconv" "time" ) func (s *Base) RecoveryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { defer func() { if r := recover(); r != nil { log.Errorf("service Panic: %v", r) err = status.Error(codes.Internal, fmt.Sprintf("Internal server error: %v", r)) } }() return handler(ctx, req) } func (s *Base) CheckSID(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { if md, ok := metadata.FromIncomingContext(ctx); ok { sidArr := md.Get("X-Sid") if len(sidArr) > 0 { if strconv.Itoa(int(s.SID)) != sidArr[0] { err = status.Error(codes.Internal, "SID mismatch") return } } } return handler(ctx, req) } func (s *Base) LoggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { usn := "" if md, ok := metadata.FromIncomingContext(ctx); ok { usnArr := md.Get("X-Usn") if len(usnArr) > 0 { usn = usnArr[0] } } _, span := otel.Tracer("grpc.interceptor.logging").Start(ctx, info.FullMethod) defer span.End() reqStr, _ := json.Marshal(req) reqString := fmt.Sprintf("[usn:%v] ↓↓↓ method: %s, Request: %v", usn, info.FullMethod, string(reqStr)) span.SetAttributes(attribute.String("rpc.req", reqString)) span.SetAttributes(attribute.String("usn", usn)) log.Infof(reqString) start := time.Now() resp, err = handler(ctx, req) respStr, _ := json.Marshal(resp) respString := fmt.Sprintf("[usn:%v] ↑↑↑ method: %s, Duration: %v, Response: %v, Error: %v", usn, info.FullMethod, time.Since(start), string(respStr), err) span.SetAttributes(attribute.String("rpc.resp", respString)) log.Infof(respString) if err != nil { if stack, ok := err.(interface{ StackTrace() string }); ok { span.AddEvent("Stack Trace", trace.WithAttributes( attribute.String("stack.trace", fmt.Sprintf("%v", stack.StackTrace())), )) if original, ok := err.(interface{ Original() error }); ok { if wrap, ok := original.Original().(interface{ Wrap() error }); ok { err = wrap.Wrap() } else { err = checkGRPCError(original.Original()) } } } else if wrap, ok := err.(interface{ Wrap() error }); ok { err = wrap.Wrap() } else { err = checkGRPCError(err) } span.SetStatus(otelcodes.Error, err.Error()) } return } func checkGRPCError(err error) error { if original, ok := err.(interface{ GRPCStatus() *status.Status }); ok { details := original.GRPCStatus().Details() if len(details) > 0 { if ei, ok := details[0].(*rscommon.ErrorInfo); ok { return httpresp.NewCode(int(ei.Code), ei.Msg).Wrap() } } } return err }