104 lines
3.2 KiB
Go
104 lines
3.2 KiB
Go
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
|
|
}
|