github.com/yimialmonte/fabric@v2.1.1+incompatible/common/grpclogging/server_test.go (about) 1 /* 2 Copyright IBM Corp. 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/hyperledger/fabric/common/flogging" 18 "github.com/hyperledger/fabric/common/grpclogging" 19 "github.com/hyperledger/fabric/common/grpclogging/fakes" 20 "github.com/hyperledger/fabric/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 const TimeThreshold = 100 * time.Millisecond 33 34 var _ = Describe("Server", func() { 35 var ( 36 fakeEchoService *fakes.EchoServiceServer 37 echoServiceClient testpb.EchoServiceClient 38 39 listener net.Listener 40 serveCompleteCh chan error 41 server *grpc.Server 42 clientConn *grpc.ClientConn 43 44 core zapcore.Core 45 observed *observer.ObservedLogs 46 logger *zap.Logger 47 ) 48 49 BeforeEach(func() { 50 var err error 51 listener, err = net.Listen("tcp", "127.0.0.1:0") 52 Expect(err).NotTo(HaveOccurred()) 53 54 core, observed = observer.New(zap.LevelEnablerFunc(func(zapcore.Level) bool { return true })) 55 logger = zap.New(core, zap.AddCaller()).Named("test-logger") 56 57 fakeEchoService = &fakes.EchoServiceServer{} 58 fakeEchoService.EchoStub = func(ctx context.Context, msg *testpb.Message) (*testpb.Message, error) { 59 msg.Sequence++ 60 return msg, nil 61 } 62 fakeEchoService.EchoStreamStub = func(stream testpb.EchoService_EchoStreamServer) error { 63 msg, err := stream.Recv() 64 if err == io.EOF { 65 return nil 66 } 67 if err != nil { 68 return err 69 } 70 71 msg.Sequence++ 72 return stream.Send(msg) 73 } 74 75 server = grpc.NewServer( 76 grpc.Creds(credentials.NewTLS(serverTLSConfig)), 77 grpc.StreamInterceptor(grpclogging.StreamServerInterceptor(logger)), 78 grpc.UnaryInterceptor(grpclogging.UnaryServerInterceptor(logger)), 79 ) 80 81 testpb.RegisterEchoServiceServer(server, fakeEchoService) 82 serveCompleteCh = make(chan error, 1) 83 go func() { serveCompleteCh <- server.Serve(listener) }() 84 85 dialOpts := []grpc.DialOption{ 86 grpc.WithTransportCredentials(credentials.NewTLS(clientTLSConfig)), 87 grpc.WithBlock(), 88 } 89 clientConn, err = grpc.Dial(listener.Addr().String(), dialOpts...) 90 Expect(err).NotTo(HaveOccurred()) 91 92 echoServiceClient = testpb.NewEchoServiceClient(clientConn) 93 }) 94 95 AfterEach(func() { 96 clientConn.Close() 97 server.Stop() 98 99 Eventually(serveCompleteCh).Should(Receive()) 100 }) 101 102 Describe("UnaryServerInterceptor", func() { 103 It("logs request data", func() { 104 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 105 defer cancel() 106 107 resp, err := echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"}) 108 Expect(err).NotTo(HaveOccurred()) 109 Expect(resp).To(Equal(&testpb.Message{Message: "hi", Sequence: 1})) 110 111 var logMessages []string 112 for _, entry := range observed.AllUntimed() { 113 logMessages = append(logMessages, entry.Message) 114 } 115 Expect(logMessages).To(ConsistOf( 116 "received unary request", // received payload 117 "sending unary response", // sending payload 118 "unary call completed", 119 )) 120 121 for _, entry := range observed.AllUntimed() { 122 keyNames := map[string]struct{}{} 123 for _, field := range entry.Context { 124 keyNames[field.Key] = struct{}{} 125 } 126 127 switch entry.LoggerName { 128 case "test-logger": 129 Expect(entry.Level).To(Equal(zapcore.InfoLevel)) 130 Expect(entry.Context).To(HaveLen(8)) 131 Expect(keyNames).To(HaveLen(8)) 132 case "test-logger.payload": 133 Expect(entry.Level).To(Equal(zapcore.DebugLevel - 1)) 134 Expect(entry.Context).To(HaveLen(6)) 135 Expect(keyNames).To(HaveLen(6)) 136 default: 137 Fail("unexpected logger name: " + entry.LoggerName) 138 } 139 Expect(entry.Caller.String()).To(ContainSubstring("grpclogging/server.go")) 140 141 for _, field := range entry.Context { 142 switch field.Key { 143 case "grpc.code": 144 Expect(field.Type).To(Equal(zapcore.StringerType)) 145 Expect(field.Interface).To(Equal(codes.OK)) 146 case "grpc.call_duration": 147 Expect(field.Type).To(Equal(zapcore.DurationType)) 148 Expect(field.Integer).NotTo(BeZero()) 149 case "grpc.service": 150 Expect(field.Type).To(Equal(zapcore.StringType)) 151 Expect(field.String).To(Equal("testpb.EchoService")) 152 case "grpc.method": 153 Expect(field.Type).To(Equal(zapcore.StringType)) 154 Expect(field.String).To(Equal("Echo")) 155 case "grpc.request_deadline": 156 deadline, ok := ctx.Deadline() 157 Expect(ok).To(BeTrue()) 158 Expect(field.Type).To(Equal(zapcore.TimeType)) 159 Expect(field.Integer).NotTo(BeZero()) 160 Expect(time.Unix(0, field.Integer)).To(BeTemporally("~", deadline, TimeThreshold)) 161 case "grpc.peer_address": 162 Expect(field.Type).To(Equal(zapcore.StringType)) 163 Expect(field.String).To(HavePrefix("127.0.0.1")) 164 case "grpc.peer_subject": 165 Expect(field.Type).To(Equal(zapcore.StringType)) 166 Expect(field.String).To(HavePrefix("CN=client")) 167 case "message": 168 Expect(field.Type).To(Equal(zapcore.ReflectType)) 169 case "error": 170 Expect(field.Type).To(Equal(zapcore.ErrorType)) 171 case "": 172 Expect(field.Type).To(Equal(zapcore.SkipType)) 173 default: 174 Fail("unexpected context field: " + field.Key) 175 } 176 } 177 } 178 }) 179 180 It("provides a decorated context", func() { 181 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 182 defer cancel() 183 _, err := echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"}) 184 Expect(err).NotTo(HaveOccurred()) 185 186 Expect(fakeEchoService.EchoCallCount()).To(Equal(1)) 187 echoContext, _ := fakeEchoService.EchoArgsForCall(0) 188 zapFields := grpclogging.ZapFields(echoContext) 189 190 keyNames := []string{} 191 for _, field := range zapFields { 192 keyNames = append(keyNames, field.Key) 193 } 194 Expect(keyNames).To(ConsistOf( 195 "grpc.service", 196 "grpc.method", 197 "grpc.request_deadline", 198 "grpc.peer_address", 199 "grpc.peer_subject", 200 )) 201 }) 202 203 Context("when the request ends with an unknown error", func() { 204 var expectedErr error 205 206 BeforeEach(func() { 207 expectedErr = errors.New("gah!") 208 fakeEchoService.EchoReturns(nil, expectedErr) 209 210 _, err := echoServiceClient.Echo(context.Background(), &testpb.Message{Message: "hi"}) 211 Expect(err).To(HaveOccurred()) 212 }) 213 214 It("logs the unknown code", func() { 215 entries := observed.FilterMessage("unary call completed").FilterField(zap.Stringer("grpc.code", codes.Unknown)).AllUntimed() 216 Expect(entries).To(HaveLen(1)) 217 }) 218 219 It("logs the error", func() { 220 entries := observed.FilterMessage("unary call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed() 221 Expect(entries).To(HaveLen(1)) 222 }) 223 }) 224 225 Context("when the request ends with a grpc status error", func() { 226 var expectedErr error 227 228 BeforeEach(func() { 229 expectedErr = &statusError{Status: status.New(codes.Aborted, "aborted")} 230 fakeEchoService.EchoReturns(nil, expectedErr) 231 232 _, err := echoServiceClient.Echo(context.Background(), &testpb.Message{Message: "hi"}) 233 Expect(err).To(HaveOccurred()) 234 }) 235 236 It("logs the corect code", func() { 237 entries := observed.FilterMessage("unary call completed").FilterField(zap.Stringer("grpc.code", codes.Aborted)).AllUntimed() 238 Expect(entries).To(HaveLen(1)) 239 }) 240 241 It("logs the error", func() { 242 entries := observed.FilterMessage("unary call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed() 243 Expect(entries).To(HaveLen(1)) 244 }) 245 }) 246 247 Context("when options are used", func() { 248 var ( 249 listener net.Listener 250 serveCompleteCh chan error 251 server *grpc.Server 252 clientConn *grpc.ClientConn 253 254 leveler *fakes.Leveler 255 payloadLeveler *fakes.Leveler 256 ) 257 258 BeforeEach(func() { 259 var err error 260 listener, err = net.Listen("tcp", "127.0.0.1:0") 261 Expect(err).NotTo(HaveOccurred()) 262 263 leveler = &fakes.Leveler{} 264 leveler.Returns(zapcore.ErrorLevel) 265 payloadLeveler = &fakes.Leveler{} 266 payloadLeveler.Returns(zapcore.WarnLevel) 267 268 server = grpc.NewServer( 269 grpc.UnaryInterceptor(grpclogging.UnaryServerInterceptor( 270 logger, 271 grpclogging.WithLeveler(grpclogging.LevelerFunc(leveler.Spy)), 272 grpclogging.WithPayloadLeveler(grpclogging.LevelerFunc(payloadLeveler.Spy)), 273 )), 274 ) 275 276 testpb.RegisterEchoServiceServer(server, fakeEchoService) 277 serveCompleteCh = make(chan error, 1) 278 go func() { serveCompleteCh <- server.Serve(listener) }() 279 280 clientConn, err = grpc.Dial(listener.Addr().String(), grpc.WithInsecure(), grpc.WithBlock()) 281 Expect(err).NotTo(HaveOccurred()) 282 echoServiceClient = testpb.NewEchoServiceClient(clientConn) 283 284 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 285 defer cancel() 286 287 _, err = echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"}) 288 Expect(err).NotTo(HaveOccurred()) 289 }) 290 291 AfterEach(func() { 292 clientConn.Close() 293 server.Stop() 294 295 Eventually(serveCompleteCh).Should(Receive()) 296 }) 297 298 It("uses the levels returned by the levelers", func() { 299 Expect(leveler.CallCount()).To(Equal(1)) 300 Expect(observed.FilterMessage("unary call completed").AllUntimed()[0].Level).To(Equal(zapcore.ErrorLevel)) 301 302 Expect(payloadLeveler.CallCount()).To(Equal(1)) 303 Expect(observed.FilterMessage("received unary request").AllUntimed()).To(HaveLen(1)) 304 Expect(observed.FilterMessage("received unary request").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel)) 305 Expect(observed.FilterMessage("sending unary response").AllUntimed()).To(HaveLen(1)) 306 Expect(observed.FilterMessage("sending unary response").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel)) 307 }) 308 309 It("provides the decorated context and full method name to the levelers", func() { 310 Expect(leveler.CallCount()).To(Equal(1)) 311 ctx, fullMethod := leveler.ArgsForCall(0) 312 Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty()) 313 Expect(fullMethod).To(Equal("/testpb.EchoService/Echo")) 314 315 Expect(payloadLeveler.CallCount()).To(Equal(1)) 316 ctx, fullMethod = payloadLeveler.ArgsForCall(0) 317 Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty()) 318 Expect(fullMethod).To(Equal("/testpb.EchoService/Echo")) 319 }) 320 }) 321 }) 322 323 Describe("StreamServerInterceptor", func() { 324 It("logs stream data", func() { 325 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 326 defer cancel() 327 streamClient, err := echoServiceClient.EchoStream(ctx) 328 Expect(err).NotTo(HaveOccurred()) 329 330 err = streamClient.Send(&testpb.Message{Message: "hello"}) 331 Expect(err).NotTo(HaveOccurred()) 332 333 msg, err := streamClient.Recv() 334 Expect(err).NotTo(HaveOccurred()) 335 Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1})) 336 337 err = streamClient.CloseSend() 338 Expect(err).NotTo(HaveOccurred()) 339 _, err = streamClient.Recv() 340 Expect(err).To(Equal(io.EOF)) 341 342 var logMessages []string 343 for _, entry := range observed.AllUntimed() { 344 logMessages = append(logMessages, entry.Message) 345 } 346 Expect(logMessages).To(ConsistOf( 347 "received stream message", // received payload 348 "sending stream message", // sending payload 349 "streaming call completed", 350 )) 351 352 for _, entry := range observed.AllUntimed() { 353 keyNames := map[string]struct{}{} 354 for _, field := range entry.Context { 355 keyNames[field.Key] = struct{}{} 356 } 357 358 switch entry.LoggerName { 359 case "test-logger": 360 Expect(entry.Level).To(Equal(zapcore.InfoLevel)) 361 Expect(entry.Context).To(HaveLen(8)) 362 Expect(keyNames).To(HaveLen(8)) 363 case "test-logger.payload": 364 Expect(entry.Level).To(Equal(zapcore.DebugLevel - 1)) 365 Expect(entry.Context).To(HaveLen(6)) 366 Expect(keyNames).To(HaveLen(6)) 367 default: 368 Fail("unexpected logger name: " + entry.LoggerName) 369 } 370 Expect(entry.Caller.String()).To(ContainSubstring("grpclogging/server.go")) 371 372 for _, field := range entry.Context { 373 switch field.Key { 374 case "grpc.code": 375 Expect(field.Type).To(Equal(zapcore.StringerType)) 376 Expect(field.Interface).To(Equal(codes.OK)) 377 case "grpc.call_duration": 378 Expect(field.Type).To(Equal(zapcore.DurationType)) 379 Expect(field.Integer).NotTo(BeZero()) 380 case "grpc.service": 381 Expect(field.Type).To(Equal(zapcore.StringType)) 382 Expect(field.String).To(Equal("testpb.EchoService")) 383 case "grpc.method": 384 Expect(field.Type).To(Equal(zapcore.StringType)) 385 Expect(field.String).To(Equal("EchoStream")) 386 case "grpc.request_deadline": 387 deadline, ok := ctx.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, TimeThreshold)) 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 }