feign
feign copied to clipboard
Slf4jLogger returns different response depending on logging level
package feign.slf4j;
public class Slf4jLogger extends feign.Logger {
...
@Override
protected Response logAndRebufferResponse(String configKey,
Level logLevel,
Response response,
long elapsedTime)
throws IOException {
if (logger.isDebugEnabled()) {
return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
}
return response;
}
...
}
It returns different response object depending on logging level.
When setting logging level above INFO, it returns just response
, and it's not same as logAndRebufferResponse
's return value.
So when I try to access response.body().toString()
in ErrorDecoder, I cannot get proper response value.
What I expected was json string value but I got feign.okhttp.OkHttpClient$1@blabla
It works fine with DEBUG/TRACE logging level.
Is it issue or am I missing something?
Why would you override the logger? Just use it as is. That is move all of the code to a custom logger helper class that will then utilize the passed in logger instance, e.g.
class LoggerHelper
{
public void logAndRebuffer...(Logger logger, ...) {
if (logger.isDebugEnabled()) {
....
}
}
}
And just make your logger helper methods return type void
. do not expect anything from a logger.
The basic cause of your dilemma is that you pass in an object and expect the logger to return the same object. just don't.
see line return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
which will return whatever super returns, which might not exactly be what you want.
@gaeulautumn This is intentional. When reading the data from the network, we must read the entire payload into memory. When using the logAndRebufferResponse
method as configured, we read the entire data stream in, log it, then wrap it again into a new byte array and return a new Response
instance. This is why you would see different instances of a Response
depending on log level.
If you want to access the data directly from the Response
object, you will need to honor the contract and use one of the as
methods, asReader
or asInputStream
to ensure consistent results.
@kdavisk6 Thank you for the detailed answer :D
BTW still there's a confusion that why one method(logAndRebufferResponse
) returns different format of response depending on log level.
(bcz... I spent a lot of time to find a error that happens only in PROD profile but not in SANDBOX profile ^^;)
I mean, isn't it supposed to be like below?
package feign.slf4j;
public class Slf4jLogger extends feign.Logger {
...
@Override
protected Response logAndRebufferResponse(String configKey,
Level logLevel,
Response response,
long elapsedTime)
throws IOException {
if (logger.isDebugEnabled()) {
return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
}
return rebufferResponse(response); // modified part (just a assumption)
}
...
}
Will wait for your opinion. Thanks.
Feign's Log Level controls how much information is included and only in the higher levels does it read and decode the response. On lower levels, you'll get the raw body, on higher levels, you'll get the content.