github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/go-grpc-middleware/logging/zap/payload_interceptors_test.go (about)

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