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