Skip to content

RestClient - Consider adding request/response logs #33753

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
michaelisvy opened this issue Oct 19, 2024 · 5 comments
Closed

RestClient - Consider adding request/response logs #33753

michaelisvy opened this issue Oct 19, 2024 · 5 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: superseded An issue that has been superseded by another type: enhancement A general enhancement

Comments

@michaelisvy
Copy link

Hi,
I commonly add logs to the RestClient based on this nice example from Craig Walls: https://github.com/habuma/logging-interceptor/tree/main

Would it make sense to add request/response logging capabilities as part of the RestClient? That way, it would be simple for everyone to set it up.

Thanks!

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 19, 2024
@rstoyanchev rstoyanchev self-assigned this Oct 22, 2024
@rstoyanchev rstoyanchev added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Oct 22, 2024
@rstoyanchev
Copy link
Contributor

Most of the code in Craig's example is to wrap the response for buffering, and the same can be applied through the BufferingClientHttpRequestFactory. The actual logging is quite straight forward:

@Bean
RestClient.Builder restClientBuilder() {
	ClientHttpRequestInterceptor interceptor = (req, reqBody, ex) -> {
		ClientHttpResponse response = ex.execute(req, reqBody);
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Request body: \n===========\n{}\n===========", new String(reqBody, StandardCharsets.UTF_8));
			LOGGER.debug("Response body:\n===========\n{}\n===========", response.getBody());
		}
		return response;
	};
	return RestClient.builder()
			.requestFactory(new BufferingClientHttpRequestFactory(new JdkClientHttpRequestFactory()))
			.requestInterceptor(interceptor);
}

However, this forces explicit creation of the underlying HttpClientRequestFactory, and that may not be desirable if you want to just add logging, but otherwise let the request factory be configured elsewhere. The other issue is that use of interception involves the InterceptingClientHttpRequestFactory, which also buffers the request, and that causes an unnecessary use of an additional buffering OutputStream and additional copy for the request body.

We can look to improve buffering by making it more of an internal concern, the way InterceptingClientHttpRequestFactory is applied. Doing so would allow us to handle interception and buffering concerns together as needed. On the Builder we can allow buffering to be enabled, with an additional callback to potentially make decisions per request. The BufferingClientHttpRequestFactory could be deprecated.

@rstoyanchev rstoyanchev added this to the 7.0.x milestone Oct 22, 2024
@rstoyanchev rstoyanchev added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Oct 22, 2024
@rstoyanchev rstoyanchev reopened this Oct 22, 2024
@rstoyanchev
Copy link
Contributor

The above commit closes #33763, but incorrectly referenced this issue.

@michaelisvy
Copy link
Author

thanks!
I was thinking it would be great to have something as simple to configure as the logger we have in Spring AI. I'm using this with Spring AI:

this.chatClient = builder
        .defaultSystem("You are a helpful assistant writing in formal English")
        .defaultAdvisors(new SimpleLoggerAdvisor())
        .build();

Not sure if we could have something like that with the RestClient?

return RestClient.builder()
			.requestInterceptor(new SimpleLoggerInterceptor());

@rstoyanchev
Copy link
Contributor

rstoyanchev commented Oct 24, 2024

A built-in interceptor becomes more complex for what should be a simple task. Take AbstractRequestLoggingFilter and sub-classes on the server side for example. You need to account for different logging frameworks, flexible choices for what to log and what not to, etc. Also, logging content comes with a buffering trade-off that arguably should be a conscious decision.

I think we should make buffering easy to enable. The actual logging then should be simple. I created #33785, and will close this for now.

@rstoyanchev rstoyanchev closed this as not planned Won't fix, can't repro, duplicate, stale Oct 24, 2024
@rstoyanchev rstoyanchev removed this from the 7.0.x milestone Oct 24, 2024
@rstoyanchev rstoyanchev added the status: superseded An issue that has been superseded by another label Oct 24, 2024
@michaelisvy
Copy link
Author

sounds good, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: superseded An issue that has been superseded by another type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants