...

Source file src/github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/payload_interceptors_test.go

Documentation: github.com/grpc-ecosystem/go-grpc-middleware/logging/zap

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

View as plain text