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

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