Last active
February 10, 2022 06:19
-
-
Save mikybars/1ea4ddb04f997d0ec4d4b973e033bfa1 to your computer and use it in GitHub Desktop.
Revisions
-
mikybars revised this gist
Feb 10, 2022 . No changes.There are no files selected for viewing
-
mikybars created this gist
Feb 10, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,147 @@ package com.inditex.mecretcond.infra.actuator; import static java.time.Instant.now; import static java.util.stream.Collectors.toList; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; import org.springframework.http.HttpRequest; import org.springframework.http.client.BufferingClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @Slf4j @Component @Endpoint(id = "rest-clients") @RequiredArgsConstructor public class RestClientLoggingEndpoint { private static final ClientHttpRequestInterceptor LOGGING_INTERCEPTOR = new LoggingInterceptor(); private static final BufferingClientHttpRequestFactory BUFFERING_CLIENT_HTTP_REQUEST_FACTORY = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()); private static final Duration MAX_TIME_WITH_LOGGING_ENABLED = Duration.ofMinutes(1L); private final Map<String, RestTemplate> restClientBeans; private final Map<String, ClientHttpRequestFactory> httpRequestFactories = new HashMap<>(); private final Map<String, Instant> activationTimes = new HashMap<>(); @Scheduled(fixedDelay = 30 * 1000) private void disableLoggingAfterAWhile() { List<String> exceededRestClients = activationTimes.keySet().stream() .filter(this::hasExceededTimeWithLoggingEnabled) .collect(toList()); exceededRestClients.forEach(this::disableLogging); // avoid concurrent modification } private boolean hasExceededTimeWithLoggingEnabled(String beanName) { Instant activatedAt = activationTimes.get(beanName); return Duration.between(activatedAt, now()).compareTo(MAX_TIME_WITH_LOGGING_ENABLED) > 0; } @ReadOperation public List<String> getAvailableRestClients() { Set<String> beanNames = restClientBeans.keySet(); return new ArrayList<>(beanNames); } @WriteOperation public void toggleLogging(@Selector String beanName) { if (activationTimes.containsKey(beanName)) { disableLogging(beanName); } else { enableLogging(beanName); } } private void enableLogging(String beanName) { if (!restClientBeans.containsKey(beanName)) { return; } var restClient = restClientBeans.get(beanName); backUpHttpRequestFactory(beanName, restClient); setUpBuffering(restClient); setUpInterceptor(restClient); activationTimes.put(beanName, now()); log.debug("Logging enabled for rest client {}", beanName); } private void disableLogging(String beanName) { if (!restClientBeans.containsKey(beanName)) { return; } var restClient = restClientBeans.get(beanName); restoreHttpRequestFactory(beanName, restClient); removeInterceptor(restClient); activationTimes.remove(beanName); log.debug("Logging disabled for rest client {}", beanName); } private void restoreHttpRequestFactory(String beanName, RestTemplate restClient) { if (httpRequestFactories.containsKey(beanName)) { restClient.setRequestFactory(httpRequestFactories.get(beanName)); } } private void removeInterceptor(RestTemplate restClient) { restClient.getInterceptors().remove(LOGGING_INTERCEPTOR); } private void backUpHttpRequestFactory(String beanName, RestTemplate restClient) { httpRequestFactories.put(beanName, restClient.getRequestFactory()); } private void setUpBuffering(RestTemplate restClient) { restClient.setRequestFactory(BUFFERING_CLIENT_HTTP_REQUEST_FACTORY); } private void setUpInterceptor(RestTemplate restClient) { restClient.getInterceptors().add(LOGGING_INTERCEPTOR); } @Slf4j private static class LoggingInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest req, byte[] reqBody, ClientHttpRequestExecution ex) throws IOException { log.debug("Request body: {}", new String(reqBody, StandardCharsets.UTF_8)); ClientHttpResponse response = ex.execute(req, reqBody); InputStreamReader isr = new InputStreamReader(response.getBody(), StandardCharsets.UTF_8); try (var buffer = new BufferedReader(isr)) { String body = buffer.lines().collect(Collectors.joining("\n")); log.debug("Response body: {}", body); } return response; } } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,8 @@ # list all available rest client beans http :8080/actuator/rest-clients { "exampleRestClient" } # toggle logging for exampleRestClient http POST :8080/actuator/rest-clients/exampleRestClient