github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/grpclogging/server_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package grpclogging_test
     8  
     9  import (
    10  	"context"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"net"
    15  	"time"
    16  
    17  	"github.com/hechain20/hechain/common/flogging"
    18  	"github.com/hechain20/hechain/common/grpclogging"
    19  	"github.com/hechain20/hechain/common/grpclogging/fakes"
    20  	"github.com/hechain20/hechain/common/grpclogging/testpb"
    21  	. "github.com/onsi/ginkgo"
    22  	. "github.com/onsi/gomega"
    23  	"go.uber.org/zap"
    24  	"go.uber.org/zap/zapcore"
    25  	"go.uber.org/zap/zaptest/observer"
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/codes"
    28  	"google.golang.org/grpc/credentials"
    29  	"google.golang.org/grpc/status"
    30  )
    31  
    32  var _ = Describe("Server", func() {
    33  	var (
    34  		fakeEchoService   *fakes.EchoServiceServer
    35  		echoServiceClient testpb.EchoServiceClient
    36  
    37  		listener        net.Listener
    38  		serveCompleteCh chan error
    39  		server          *grpc.Server
    40  		clientConn      *grpc.ClientConn
    41  
    42  		core     zapcore.Core
    43  		observed *observer.ObservedLogs
    44  		logger   *zap.Logger
    45  	)
    46  
    47  	BeforeEach(func() {
    48  		var err error
    49  		listener, err = net.Listen("tcp", "127.0.0.1:0")
    50  		Expect(err).NotTo(HaveOccurred())
    51  
    52  		core, observed = observer.New(zap.LevelEnablerFunc(func(zapcore.Level) bool { return true }))
    53  		logger = zap.New(core, zap.AddCaller()).Named("test-logger")
    54  
    55  		fakeEchoService = &fakes.EchoServiceServer{}
    56  		fakeEchoService.EchoStub = func(ctx context.Context, msg *testpb.Message) (*testpb.Message, error) {
    57  			msg.Sequence++
    58  			return msg, nil
    59  		}
    60  		fakeEchoService.EchoStreamStub = func(stream testpb.EchoService_EchoStreamServer) error {
    61  			msg, err := stream.Recv()
    62  			if err == io.EOF {
    63  				return nil
    64  			}
    65  			if err != nil {
    66  				return err
    67  			}
    68  
    69  			msg.Sequence++
    70  			return stream.Send(msg)
    71  		}
    72  
    73  		server = grpc.NewServer(
    74  			grpc.Creds(credentials.NewTLS(serverTLSConfig)),
    75  			grpc.StreamInterceptor(grpclogging.StreamServerInterceptor(logger)),
    76  			grpc.UnaryInterceptor(grpclogging.UnaryServerInterceptor(logger)),
    77  		)
    78  
    79  		testpb.RegisterEchoServiceServer(server, fakeEchoService)
    80  		serveCompleteCh = make(chan error, 1)
    81  		go func() { serveCompleteCh <- server.Serve(listener) }()
    82  
    83  		dialOpts := []grpc.DialOption{
    84  			grpc.WithTransportCredentials(credentials.NewTLS(clientTLSConfig)),
    85  			grpc.WithBlock(),
    86  		}
    87  		clientConn, err = grpc.Dial(listener.Addr().String(), dialOpts...)
    88  		Expect(err).NotTo(HaveOccurred())
    89  
    90  		echoServiceClient = testpb.NewEchoServiceClient(clientConn)
    91  	})
    92  
    93  	AfterEach(func() {
    94  		clientConn.Close()
    95  		server.Stop()
    96  
    97  		Eventually(serveCompleteCh).Should(Receive())
    98  	})
    99  
   100  	Describe("UnaryServerInterceptor", func() {
   101  		It("logs request data", func() {
   102  			ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
   103  			defer cancel()
   104  
   105  			resp, err := echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"})
   106  			Expect(err).NotTo(HaveOccurred())
   107  			Expect(resp).To(Equal(&testpb.Message{Message: "hi", Sequence: 1}))
   108  
   109  			var logMessages []string
   110  			for _, entry := range observed.AllUntimed() {
   111  				logMessages = append(logMessages, entry.Message)
   112  			}
   113  			Expect(logMessages).To(ConsistOf(
   114  				"received unary request", // received payload
   115  				"sending unary response", // sending payload
   116  				"unary call completed",
   117  			))
   118  
   119  			for _, entry := range observed.AllUntimed() {
   120  				keyNames := map[string]struct{}{}
   121  				for _, field := range entry.Context {
   122  					keyNames[field.Key] = struct{}{}
   123  				}
   124  
   125  				switch entry.LoggerName {
   126  				case "test-logger":
   127  					Expect(entry.Level).To(Equal(zapcore.InfoLevel))
   128  					Expect(entry.Context).To(HaveLen(8))
   129  					Expect(keyNames).To(HaveLen(8))
   130  				case "test-logger.payload":
   131  					Expect(entry.Level).To(Equal(zapcore.DebugLevel - 1))
   132  					Expect(entry.Context).To(HaveLen(6))
   133  					Expect(keyNames).To(HaveLen(6))
   134  				default:
   135  					Fail("unexpected logger name: " + entry.LoggerName)
   136  				}
   137  				Expect(entry.Caller.String()).To(ContainSubstring("grpclogging/server.go"))
   138  
   139  				for _, field := range entry.Context {
   140  					switch field.Key {
   141  					case "grpc.code":
   142  						Expect(field.Type).To(Equal(zapcore.StringerType))
   143  						Expect(field.Interface).To(Equal(codes.OK))
   144  					case "grpc.call_duration":
   145  						Expect(field.Type).To(Equal(zapcore.DurationType))
   146  						Expect(field.Integer).NotTo(BeZero())
   147  					case "grpc.service":
   148  						Expect(field.Type).To(Equal(zapcore.StringType))
   149  						Expect(field.String).To(Equal("testpb.EchoService"))
   150  					case "grpc.method":
   151  						Expect(field.Type).To(Equal(zapcore.StringType))
   152  						Expect(field.String).To(Equal("Echo"))
   153  					case "grpc.request_deadline":
   154  						ctx, _ := fakeEchoService.EchoArgsForCall(0)
   155  						deadline, ok := ctx.Deadline()
   156  						Expect(ok).To(BeTrue())
   157  						Expect(field.Type).To(Equal(zapcore.TimeType))
   158  						Expect(field.Integer).NotTo(BeZero())
   159  						Expect(time.Unix(0, field.Integer)).To(BeTemporally("==", deadline))
   160  					case "grpc.peer_address":
   161  						Expect(field.Type).To(Equal(zapcore.StringType))
   162  						Expect(field.String).To(HavePrefix("127.0.0.1"))
   163  					case "grpc.peer_subject":
   164  						Expect(field.Type).To(Equal(zapcore.StringType))
   165  						Expect(field.String).To(HavePrefix("CN=client"))
   166  					case "message":
   167  						Expect(field.Type).To(Equal(zapcore.ReflectType))
   168  					case "error":
   169  						Expect(field.Type).To(Equal(zapcore.ErrorType))
   170  					case "":
   171  						Expect(field.Type).To(Equal(zapcore.SkipType))
   172  					default:
   173  						Fail("unexpected context field: " + field.Key)
   174  					}
   175  				}
   176  			}
   177  		})
   178  
   179  		It("provides a decorated context", func() {
   180  			ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
   181  			defer cancel()
   182  			_, err := echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"})
   183  			Expect(err).NotTo(HaveOccurred())
   184  
   185  			Expect(fakeEchoService.EchoCallCount()).To(Equal(1))
   186  			echoContext, _ := fakeEchoService.EchoArgsForCall(0)
   187  			zapFields := grpclogging.ZapFields(echoContext)
   188  
   189  			keyNames := []string{}
   190  			for _, field := range zapFields {
   191  				keyNames = append(keyNames, field.Key)
   192  			}
   193  			Expect(keyNames).To(ConsistOf(
   194  				"grpc.service",
   195  				"grpc.method",
   196  				"grpc.request_deadline",
   197  				"grpc.peer_address",
   198  				"grpc.peer_subject",
   199  			))
   200  		})
   201  
   202  		Context("when the request ends with an unknown error", func() {
   203  			var expectedErr error
   204  
   205  			BeforeEach(func() {
   206  				expectedErr = errors.New("gah!")
   207  				fakeEchoService.EchoReturns(nil, expectedErr)
   208  
   209  				_, err := echoServiceClient.Echo(context.Background(), &testpb.Message{Message: "hi"})
   210  				Expect(err).To(HaveOccurred())
   211  			})
   212  
   213  			It("logs the unknown code", func() {
   214  				entries := observed.FilterMessage("unary call completed").FilterField(zap.Stringer("grpc.code", codes.Unknown)).AllUntimed()
   215  				Expect(entries).To(HaveLen(1))
   216  			})
   217  
   218  			It("logs the error", func() {
   219  				entries := observed.FilterMessage("unary call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed()
   220  				Expect(entries).To(HaveLen(1))
   221  			})
   222  		})
   223  
   224  		Context("when the request ends with a grpc status error", func() {
   225  			var expectedErr error
   226  
   227  			BeforeEach(func() {
   228  				expectedErr = &statusError{Status: status.New(codes.Aborted, "aborted")}
   229  				fakeEchoService.EchoReturns(nil, expectedErr)
   230  
   231  				_, err := echoServiceClient.Echo(context.Background(), &testpb.Message{Message: "hi"})
   232  				Expect(err).To(HaveOccurred())
   233  			})
   234  
   235  			It("logs the corect code", func() {
   236  				entries := observed.FilterMessage("unary call completed").FilterField(zap.Stringer("grpc.code", codes.Aborted)).AllUntimed()
   237  				Expect(entries).To(HaveLen(1))
   238  			})
   239  
   240  			It("logs the error", func() {
   241  				entries := observed.FilterMessage("unary call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed()
   242  				Expect(entries).To(HaveLen(1))
   243  			})
   244  		})
   245  
   246  		Context("when options are used", func() {
   247  			var (
   248  				listener        net.Listener
   249  				serveCompleteCh chan error
   250  				server          *grpc.Server
   251  				clientConn      *grpc.ClientConn
   252  
   253  				leveler        *fakes.Leveler
   254  				payloadLeveler *fakes.Leveler
   255  			)
   256  
   257  			BeforeEach(func() {
   258  				var err error
   259  				listener, err = net.Listen("tcp", "127.0.0.1:0")
   260  				Expect(err).NotTo(HaveOccurred())
   261  
   262  				leveler = &fakes.Leveler{}
   263  				leveler.Returns(zapcore.ErrorLevel)
   264  				payloadLeveler = &fakes.Leveler{}
   265  				payloadLeveler.Returns(zapcore.WarnLevel)
   266  
   267  				server = grpc.NewServer(
   268  					grpc.UnaryInterceptor(grpclogging.UnaryServerInterceptor(
   269  						logger,
   270  						grpclogging.WithLeveler(grpclogging.LevelerFunc(leveler.Spy)),
   271  						grpclogging.WithPayloadLeveler(grpclogging.LevelerFunc(payloadLeveler.Spy)),
   272  					)),
   273  				)
   274  
   275  				testpb.RegisterEchoServiceServer(server, fakeEchoService)
   276  				serveCompleteCh = make(chan error, 1)
   277  				go func() { serveCompleteCh <- server.Serve(listener) }()
   278  
   279  				clientConn, err = grpc.Dial(listener.Addr().String(), grpc.WithInsecure(), grpc.WithBlock())
   280  				Expect(err).NotTo(HaveOccurred())
   281  				echoServiceClient = testpb.NewEchoServiceClient(clientConn)
   282  
   283  				ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
   284  				defer cancel()
   285  
   286  				_, err = echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"})
   287  				Expect(err).NotTo(HaveOccurred())
   288  			})
   289  
   290  			AfterEach(func() {
   291  				clientConn.Close()
   292  				server.Stop()
   293  
   294  				Eventually(serveCompleteCh).Should(Receive())
   295  			})
   296  
   297  			It("uses the levels returned by the levelers", func() {
   298  				Expect(leveler.CallCount()).To(Equal(1))
   299  				Expect(observed.FilterMessage("unary call completed").AllUntimed()[0].Level).To(Equal(zapcore.ErrorLevel))
   300  
   301  				Expect(payloadLeveler.CallCount()).To(Equal(1))
   302  				Expect(observed.FilterMessage("received unary request").AllUntimed()).To(HaveLen(1))
   303  				Expect(observed.FilterMessage("received unary request").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel))
   304  				Expect(observed.FilterMessage("sending unary response").AllUntimed()).To(HaveLen(1))
   305  				Expect(observed.FilterMessage("sending unary response").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel))
   306  			})
   307  
   308  			It("provides the decorated context and full method name to the levelers", func() {
   309  				Expect(leveler.CallCount()).To(Equal(1))
   310  				ctx, fullMethod := leveler.ArgsForCall(0)
   311  				Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty())
   312  				Expect(fullMethod).To(Equal("/testpb.EchoService/Echo"))
   313  
   314  				Expect(payloadLeveler.CallCount()).To(Equal(1))
   315  				ctx, fullMethod = payloadLeveler.ArgsForCall(0)
   316  				Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty())
   317  				Expect(fullMethod).To(Equal("/testpb.EchoService/Echo"))
   318  			})
   319  		})
   320  	})
   321  
   322  	Describe("StreamServerInterceptor", func() {
   323  		It("logs stream data", func() {
   324  			ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
   325  			defer cancel()
   326  			streamClient, err := echoServiceClient.EchoStream(ctx)
   327  			Expect(err).NotTo(HaveOccurred())
   328  
   329  			err = streamClient.Send(&testpb.Message{Message: "hello"})
   330  			Expect(err).NotTo(HaveOccurred())
   331  
   332  			msg, err := streamClient.Recv()
   333  			Expect(err).NotTo(HaveOccurred())
   334  			Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1}))
   335  
   336  			err = streamClient.CloseSend()
   337  			Expect(err).NotTo(HaveOccurred())
   338  			_, err = streamClient.Recv()
   339  			Expect(err).To(Equal(io.EOF))
   340  
   341  			var logMessages []string
   342  			for _, entry := range observed.AllUntimed() {
   343  				logMessages = append(logMessages, entry.Message)
   344  			}
   345  			Expect(logMessages).To(ConsistOf(
   346  				"received stream message", // received payload
   347  				"sending stream message",  // sending payload
   348  				"streaming call completed",
   349  			))
   350  
   351  			for _, entry := range observed.AllUntimed() {
   352  				keyNames := map[string]struct{}{}
   353  				for _, field := range entry.Context {
   354  					keyNames[field.Key] = struct{}{}
   355  				}
   356  
   357  				switch entry.LoggerName {
   358  				case "test-logger":
   359  					Expect(entry.Level).To(Equal(zapcore.InfoLevel))
   360  					Expect(entry.Context).To(HaveLen(8))
   361  					Expect(keyNames).To(HaveLen(8))
   362  				case "test-logger.payload":
   363  					Expect(entry.Level).To(Equal(zapcore.DebugLevel - 1))
   364  					Expect(entry.Context).To(HaveLen(6))
   365  					Expect(keyNames).To(HaveLen(6))
   366  				default:
   367  					Fail("unexpected logger name: " + entry.LoggerName)
   368  				}
   369  				Expect(entry.Caller.String()).To(ContainSubstring("grpclogging/server.go"))
   370  
   371  				for _, field := range entry.Context {
   372  					switch field.Key {
   373  					case "grpc.code":
   374  						Expect(field.Type).To(Equal(zapcore.StringerType))
   375  						Expect(field.Interface).To(Equal(codes.OK))
   376  					case "grpc.call_duration":
   377  						Expect(field.Type).To(Equal(zapcore.DurationType))
   378  						Expect(field.Integer).NotTo(BeZero())
   379  					case "grpc.service":
   380  						Expect(field.Type).To(Equal(zapcore.StringType))
   381  						Expect(field.String).To(Equal("testpb.EchoService"))
   382  					case "grpc.method":
   383  						Expect(field.Type).To(Equal(zapcore.StringType))
   384  						Expect(field.String).To(Equal("EchoStream"))
   385  					case "grpc.request_deadline":
   386  						stream := fakeEchoService.EchoStreamArgsForCall(0)
   387  						deadline, ok := stream.Context().Deadline()
   388  						Expect(ok).To(BeTrue())
   389  						Expect(field.Type).To(Equal(zapcore.TimeType))
   390  						Expect(field.Integer).NotTo(BeZero())
   391  						Expect(time.Unix(0, field.Integer)).To(BeTemporally("==", deadline))
   392  					case "grpc.peer_address":
   393  						Expect(field.Type).To(Equal(zapcore.StringType))
   394  						Expect(field.String).To(HavePrefix("127.0.0.1"))
   395  					case "grpc.peer_subject":
   396  						Expect(field.Type).To(Equal(zapcore.StringType))
   397  						Expect(field.String).To(HavePrefix("CN=client"))
   398  					case "message":
   399  						Expect(field.Type).To(Equal(zapcore.ReflectType))
   400  					case "error":
   401  						Expect(field.Type).To(Equal(zapcore.ErrorType))
   402  					case "":
   403  						Expect(field.Type).To(Equal(zapcore.SkipType))
   404  					default:
   405  						Fail("unexpected context field: " + field.Key)
   406  					}
   407  				}
   408  			}
   409  		})
   410  
   411  		It("provides a decorated context", func() {
   412  			ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
   413  			defer cancel()
   414  			streamClient, err := echoServiceClient.EchoStream(ctx)
   415  			Expect(err).NotTo(HaveOccurred())
   416  
   417  			err = streamClient.Send(&testpb.Message{Message: "hello"})
   418  			Expect(err).NotTo(HaveOccurred())
   419  
   420  			msg, err := streamClient.Recv()
   421  			Expect(err).NotTo(HaveOccurred())
   422  			Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1}))
   423  
   424  			err = streamClient.CloseSend()
   425  			Expect(err).NotTo(HaveOccurred())
   426  			_, err = streamClient.Recv()
   427  			Expect(err).To(Equal(io.EOF))
   428  
   429  			Expect(fakeEchoService.EchoStreamCallCount()).To(Equal(1))
   430  			echoStream := fakeEchoService.EchoStreamArgsForCall(0)
   431  			zapFields := grpclogging.ZapFields(echoStream.Context())
   432  
   433  			keyNames := []string{}
   434  			for _, field := range zapFields {
   435  				keyNames = append(keyNames, field.Key)
   436  			}
   437  			Expect(keyNames).To(ConsistOf(
   438  				"grpc.service",
   439  				"grpc.method",
   440  				"grpc.request_deadline",
   441  				"grpc.peer_address",
   442  				"grpc.peer_subject",
   443  			))
   444  		})
   445  
   446  		Context("when tls client auth is missing", func() {
   447  			var clientConn *grpc.ClientConn
   448  
   449  			BeforeEach(func() {
   450  				dialOpts := []grpc.DialOption{
   451  					grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(caCertPool, "")),
   452  					grpc.WithBlock(),
   453  				}
   454  				var err error
   455  				clientConn, err = grpc.Dial(listener.Addr().String(), dialOpts...)
   456  				Expect(err).NotTo(HaveOccurred())
   457  
   458  				echoServiceClient = testpb.NewEchoServiceClient(clientConn)
   459  			})
   460  
   461  			AfterEach(func() {
   462  				clientConn.Close()
   463  			})
   464  
   465  			It("omits grpc.peer_subject", func() {
   466  				streamClient, err := echoServiceClient.EchoStream(context.Background())
   467  				Expect(err).NotTo(HaveOccurred())
   468  
   469  				err = streamClient.Send(&testpb.Message{Message: "hello"})
   470  				Expect(err).NotTo(HaveOccurred())
   471  
   472  				msg, err := streamClient.Recv()
   473  				Expect(err).NotTo(HaveOccurred())
   474  				Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1}))
   475  
   476  				err = streamClient.CloseSend()
   477  				Expect(err).NotTo(HaveOccurred())
   478  				_, err = streamClient.Recv()
   479  				Expect(err).To(Equal(io.EOF))
   480  
   481  				for _, entry := range observed.AllUntimed() {
   482  					keyNames := map[string]struct{}{}
   483  					for _, field := range entry.Context {
   484  						keyNames[field.Key] = struct{}{}
   485  					}
   486  					Expect(keyNames).NotTo(HaveKey("grpc.peer_subject"))
   487  				}
   488  			})
   489  		})
   490  
   491  		Context("when the stream ends with an unknown error", func() {
   492  			var expectedErr error
   493  
   494  			BeforeEach(func() {
   495  				expectedErr = errors.New("gah!")
   496  				fakeEchoService.EchoStreamStub = func(stream testpb.EchoService_EchoStreamServer) error {
   497  					stream.Recv()
   498  					return expectedErr
   499  				}
   500  
   501  				streamClient, err := echoServiceClient.EchoStream(context.Background())
   502  				Expect(err).NotTo(HaveOccurred())
   503  
   504  				err = streamClient.Send(&testpb.Message{Message: "hello"})
   505  				Expect(err).NotTo(HaveOccurred())
   506  				_, err = streamClient.Recv()
   507  				Expect(err).To(HaveOccurred())
   508  			})
   509  
   510  			It("logs the unknown code", func() {
   511  				entries := observed.FilterMessage("streaming call completed").FilterField(zap.Stringer("grpc.code", codes.Unknown)).AllUntimed()
   512  				Expect(entries).To(HaveLen(1))
   513  			})
   514  
   515  			It("logs the error", func() {
   516  				entries := observed.FilterMessage("streaming call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed()
   517  				Expect(entries).To(HaveLen(1))
   518  			})
   519  		})
   520  
   521  		Context("when the stream ends with a grpc status error", func() {
   522  			var expectedErr error
   523  
   524  			BeforeEach(func() {
   525  				errCh := make(chan error)
   526  				fakeEchoService.EchoStreamStub = func(svr testpb.EchoService_EchoStreamServer) error {
   527  					return <-errCh
   528  				}
   529  
   530  				streamClient, err := echoServiceClient.EchoStream(context.Background())
   531  				Expect(err).NotTo(HaveOccurred())
   532  
   533  				err = streamClient.Send(&testpb.Message{Message: "hello"})
   534  				Expect(err).NotTo(HaveOccurred())
   535  
   536  				expectedErr = &statusError{Status: status.New(codes.Aborted, "aborted")}
   537  				errCh <- expectedErr
   538  
   539  				_, err = streamClient.Recv()
   540  				Expect(err).To(HaveOccurred())
   541  			})
   542  
   543  			It("logs the corect code", func() {
   544  				entries := observed.FilterMessage("streaming call completed").FilterField(zap.Stringer("grpc.code", codes.Aborted)).AllUntimed()
   545  				Expect(entries).To(HaveLen(1))
   546  			})
   547  
   548  			It("logs the error", func() {
   549  				entries := observed.FilterMessage("streaming call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed()
   550  				Expect(entries).To(HaveLen(1))
   551  			})
   552  		})
   553  
   554  		Context("when options are used", func() {
   555  			var (
   556  				listener        net.Listener
   557  				serveCompleteCh chan error
   558  				server          *grpc.Server
   559  				clientConn      *grpc.ClientConn
   560  
   561  				leveler        *fakes.Leveler
   562  				payloadLeveler *fakes.Leveler
   563  			)
   564  
   565  			BeforeEach(func() {
   566  				var err error
   567  				listener, err = net.Listen("tcp", "127.0.0.1:0")
   568  				Expect(err).NotTo(HaveOccurred())
   569  
   570  				leveler = &fakes.Leveler{}
   571  				leveler.Returns(zapcore.ErrorLevel)
   572  				payloadLeveler = &fakes.Leveler{}
   573  				payloadLeveler.Returns(zapcore.WarnLevel)
   574  
   575  				server = grpc.NewServer(
   576  					grpc.StreamInterceptor(grpclogging.StreamServerInterceptor(
   577  						logger,
   578  						grpclogging.WithLeveler(grpclogging.LevelerFunc(leveler.Spy)),
   579  						grpclogging.WithPayloadLeveler(grpclogging.LevelerFunc(payloadLeveler.Spy)),
   580  					)),
   581  				)
   582  
   583  				testpb.RegisterEchoServiceServer(server, fakeEchoService)
   584  				serveCompleteCh = make(chan error, 1)
   585  				go func() { serveCompleteCh <- server.Serve(listener) }()
   586  
   587  				clientConn, err = grpc.Dial(listener.Addr().String(), grpc.WithInsecure(), grpc.WithBlock())
   588  				Expect(err).NotTo(HaveOccurred())
   589  				echoServiceClient = testpb.NewEchoServiceClient(clientConn)
   590  
   591  				streamClient, err := echoServiceClient.EchoStream(context.Background())
   592  				Expect(err).NotTo(HaveOccurred())
   593  				err = streamClient.Send(&testpb.Message{Message: "hello"})
   594  				Expect(err).NotTo(HaveOccurred())
   595  				msg, err := streamClient.Recv()
   596  				Expect(err).NotTo(HaveOccurred())
   597  				Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1}))
   598  
   599  				err = streamClient.CloseSend()
   600  				Expect(err).NotTo(HaveOccurred())
   601  				_, err = streamClient.Recv()
   602  				Expect(err).To(Equal(io.EOF))
   603  			})
   604  
   605  			AfterEach(func() {
   606  				clientConn.Close()
   607  
   608  				err := listener.Close()
   609  				Expect(err).NotTo(HaveOccurred())
   610  				Eventually(serveCompleteCh).Should(Receive())
   611  			})
   612  
   613  			It("uses the levels returned by the levelers", func() {
   614  				Expect(leveler.CallCount()).To(Equal(1))
   615  				Expect(observed.FilterMessage("streaming call completed").AllUntimed()[0].Level).To(Equal(zapcore.ErrorLevel))
   616  
   617  				Expect(payloadLeveler.CallCount()).To(Equal(1))
   618  				Expect(observed.FilterMessage("received stream message").AllUntimed()).To(HaveLen(1))
   619  				Expect(observed.FilterMessage("received stream message").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel))
   620  				Expect(observed.FilterMessage("sending stream message").AllUntimed()).To(HaveLen(1))
   621  				Expect(observed.FilterMessage("sending stream message").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel))
   622  			})
   623  
   624  			It("provides the decorated context and full method name to the levelers", func() {
   625  				Expect(leveler.CallCount()).To(Equal(1))
   626  				ctx, fullMethod := leveler.ArgsForCall(0)
   627  				Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty())
   628  				Expect(fullMethod).To(Equal("/testpb.EchoService/EchoStream"))
   629  
   630  				Expect(payloadLeveler.CallCount()).To(Equal(1))
   631  				ctx, fullMethod = payloadLeveler.ArgsForCall(0)
   632  				Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty())
   633  				Expect(fullMethod).To(Equal("/testpb.EchoService/EchoStream"))
   634  			})
   635  		})
   636  	})
   637  
   638  	It("uses flogging.PayloadLevel as DefaultPayloadLevel", func() {
   639  		Expect(grpclogging.DefaultPayloadLevel).To(Equal(flogging.PayloadLevel))
   640  	})
   641  })
   642  
   643  type statusError struct{ *status.Status }
   644  
   645  func (s *statusError) GRPCStatus() *status.Status { return s.Status }
   646  
   647  func (s *statusError) Error() string {
   648  	return fmt.Sprintf("🎶 I'm a little error, short and sweet. Here is my message: %s. Here is my code: %d.🎶", s.Status.Message(), s.Status.Code())
   649  }