gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/go-grpc-middleware/logging/logrus/payload_interceptors.go (about) 1 package grpc_logrus 2 3 import ( 4 "bytes" 5 "fmt" 6 "gitee.com/zhaochuninhefei/gmgo/go-grpc-middleware/logging/logrus/ctxlogrus" 7 8 grpclogging "gitee.com/zhaochuninhefei/gmgo/go-grpc-middleware/logging" 9 "gitee.com/zhaochuninhefei/gmgo/grpc" 10 "gitee.com/zhaochuninhefei/gmgo/net/context" 11 "github.com/golang/protobuf/jsonpb" 12 "github.com/golang/protobuf/proto" 13 "github.com/sirupsen/logrus" 14 ) 15 16 var ( 17 // JsonPbMarshaller is the marshaller used for serializing protobuf messages. 18 JsonPbMarshaller = &jsonpb.Marshaler{} 19 ) 20 21 // PayloadUnaryServerInterceptor returns a new unary server interceptors that logs the payloads of requests. 22 // 23 // This *only* works when placed *after* the `grpc_logrus.UnaryServerInterceptor`. However, the logging can be done to a 24 // separate instance of the logger. 25 func PayloadUnaryServerInterceptor(entry *logrus.Entry, decider grpclogging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor { 26 return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { 27 if !decider(ctx, info.FullMethod, info.Server) { 28 return handler(ctx, req) 29 } 30 // Use the provided logrus.Entry for logging but use the fields from context. 31 // ctx_logrus.Extract is deprecated, use the ctxlogrus.Extract instead. 32 //logEntry := entry.WithFields(ctx_logrus.Extract(ctx).Data) 33 logEntry := entry.WithFields(ctxlogrus.Extract(ctx).Data) 34 logProtoMessageAsJson(logEntry, req, "grpc.request.content", "server request payload logged as grpc.request.content field") 35 resp, err := handler(ctx, req) 36 if err == nil { 37 logProtoMessageAsJson(logEntry, resp, "grpc.response.content", "server response payload logged as grpc.request.content field") 38 } 39 return resp, err 40 } 41 } 42 43 // PayloadStreamServerInterceptor returns a new server server interceptors that logs the payloads of requests. 44 // 45 // This *only* works when placed *after* the `grpc_logrus.StreamServerInterceptor`. However, the logging can be done to a 46 // separate instance of the logger. 47 func PayloadStreamServerInterceptor(entry *logrus.Entry, decider grpclogging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor { 48 return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { 49 if !decider(stream.Context(), info.FullMethod, srv) { 50 return handler(srv, stream) 51 } 52 // Use the provided logrus.Entry for logging but use the fields from context. 53 // ctx_logrus.Extract is deprecated, use the ctxlogrus.Extract instead. 54 //logEntry := entry.WithFields(Extract(stream.Context()).Data) 55 logEntry := entry.WithFields(ctxlogrus.Extract(stream.Context()).Data) 56 newStream := &loggingServerStream{ServerStream: stream, entry: logEntry} 57 return handler(srv, newStream) 58 } 59 } 60 61 // PayloadUnaryClientInterceptor returns a new unary client interceptor that logs the paylods of requests and responses. 62 func PayloadUnaryClientInterceptor(entry *logrus.Entry, decider grpclogging.ClientPayloadLoggingDecider) grpc.UnaryClientInterceptor { 63 return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { 64 if !decider(ctx, method) { 65 return invoker(ctx, method, req, reply, cc, opts...) 66 } 67 logEntry := entry.WithFields(newClientLoggerFields(ctx, method)) 68 logProtoMessageAsJson(logEntry, req, "grpc.request.content", "client request payload logged as grpc.request.content") 69 err := invoker(ctx, method, req, reply, cc, opts...) 70 if err == nil { 71 logProtoMessageAsJson(logEntry, reply, "grpc.response.content", "client response payload logged as grpc.response.content") 72 } 73 return err 74 } 75 } 76 77 // PayloadStreamClientInterceptor returns a new streaming client interceptor that logs the paylods of requests and responses. 78 func PayloadStreamClientInterceptor(entry *logrus.Entry, decider grpclogging.ClientPayloadLoggingDecider) grpc.StreamClientInterceptor { 79 return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { 80 if !decider(ctx, method) { 81 return streamer(ctx, desc, cc, method, opts...) 82 } 83 logEntry := entry.WithFields(newClientLoggerFields(ctx, method)) 84 clientStream, err := streamer(ctx, desc, cc, method, opts...) 85 newStream := &loggingClientStream{ClientStream: clientStream, entry: logEntry} 86 return newStream, err 87 } 88 } 89 90 type loggingClientStream struct { 91 grpc.ClientStream 92 entry *logrus.Entry 93 } 94 95 func (l *loggingClientStream) SendMsg(m interface{}) error { 96 err := l.ClientStream.SendMsg(m) 97 if err == nil { 98 logProtoMessageAsJson(l.entry, m, "grpc.request.content", "server request payload logged as grpc.request.content field") 99 } 100 return err 101 } 102 103 func (l *loggingClientStream) RecvMsg(m interface{}) error { 104 err := l.ClientStream.RecvMsg(m) 105 if err == nil { 106 logProtoMessageAsJson(l.entry, m, "grpc.response.content", "server response payload logged as grpc.response.content field") 107 } 108 return err 109 } 110 111 type loggingServerStream struct { 112 grpc.ServerStream 113 entry *logrus.Entry 114 } 115 116 func (l *loggingServerStream) SendMsg(m interface{}) error { 117 err := l.ServerStream.SendMsg(m) 118 if err == nil { 119 logProtoMessageAsJson(l.entry, m, "grpc.response.content", "server response payload logged as grpc.response.content field") 120 } 121 return err 122 } 123 124 func (l *loggingServerStream) RecvMsg(m interface{}) error { 125 err := l.ServerStream.RecvMsg(m) 126 if err == nil { 127 logProtoMessageAsJson(l.entry, m, "grpc.request.content", "server request payload logged as grpc.request.content field") 128 } 129 return err 130 } 131 132 func logProtoMessageAsJson(entry *logrus.Entry, pbMsg interface{}, key string, msg string) { 133 if p, ok := pbMsg.(proto.Message); ok { 134 entry.WithField(key, &jsonpbMarshalleble{p}).Info(msg) 135 } 136 } 137 138 type jsonpbMarshalleble struct { 139 proto.Message 140 } 141 142 func (j *jsonpbMarshalleble) MarshalJSON() ([]byte, error) { 143 b := &bytes.Buffer{} 144 if err := JsonPbMarshaller.Marshal(b, j.Message); err != nil { 145 return nil, fmt.Errorf("jsonpb serializer failed: %v", err) 146 } 147 return b.Bytes(), nil 148 }