11package org .hibernate .infra .sync .jira .service .jira .client ;
22
33import java .util .Map ;
4+ import java .util .stream .Collectors ;
45
56import org .hibernate .infra .sync .jira .JiraConfig ;
67
8+ import org .jboss .resteasy .reactive .client .api .ClientLogger ;
9+ import org .jboss .resteasy .reactive .client .api .LoggingScope ;
10+
11+ import io .quarkus .logging .Log ;
712import io .quarkus .rest .client .reactive .QuarkusRestClientBuilder ;
13+ import io .vertx .core .MultiMap ;
14+ import io .vertx .core .buffer .Buffer ;
15+ import io .vertx .core .http .HttpClientRequest ;
16+ import io .vertx .core .http .HttpClientResponse ;
817
918public class JiraRestClientBuilder {
1019
@@ -13,14 +22,84 @@ public static JiraRestClient of(JiraConfig.Instance jira) {
1322
1423 Map <String , String > headers = jira .loginKind ().headers (jiraUser .email (), jiraUser .token ());
1524
16- return QuarkusRestClientBuilder .newBuilder ().baseUri (jira .apiUri ())
25+ QuarkusRestClientBuilder builder = QuarkusRestClientBuilder .newBuilder ().baseUri (jira .apiUri ())
1726 // TODO: Add a custom client logger that cleans up auth headers so that we do
1827 // not write any secrets to the logs ...
1928 .clientHeadersFactory ((incomingHeaders , clientOutgoingHeaders ) -> {
2029 for (var entry : headers .entrySet ()) {
2130 clientOutgoingHeaders .add (entry .getKey (), entry .getValue ());
2231 }
2332 return clientOutgoingHeaders ;
24- }).build (JiraRestClient .class );
33+ });
34+ if (jira .logRequests ()) {
35+ builder .clientLogger (CustomClientLogger .INSTANCE ).loggingScope (LoggingScope .REQUEST_RESPONSE );
36+ }
37+ return builder .build (JiraRestClient .class );
38+ }
39+
40+ private static class CustomClientLogger implements ClientLogger {
41+ private static final CustomClientLogger INSTANCE = new CustomClientLogger ();
42+
43+ @ Override
44+ public void setBodySize (int bodySize ) {
45+ // ignored
46+ }
47+
48+ @ Override
49+ public void logResponse (HttpClientResponse response , boolean redirect ) {
50+ response .bodyHandler (body -> Log .infof ("%s: %s %s, Status[%d %s], Headers[%s], Body:\n %s" ,
51+ redirect ? "Redirect" : "Response" , response .request ().getMethod (),
52+ response .request ().absoluteURI (), response .statusCode (), response .statusMessage (),
53+ asString (response .headers ()), bodyToString (body )));
54+ }
55+
56+ @ Override
57+ public void logRequest (HttpClientRequest request , Buffer body , boolean omitBody ) {
58+ if (omitBody ) {
59+ Log .infof ("Request: %s %s Headers[%s], Body omitted" , request .getMethod (), request .absoluteURI (),
60+ asString (request .headers ()));
61+ } else if (body == null || body .length () == 0 ) {
62+ Log .infof ("Request: %s %s Headers[%s], Empty body" , request .getMethod (), request .absoluteURI (),
63+ asString (request .headers ()));
64+ } else {
65+ Log .infof ("Request: %s %s Headers[%s], Body:\n %s" , request .getMethod (), request .absoluteURI (),
66+ asString (request .headers ()), bodyToString (body ));
67+ }
68+ }
69+
70+ private String bodyToString (Buffer body ) {
71+ if (body == null ) {
72+ return "" ;
73+ } else {
74+ return body .toString ();
75+ }
76+ }
77+
78+ private String asString (MultiMap headers ) {
79+ if (headers .isEmpty ()) {
80+ return "" ;
81+ }
82+ StringBuilder sb = new StringBuilder ();
83+ boolean isFirst = true ;
84+ for (Map .Entry <String , String > entry : headers ) {
85+ if (isFirst ) {
86+ isFirst = false ;
87+ } else {
88+ sb .append (' ' );
89+ }
90+ sb .append (entry .getKey ()).append ('=' ).append (entry .getValue ());
91+ }
92+ return headers .entries ().stream ()
93+ .map (entry -> "%s: %s" .formatted (entry .getKey (), sanitize (entry .getKey (), entry .getValue ())))
94+ .collect (Collectors .joining (" | " ));
95+ }
96+
97+ private String sanitize (String header , String value ) {
98+ if ("Authorization" .equalsIgnoreCase (header )) {
99+ return "***" ;
100+ } else {
101+ return value ;
102+ }
103+ }
25104 }
26105}
0 commit comments