1
+ package no .nav .testnav .libs .reactivecore .logging ;
2
+
3
+ import io .netty .channel .ChannelDuplexHandler ;
4
+ import io .netty .channel .ChannelHandlerContext ;
5
+ import io .netty .channel .ChannelPromise ;
6
+ import io .netty .handler .codec .http .FullHttpMessage ;
7
+ import io .netty .handler .codec .http .FullHttpRequest ;
8
+ import io .netty .handler .codec .http .FullHttpResponse ;
9
+ import io .netty .handler .codec .http .HttpContent ;
10
+ import io .netty .handler .codec .http .HttpRequest ;
11
+ import io .netty .handler .codec .http .HttpResponse ;
12
+ import io .netty .handler .codec .http .LastHttpContent ;
13
+ import lombok .extern .slf4j .Slf4j ;
14
+ import org .springframework .boot .web .reactive .function .client .WebClientCustomizer ;
15
+ import org .springframework .http .client .reactive .ReactorClientHttpConnector ;
16
+ import org .springframework .stereotype .Component ;
17
+ import org .springframework .web .reactive .function .client .WebClient ;
18
+ import reactor .netty .http .client .HttpClient ;
19
+
20
+ import java .util .List ;
21
+ import java .util .Map ;
22
+
23
+ import static java .nio .charset .Charset .defaultCharset ;
24
+ import static java .util .stream .Collectors .joining ;
25
+
26
+ @ Slf4j
27
+ @ Component
28
+ public class WebClientLogger implements WebClientCustomizer {
29
+
30
+ @ Override
31
+ public void customize (WebClient .Builder webClientBuilder ) {
32
+
33
+ var httpClient = HttpClient .create ()
34
+ .doOnRequest ((httpClientRequest , connection ) -> connection .addHandlerFirst (new LoggingHandler ()));
35
+ webClientBuilder .clientConnector (new ReactorClientHttpConnector (httpClient ));
36
+ }
37
+
38
+ private static class LoggingHandler extends ChannelDuplexHandler {
39
+
40
+ @ Override
41
+ public void write (ChannelHandlerContext ctx , Object msg , ChannelPromise promise ) throws Exception {
42
+ if (msg instanceof FullHttpRequest request ) {
43
+ log .debug ("DOWNSTREAM REQUEST: METHOD: {}, URI: {}, BODY: {}, HEADERS: {}" ,
44
+ request .method (), request .uri (), request .content ().toString (defaultCharset ()),
45
+ tokenFilter (request .headers ().entries ()));
46
+ } else if (msg instanceof HttpRequest request ) {
47
+ log .debug ("DOWNSTREAM REQUEST: METHOD: {}, URI: {}, HEADERS: {}" ,
48
+ request .method (), request .uri (), tokenFilter (request .headers ().entries ()));
49
+ } else if (msg instanceof FullHttpMessage message ) {
50
+ log .debug ("DOWNSTREAM REQUEST: BODY: {}" ,
51
+ message .content ().toString (defaultCharset ()));
52
+ }
53
+ super .write (ctx , msg , promise );
54
+ }
55
+
56
+ @ Override
57
+ public void channelRead (ChannelHandlerContext ctx , Object msg ) throws Exception {
58
+ if (msg instanceof FullHttpResponse response ) {
59
+ log .debug ("DOWNSTREAM RESPONSE: STATUS: {}, BODY: {}, HEADERS: {}" ,
60
+ response .status ().code (), response .content ().toString (defaultCharset ()), response .headers ());
61
+ } else if (msg instanceof HttpResponse response ) {
62
+ log .debug ("DOWNSTREAM RESPONSE: STATUS: {}, HEADERS: {}" ,
63
+ response .status ().code (), response .headers ());
64
+ } else if (!(msg instanceof LastHttpContent ) && msg instanceof HttpContent httpContent ) {
65
+ log .debug ("DOWNSTREAM RESPONSE: BODY: {}" ,
66
+ httpContent .content ().toString (defaultCharset ()));
67
+ }
68
+ super .channelRead (ctx , msg );
69
+ }
70
+ }
71
+
72
+ private static String tokenFilter (List <Map .Entry <String , String >> headers ) {
73
+ return headers .stream ()
74
+ .map (header -> header .getKey () + ": " +
75
+ (header .getValue ().startsWith ("Bearer " ) ? "Bearer ******" : header .getValue ()))
76
+ .collect (joining (", " ));
77
+ }
78
+ }
0 commit comments