...

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

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

     1  package grpc_zap_test
     2  
     3  import (
     4  	"io"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  	"github.com/stretchr/testify/suite"
    10  	"google.golang.org/grpc"
    11  	"google.golang.org/grpc/codes"
    12  
    13  	grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
    14  	pb_testproto "github.com/grpc-ecosystem/go-grpc-middleware/testing/testproto"
    15  	"go.uber.org/zap/zapcore"
    16  )
    17  
    18  func customClientCodeToLevel(c codes.Code) zapcore.Level {
    19  	if c == codes.Unauthenticated {
    20  		// Make this a special case for tests, and an error.
    21  		return zapcore.ErrorLevel
    22  	}
    23  	level := grpc_zap.DefaultClientCodeToLevel(c)
    24  	return level
    25  }
    26  
    27  func TestZapClientSuite(t *testing.T) {
    28  	opts := []grpc_zap.Option{
    29  		grpc_zap.WithLevels(customClientCodeToLevel),
    30  	}
    31  	b := newBaseZapSuite(t)
    32  	b.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
    33  		grpc.WithUnaryInterceptor(grpc_zap.UnaryClientInterceptor(b.log, opts...)),
    34  		grpc.WithStreamInterceptor(grpc_zap.StreamClientInterceptor(b.log, opts...)),
    35  	}
    36  	suite.Run(t, &zapClientSuite{b})
    37  }
    38  
    39  type zapClientSuite struct {
    40  	*zapBaseSuite
    41  }
    42  
    43  func (s *zapClientSuite) TestPing() {
    44  	_, err := s.Client.Ping(s.SimpleCtx(), goodPing)
    45  	require.NoError(s.T(), err, "there must be not be an error on a successful call")
    46  
    47  	msgs := s.getOutputJSONs()
    48  	require.Len(s.T(), msgs, 1, "one log statement should be logged")
    49  
    50  	assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain service name")
    51  	assert.Equal(s.T(), msgs[0]["grpc.method"], "Ping", "all lines must contain method name")
    52  	assert.Equal(s.T(), msgs[0]["msg"], "finished client unary call", "must contain correct message")
    53  	assert.Equal(s.T(), msgs[0]["span.kind"], "client", "all lines must contain the kind of call (client)")
    54  	assert.Equal(s.T(), msgs[0]["level"], "debug", "must be logged on debug level.")
    55  	assert.Contains(s.T(), msgs[0], "grpc.time_ms", "interceptor log statement should contain execution time")
    56  }
    57  
    58  func (s *zapClientSuite) TestPingList() {
    59  	stream, err := s.Client.PingList(s.SimpleCtx(), goodPing)
    60  	require.NoError(s.T(), err, "should not fail on establishing the stream")
    61  	for {
    62  		_, err := stream.Recv()
    63  		if err == io.EOF {
    64  			break
    65  		}
    66  		require.NoError(s.T(), err, "reading stream should not fail")
    67  	}
    68  	msgs := s.getOutputJSONs()
    69  	require.Len(s.T(), msgs, 1, "one log statement should be logged")
    70  
    71  	assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain service name")
    72  	assert.Equal(s.T(), msgs[0]["grpc.method"], "PingList", "all lines must contain method name")
    73  	assert.Equal(s.T(), msgs[0]["msg"], "finished client streaming call", "handler's message must contain user message")
    74  	assert.Equal(s.T(), msgs[0]["span.kind"], "client", "all lines must contain the kind of call (client)")
    75  	assert.Equal(s.T(), msgs[0]["level"], "debug", "OK codes must be logged on debug level.")
    76  	assert.Contains(s.T(), msgs[0], "grpc.time_ms", "handler's message must contain time in ms")
    77  }
    78  
    79  func (s *zapClientSuite) TestPingError_WithCustomLevels() {
    80  	for _, tcase := range []struct {
    81  		code  codes.Code
    82  		level zapcore.Level
    83  		msg   string
    84  	}{
    85  		{
    86  			code:  codes.Internal,
    87  			level: zapcore.WarnLevel,
    88  			msg:   "Internal must remap to ErrorLevel in DefaultClientCodeToLevel",
    89  		},
    90  		{
    91  			code:  codes.NotFound,
    92  			level: zapcore.DebugLevel,
    93  			msg:   "NotFound must remap to InfoLevel in DefaultClientCodeToLevel",
    94  		},
    95  		{
    96  			code:  codes.FailedPrecondition,
    97  			level: zapcore.DebugLevel,
    98  			msg:   "FailedPrecondition must remap to WarnLevel in DefaultClientCodeToLevel",
    99  		},
   100  		{
   101  			code:  codes.Unauthenticated,
   102  			level: zapcore.ErrorLevel,
   103  			msg:   "Unauthenticated is overwritten to ErrorLevel with customClientCodeToLevel override, which probably didn't work",
   104  		},
   105  	} {
   106  		s.SetupTest()
   107  		_, err := s.Client.PingError(
   108  			s.SimpleCtx(),
   109  			&pb_testproto.PingRequest{Value: "something", ErrorCodeReturned: uint32(tcase.code)})
   110  		require.Error(s.T(), err, "each call here must return an error")
   111  
   112  		msgs := s.getOutputJSONs()
   113  		require.Len(s.T(), msgs, 1, "only the interceptor log message is printed in PingErr")
   114  
   115  		assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain service name")
   116  		assert.Equal(s.T(), msgs[0]["grpc.method"], "PingError", "all lines must contain method name")
   117  		assert.Equal(s.T(), msgs[0]["grpc.code"], tcase.code.String(), "all lines must contain the correct gRPC code")
   118  		assert.Equal(s.T(), msgs[0]["level"], tcase.level.String(), tcase.msg)
   119  	}
   120  }
   121  
   122  func TestZapClientOverrideSuite(t *testing.T) {
   123  	opts := []grpc_zap.Option{
   124  		grpc_zap.WithDurationField(grpc_zap.DurationToDurationField),
   125  	}
   126  	b := newBaseZapSuite(t)
   127  	b.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
   128  		grpc.WithUnaryInterceptor(grpc_zap.UnaryClientInterceptor(b.log, opts...)),
   129  		grpc.WithStreamInterceptor(grpc_zap.StreamClientInterceptor(b.log, opts...)),
   130  	}
   131  	suite.Run(t, &zapClientOverrideSuite{b})
   132  }
   133  
   134  type zapClientOverrideSuite struct {
   135  	*zapBaseSuite
   136  }
   137  
   138  func (s *zapClientOverrideSuite) TestPing_HasOverrides() {
   139  	_, err := s.Client.Ping(s.SimpleCtx(), goodPing)
   140  	require.NoError(s.T(), err, "there must be not be an error on a successful call")
   141  
   142  	msgs := s.getOutputJSONs()
   143  	require.Len(s.T(), msgs, 1, "one log statement should be logged")
   144  
   145  	assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain service name")
   146  	assert.Equal(s.T(), msgs[0]["grpc.method"], "Ping", "all lines must contain method name")
   147  	assert.Equal(s.T(), msgs[0]["msg"], "finished client unary call", "handler's message must contain user message")
   148  
   149  	assert.NotContains(s.T(), msgs[0], "grpc.time_ms", "handler's message must not contain default duration")
   150  	assert.Contains(s.T(), msgs[0], "grpc.duration", "handler's message must contain overridden duration")
   151  }
   152  
   153  func (s *zapClientOverrideSuite) TestPingList_HasOverrides() {
   154  	stream, err := s.Client.PingList(s.SimpleCtx(), goodPing)
   155  	require.NoError(s.T(), err, "should not fail on establishing the stream")
   156  	for {
   157  		_, err := stream.Recv()
   158  		if err == io.EOF {
   159  			break
   160  		}
   161  		require.NoError(s.T(), err, "reading stream should not fail")
   162  	}
   163  	msgs := s.getOutputJSONs()
   164  	require.Len(s.T(), msgs, 1, "one log statement should be logged")
   165  
   166  	assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain service name")
   167  	assert.Equal(s.T(), msgs[0]["grpc.method"], "PingList", "all lines must contain method name")
   168  	assert.Equal(s.T(), msgs[0]["msg"], "finished client streaming call", "handler's message must contain user message")
   169  	assert.Equal(s.T(), msgs[0]["span.kind"], "client", "all lines must contain the kind of call (client)")
   170  	assert.Equal(s.T(), msgs[0]["level"], "debug", "must be logged on debug level.")
   171  
   172  	assert.NotContains(s.T(), msgs[0], "grpc.time_ms", "handler's message must not contain default duration")
   173  	assert.Contains(s.T(), msgs[0], "grpc.duration", "handler's message must contain overridden duration")
   174  }
   175  
   176  func TestZapLoggingClientMessageProducerSuite(t *testing.T) {
   177  	opts := []grpc_zap.Option{
   178  		grpc_zap.WithMessageProducer(StubMessageProducer),
   179  	}
   180  	b := newBaseZapSuite(t)
   181  	b.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
   182  		grpc.WithUnaryInterceptor(grpc_zap.UnaryClientInterceptor(b.log, opts...)),
   183  		grpc.WithStreamInterceptor(grpc_zap.StreamClientInterceptor(b.log, opts...)),
   184  	}
   185  	suite.Run(t, &zapClientMessageProducerSuite{b})
   186  }
   187  
   188  type zapClientMessageProducerSuite struct {
   189  	*zapBaseSuite
   190  }
   191  
   192  func (s *zapClientMessageProducerSuite) TestPing_HasOverriddenMessageProducer() {
   193  	_, err := s.Client.Ping(s.SimpleCtx(), goodPing)
   194  	require.NoError(s.T(), err, "there must be not be an error on a successful call")
   195  
   196  	msgs := s.getOutputJSONs()
   197  	require.Len(s.T(), msgs, 1, "one log statement should be logged")
   198  
   199  	assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain service name")
   200  	assert.Equal(s.T(), msgs[0]["grpc.method"], "Ping", "all lines must contain method name")
   201  	assert.Equal(s.T(), msgs[0]["msg"], "custom message", "handler's message must contain user message")
   202  }
   203  

View as plain text