Skip to content

Conversation

@loadkrnis
Copy link

@velo

Problem

Slf4jLogger and JavaLogger currently behave differently depending on the logging level.

When the SLF4J level is set to INFO or higher (or java.util.logging is above FINE),
logAndRebufferResponse() does not delegate to super.logAndRebufferResponse().
As a result, the response body is not rebuffered and remains a one-time InputStream.

This leads to several practical issues:

  • ErrorDecoder implementations cannot reliably read the response body from error responses
  • Calling response.body().toString() returns an instance reference (e.g. feign@...) instead of the actual content
  • Application behavior varies across environments with different logging configurations

Solution

Always delegate to super.logAndRebufferResponse(), regardless of the logger’s runtime level.

This ensures that response buffering follows Feign’s Logger.Level consistently and is no longer affected by SLF4J or JUL configuration differences.


Result

  • Response bodies are always rebuffered when Logger.Level >= HEADERS, regardless of SLF4J or JUL logging levels
  • Consistent behavior is guaranteed across environments
  • ErrorDecoder can reliably read response bodies

Changes

  • Slf4jLogger: Removed conditional logic in logAndRebufferResponse() and always delegate to super

Behavioral Impact

Memory usage

  • Response bodies are now buffered in memory when Logger.Level is HEADERS or FULL, even if the underlying SLF4J / JUL level is INFO or higher

All existing tests pass.

I’m happy to adjust this approach if there are alternative suggestions or concerns from the maintainers.


Alternative Approach Considered

Option: Lazy buffering with LazyBufferedBody

As an alternative to eager buffering, we also considered introducing a LazyBufferedBody wrapper that would:

  • Wrap non-repeatable streams when Logger.Level >= HEADERS
  • Buffer the body into memory only on first access (for example, by an ErrorDecoder)
  • Avoid allocating memory when the response body is never read

This approach could reduce memory usage in some cases, especially when response bodies are rarely accessed.

The current implementation is not meant to assert that eager rebuffering is the only or best solution.
Rather, it serves as a concrete proposal to make the existing behavior consistent.

If maintainers prefer a different approach—such as lazy buffering—I’m happy to adjust the implementation based on that feedback.

Fixes #1336

loadkrnis and others added 3 commits January 14, 2026 15:36
…ging disabled

When SLF4J/java.util.logging level is above DEBUG/FINE, logAndRebufferResponse()
was returning the original response without rebuffering. This caused:

1. ErrorDecoder failing to read response body from error responses
2. Inconsistent behavior where response.body() returns different types
   (byte[] vs InputStream) based solely on logging configuration

Now always delegates to super.logAndRebufferResponse() to ensure consistent
rebuffering based on Feign's Logger.Level, while logging output is still
controlled by the underlying logger's level check in log() method.

- Remove conditional in Slf4jLogger.logAndRebufferResponse()
- Remove conditional in JavaLogger.logAndRebufferResponse()
- Add unit tests for rebuffering at various logging levels

Fixes OpenFeign#1336
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slf4jLogger returns different response depending on logging level

1 participant