gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/go-grpc-middleware/logging/logrus/payload_interceptors_test.go (about)

     1  package grpc_logrus_test
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  
    10  	grpcmiddleware "gitee.com/ks-custle/core-gm/go-grpc-middleware"
    11  	grpclogrus "gitee.com/ks-custle/core-gm/go-grpc-middleware/logging/logrus"
    12  	grpcctxtags "gitee.com/ks-custle/core-gm/go-grpc-middleware/tags"
    13  	pbtestproto "gitee.com/ks-custle/core-gm/go-grpc-middleware/testing/testproto"
    14  	"gitee.com/ks-custle/core-gm/grpc"
    15  	"gitee.com/ks-custle/core-gm/net/context"
    16  	"github.com/sirupsen/logrus"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  	"github.com/stretchr/testify/suite"
    20  )
    21  
    22  var (
    23  	nullLogger = &logrus.Logger{
    24  		Out:       ioutil.Discard,
    25  		Formatter: new(logrus.TextFormatter),
    26  		Hooks:     make(logrus.LevelHooks),
    27  		Level:     logrus.PanicLevel,
    28  	}
    29  )
    30  
    31  func TestLogrusPayloadSuite(t *testing.T) {
    32  	if strings.HasPrefix(runtime.Version(), "go1.7") {
    33  		t.Skipf("Skipping due to json.RawMessage incompatibility with go1.7")
    34  		return
    35  	}
    36  	alwaysLoggingDeciderServer := func(ctx context.Context, fullMethodName string, servingObject interface{}) bool { return true }
    37  	alwaysLoggingDeciderClient := func(ctx context.Context, fullMethodName string) bool { return true }
    38  	b := newLogrusBaseSuite(t)
    39  	b.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
    40  		grpc.WithUnaryInterceptor(grpclogrus.PayloadUnaryClientInterceptor(logrus.NewEntry(b.logger), alwaysLoggingDeciderClient)),
    41  		grpc.WithStreamInterceptor(grpclogrus.PayloadStreamClientInterceptor(logrus.NewEntry(b.logger), alwaysLoggingDeciderClient)),
    42  	}
    43  	b.InterceptorTestSuite.ServerOpts = []grpc.ServerOption{
    44  		grpcmiddleware.WithStreamServerChain(
    45  			grpcctxtags.StreamServerInterceptor(grpcctxtags.WithFieldExtractor(grpcctxtags.CodeGenRequestFieldExtractor)),
    46  			grpclogrus.StreamServerInterceptor(logrus.NewEntry(nullLogger)),
    47  			grpclogrus.PayloadStreamServerInterceptor(logrus.NewEntry(b.logger), alwaysLoggingDeciderServer)),
    48  		grpcmiddleware.WithUnaryServerChain(
    49  			grpcctxtags.UnaryServerInterceptor(grpcctxtags.WithFieldExtractor(grpcctxtags.CodeGenRequestFieldExtractor)),
    50  			grpclogrus.UnaryServerInterceptor(logrus.NewEntry(nullLogger)),
    51  			grpclogrus.PayloadUnaryServerInterceptor(logrus.NewEntry(b.logger), alwaysLoggingDeciderServer)),
    52  	}
    53  	suite.Run(t, &logrusPayloadSuite{b})
    54  }
    55  
    56  type logrusPayloadSuite struct {
    57  	*logrusBaseSuite
    58  }
    59  
    60  func (s *logrusPayloadSuite) getServerAndClientMessages(expectedServer int, expectedClient int) (serverMsgs []map[string]interface{}, clientMsgs []map[string]interface{}) {
    61  	msgs := s.getOutputJSONs()
    62  	for _, m := range msgs {
    63  		if m["span.kind"] == "server" {
    64  			serverMsgs = append(serverMsgs, m)
    65  		} else if m["span.kind"] == "client" {
    66  			clientMsgs = append(clientMsgs, m)
    67  		}
    68  	}
    69  
    70  	require.Len(s.T(), serverMsgs, expectedServer, "must match expected number of server log messages")
    71  	require.Len(s.T(), clientMsgs, expectedClient, "must match expected number of client log messages")
    72  	return serverMsgs, clientMsgs
    73  }
    74  
    75  func (s *logrusPayloadSuite) TestPing_LogsBothRequestAndResponse() {
    76  	_, err := s.Client.Ping(s.SimpleCtx(), goodPing)
    77  	require.NoError(s.T(), err, "there must be not be an on a successful call")
    78  	serverMsgs, clientMsgs := s.getServerAndClientMessages(2, 2)
    79  
    80  	for _, m := range append(serverMsgs, clientMsgs...) {
    81  		assert.Equal(s.T(), m["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
    82  		assert.Equal(s.T(), m["grpc.method"], "Ping", "all lines must contain the correct method name")
    83  		assert.Equal(s.T(), m["level"], "info", "all lines must contain method name")
    84  	}
    85  
    86  	serverReq, serverResp := serverMsgs[0], serverMsgs[1]
    87  	clientReq, clientResp := clientMsgs[0], clientMsgs[1]
    88  	assert.Contains(s.T(), clientReq, "grpc.request.content", "request payload must be logged in a structured way")
    89  	assert.Contains(s.T(), serverReq, "grpc.request.content", "request payload must be logged in a structured way")
    90  	assert.Contains(s.T(), clientResp, "grpc.response.content", "response payload must be logged in a structured way")
    91  	assert.Contains(s.T(), serverResp, "grpc.response.content", "response payload must be logged in a structured way")
    92  }
    93  
    94  func (s *logrusPayloadSuite) TestPingError_LogsOnlyRequestsOnError() {
    95  	_, err := s.Client.PingError(s.SimpleCtx(), &pbtestproto.PingRequest{Value: "something", ErrorCodeReturned: uint32(4)})
    96  	require.Error(s.T(), err, "there must be not be an error on a successful call")
    97  
    98  	serverMsgs, clientMsgs := s.getServerAndClientMessages(1, 1)
    99  	for _, m := range append(serverMsgs, clientMsgs...) {
   100  		assert.Equal(s.T(), m["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
   101  		assert.Equal(s.T(), m["grpc.method"], "PingError", "all lines must contain the correct method name")
   102  		assert.Equal(s.T(), m["level"], "info", "all lines must be logged at info level")
   103  	}
   104  
   105  	assert.Contains(s.T(), clientMsgs[0], "grpc.request.content", "request payload must be logged by the client")
   106  	assert.Contains(s.T(), serverMsgs[0], "grpc.request.content", "request payload must be logged by the server")
   107  }
   108  
   109  func (s *logrusPayloadSuite) TestPingStream_LogsAllRequestsAndResponses() {
   110  	messagesExpected := 20
   111  	stream, err := s.Client.PingStream(s.SimpleCtx())
   112  	require.NoError(s.T(), err, "no error on stream creation")
   113  	for i := 0; i < messagesExpected; i++ {
   114  		require.NoError(s.T(), stream.Send(goodPing), "sending must succeed")
   115  	}
   116  	require.NoError(s.T(), stream.CloseSend(), "no error on close of stream")
   117  
   118  	for {
   119  		pong := &pbtestproto.PingResponse{}
   120  		err := stream.RecvMsg(pong)
   121  		if err == io.EOF {
   122  			break
   123  		}
   124  		require.NoError(s.T(), err, "no error on receive")
   125  	}
   126  	serverMsgs, clientMsgs := s.getServerAndClientMessages(2*messagesExpected, 2*messagesExpected)
   127  	for _, m := range append(serverMsgs, clientMsgs...) {
   128  		assert.Equal(s.T(), m["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
   129  		assert.Equal(s.T(), m["grpc.method"], "PingStream", "all lines must contain the correct method name")
   130  		assert.Equal(s.T(), m["level"], "info", "all lines must be at info log level")
   131  
   132  		content := m["grpc.request.content"] != nil || m["grpc.response.content"] != nil
   133  		assert.True(s.T(), content, "all messages must contain a payload")
   134  	}
   135  }