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 }