1
- #region Copyright notice and license
1
+ #region Copyright notice and license
2
2
3
3
// Copyright 2019 The gRPC Authors
4
4
//
20
20
using System . Net . Http . Headers ;
21
21
using Greet ;
22
22
using Grpc . Core ;
23
+ using Grpc . Core . Interceptors ;
23
24
using Grpc . Net . Client . Internal ;
24
25
using Grpc . Net . Client . Tests . Infrastructure ;
25
26
using Grpc . Shared ;
@@ -239,11 +240,12 @@ public enum ResponseHandleAction
239
240
}
240
241
241
242
[ Test ]
242
- [ TestCase ( 0 , ResponseHandleAction . ResponseAsync ) ]
243
- [ TestCase ( 0 , ResponseHandleAction . ResponseHeadersAsync ) ]
244
- [ TestCase ( 0 , ResponseHandleAction . Dispose ) ]
245
- [ TestCase ( 1 , ResponseHandleAction . Nothing ) ]
246
- public async Task AsyncUnaryCall_CallFailed_NoUnobservedExceptions ( int expectedUnobservedExceptions , ResponseHandleAction action )
243
+ [ TestCase ( 0 , false , ResponseHandleAction . ResponseAsync ) ]
244
+ [ TestCase ( 0 , true , ResponseHandleAction . ResponseAsync ) ]
245
+ [ TestCase ( 0 , false , ResponseHandleAction . ResponseHeadersAsync ) ]
246
+ [ TestCase ( 0 , false , ResponseHandleAction . Dispose ) ]
247
+ [ TestCase ( 1 , false , ResponseHandleAction . Nothing ) ]
248
+ public async Task AsyncUnaryCall_CallFailed_NoUnobservedExceptions ( int expectedUnobservedExceptions , bool addClientInterceptor , ResponseHandleAction action )
247
249
{
248
250
// Arrange
249
251
var services = new ServiceCollection ( ) ;
@@ -267,7 +269,11 @@ public async Task AsyncUnaryCall_CallFailed_NoUnobservedExceptions(int expectedU
267
269
{
268
270
throw new Exception ( "Test error" ) ;
269
271
} ) ;
270
- var invoker = HttpClientCallInvokerFactory . Create ( httpClient , loggerFactory : loggerFactory ) ;
272
+ CallInvoker invoker = HttpClientCallInvokerFactory . Create ( httpClient , loggerFactory : loggerFactory ) ;
273
+ if ( addClientInterceptor )
274
+ {
275
+ invoker = invoker . Intercept ( new ClientLoggerInterceptor ( loggerFactory ) ) ;
276
+ }
271
277
272
278
// Act
273
279
logger . LogDebug ( "Starting call" ) ;
@@ -282,7 +288,7 @@ public async Task AsyncUnaryCall_CallFailed_NoUnobservedExceptions(int expectedU
282
288
// Assert
283
289
Assert . AreEqual ( expectedUnobservedExceptions , unobservedExceptions . Count ) ;
284
290
285
- static async Task MakeGrpcCallAsync ( ILogger logger , HttpClientCallInvoker invoker , ResponseHandleAction action )
291
+ static async Task MakeGrpcCallAsync ( ILogger logger , CallInvoker invoker , ResponseHandleAction action )
286
292
{
287
293
var runTask = Task . Run ( async ( ) =>
288
294
{
@@ -313,4 +319,157 @@ static async Task MakeGrpcCallAsync(ILogger logger, HttpClientCallInvoker invoke
313
319
TaskScheduler . UnobservedTaskException -= onUnobservedTaskException ;
314
320
}
315
321
}
322
+
323
+ private class ClientLoggerInterceptor : Interceptor
324
+ {
325
+ private readonly ILogger < ClientLoggerInterceptor > _logger ;
326
+
327
+ public ClientLoggerInterceptor ( ILoggerFactory loggerFactory )
328
+ {
329
+ _logger = loggerFactory . CreateLogger < ClientLoggerInterceptor > ( ) ;
330
+ }
331
+
332
+ public override TResponse BlockingUnaryCall < TRequest , TResponse > (
333
+ TRequest request ,
334
+ ClientInterceptorContext < TRequest , TResponse > context ,
335
+ BlockingUnaryCallContinuation < TRequest , TResponse > continuation )
336
+ {
337
+ LogCall ( context . Method ) ;
338
+ AddCallerMetadata ( ref context ) ;
339
+
340
+ try
341
+ {
342
+ return continuation ( request , context ) ;
343
+ }
344
+ catch ( Exception ex )
345
+ {
346
+ LogError ( ex ) ;
347
+ throw ;
348
+ }
349
+ }
350
+
351
+ public override AsyncUnaryCall < TResponse > AsyncUnaryCall < TRequest , TResponse > (
352
+ TRequest request ,
353
+ ClientInterceptorContext < TRequest , TResponse > context ,
354
+ AsyncUnaryCallContinuation < TRequest , TResponse > continuation )
355
+ {
356
+ LogCall ( context . Method ) ;
357
+ AddCallerMetadata ( ref context ) ;
358
+
359
+ try
360
+ {
361
+ var call = continuation ( request , context ) ;
362
+
363
+ return new AsyncUnaryCall < TResponse > ( HandleResponse ( call . ResponseAsync ) , call . ResponseHeadersAsync , call . GetStatus , call . GetTrailers , call . Dispose ) ;
364
+ }
365
+ catch ( Exception ex )
366
+ {
367
+ LogError ( ex ) ;
368
+ throw ;
369
+ }
370
+ }
371
+
372
+ private async Task < TResponse > HandleResponse < TResponse > ( Task < TResponse > t )
373
+ {
374
+ try
375
+ {
376
+ var response = await t ;
377
+ _logger . LogInformation ( $ "Response received: { response } ") ;
378
+ return response ;
379
+ }
380
+ catch ( Exception ex )
381
+ {
382
+ LogError ( ex ) ;
383
+ throw ;
384
+ }
385
+ }
386
+
387
+ public override AsyncClientStreamingCall < TRequest , TResponse > AsyncClientStreamingCall < TRequest , TResponse > (
388
+ ClientInterceptorContext < TRequest , TResponse > context ,
389
+ AsyncClientStreamingCallContinuation < TRequest , TResponse > continuation )
390
+ {
391
+ LogCall ( context . Method ) ;
392
+ AddCallerMetadata ( ref context ) ;
393
+
394
+ try
395
+ {
396
+ return continuation ( context ) ;
397
+ }
398
+ catch ( Exception ex )
399
+ {
400
+ LogError ( ex ) ;
401
+ throw ;
402
+ }
403
+ }
404
+
405
+ public override AsyncServerStreamingCall < TResponse > AsyncServerStreamingCall < TRequest , TResponse > (
406
+ TRequest request ,
407
+ ClientInterceptorContext < TRequest , TResponse > context ,
408
+ AsyncServerStreamingCallContinuation < TRequest , TResponse > continuation )
409
+ {
410
+ LogCall ( context . Method ) ;
411
+ AddCallerMetadata ( ref context ) ;
412
+
413
+ try
414
+ {
415
+ return continuation ( request , context ) ;
416
+ }
417
+ catch ( Exception ex )
418
+ {
419
+ LogError ( ex ) ;
420
+ throw ;
421
+ }
422
+ }
423
+
424
+ public override AsyncDuplexStreamingCall < TRequest , TResponse > AsyncDuplexStreamingCall < TRequest , TResponse > (
425
+ ClientInterceptorContext < TRequest , TResponse > context ,
426
+ AsyncDuplexStreamingCallContinuation < TRequest , TResponse > continuation )
427
+ {
428
+ LogCall ( context . Method ) ;
429
+ AddCallerMetadata ( ref context ) ;
430
+
431
+ try
432
+ {
433
+ return continuation ( context ) ;
434
+ }
435
+ catch ( Exception ex )
436
+ {
437
+ LogError ( ex ) ;
438
+ throw ;
439
+ }
440
+ }
441
+
442
+ private void LogCall < TRequest , TResponse > ( Method < TRequest , TResponse > method )
443
+ where TRequest : class
444
+ where TResponse : class
445
+ {
446
+ _logger . LogInformation ( $ "Starting call. Name: { method . Name } . Type: { method . Type } . Request: { typeof ( TRequest ) } . Response: { typeof ( TResponse ) } ") ;
447
+ }
448
+
449
+ private void AddCallerMetadata < TRequest , TResponse > ( ref ClientInterceptorContext < TRequest , TResponse > context )
450
+ where TRequest : class
451
+ where TResponse : class
452
+ {
453
+ var headers = context . Options . Headers ;
454
+
455
+ // Call doesn't have a headers collection to add to.
456
+ // Need to create a new context with headers for the call.
457
+ if ( headers == null )
458
+ {
459
+ headers = new Metadata ( ) ;
460
+ var options = context . Options . WithHeaders ( headers ) ;
461
+ context = new ClientInterceptorContext < TRequest , TResponse > ( context . Method , context . Host , options ) ;
462
+ }
463
+
464
+ // Add caller metadata to call headers
465
+ headers . Add ( "caller-user" , Environment . UserName ) ;
466
+ headers . Add ( "caller-machine" , Environment . MachineName ) ;
467
+ headers . Add ( "caller-os" , Environment . OSVersion . ToString ( ) ) ;
468
+ }
469
+
470
+ private void LogError ( Exception ex )
471
+ {
472
+ _logger . LogError ( ex , $ "Call error: { ex . Message } ") ;
473
+ }
474
+ }
316
475
}
0 commit comments