Feign has out of box logging mechanism and it can be achieved through simple steps.

If you are using spring-cloud-starter-feign

Feign using Slf4jLogger for logging.Feign logging documentation

As per doc, the below logging levels are available to configure,

  • NONE - No logging (DEFAULT).
  • BASIC - Log only the request method and URL and the response status code and execution time.
  • HEADERS - Log the basic information along with request and response headers.
  • FULL - Log the headers, body, and metadata for both requests and responses.

Injecting the Logger.Level bean is enough.

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }

OR

If you prefer using configuration properties to configured all @FeignClient, you can create configuration properties with default feign name.

feign:
  client:
    config:
      default:
        loggerLevel: basic

of if you are using a newer version (Spring Boot 3) the config will be like:

spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            loggerLevel: full

If you are using 'io.github.openfeign:feign-core'

If you are constructing the Feign builder then you can mention logLevel(Level.BASIC) as

Feign.builder()
    .logger(new Slf4jLogger())
    .logLevel(Level.BASIC)
    .target(SomeFeignClient.class, url);

We have the flexibility to customize the logging message

The default feign request and response logging

Request logging

Resopnse logging

we can customize the feign request, response logging pattern by overriding Logger#logRequest and Logger#logAndRebufferResponse methods. In the following example, we have customized request logging pattern

log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) ", request.httpMethod().name(), request.url(), bodyLength);

and response logging pattern

log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);

The Full example is


import feign.Logger;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

import static feign.Logger.Level.HEADERS;

@Slf4j
public class CustomFeignRequestLogging extends Logger {

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {

        if (logLevel.ordinal() >= HEADERS.ordinal()) {
            super.logRequest(configKey, logLevel, request);
        } else {
            int bodyLength = 0;
            if (request.requestBody().asBytes() != null) {
                bodyLength = request.requestBody().asBytes().length;
            }
            log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) ", request.httpMethod().name(), request.url(), bodyLength);
        }
    }

    @Override
    protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime)
            throws IOException {
        if (logLevel.ordinal() >= HEADERS.ordinal()) {
            return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
        } else {
            int status = response.status();
            Request request = response.request();
            log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);
            return response;   
        }        
    }


    @Override
    protected void log(String configKey, String format, Object... args) {
        log.debug(format(configKey, format, args));
    }

    protected String format(String configKey, String format, Object... args) {
        return String.format(methodTag(configKey) + format, args);
    }
}

NOTE: Request payload can be easily logged through

String bodyText =
              request.charset() != null ? new String(request.body(), request.charset()) : null;

but be careful writing the response payload after you are reading the input stream Util.toByteArray(response.body().asInputStream()) then you have to construct the response again like response.toBuilder().body(bodyData).build(). Otherwise, you will end up with the expection. The reason is response streams are read and always closed before returning, thats why the method is named as logAndRebufferResponse

How to use the custom CustomFeignRequestLogging?

If you are building feign client using just 'io.github.openfeign:feign-core'

Feign.builder()
     .logger(new CustomFeignRequestLogging())
     .logLevel(feign.Logger.Level.BASIC);

If you are using 'org.springframework.cloud:spring-cloud-starter-openfeign'

@Configuration
public class FeignLoggingConfiguration {

    @Bean
    public CustomFeignRequestLogging customFeignRequestLogging() {
        return new CustomFeignRequestLogging();
    }

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
}

Answer from Prasanth Rajendran on Stack Overflow
🌐
GitHub
github.com › PouyaPouryaie › feign-client
GitHub - PouyaPouryaie/feign-client: This repository demonstrates how to programmatically implement a Feign client in a Spring Boot application · GitHub
This class extends Feign's Logger to provide a custom logging implementation using SLF4j. It logs the full request and response information. This class implements ErrorDecoder to handle specific HTTP status codes from the server.
🌐
GitHub
github.com › OpenFeign › feign › blob › master › core › src › main › java › feign › Logger.java
feign/core/src/main/java/feign/Logger.java at master · OpenFeign/feign
* Override to log requests and responses using your own implementation. Messages will be http · * request and response text. * * @param configKey value of {@link Feign#configKey(Class, java.lang.reflect.Method)} * @param format {@link java.util.Formatter format string} * @param args arguments applied to {@code format} */ protected abstract void log(String configKey, String format, Object...
🌐
GitHub
github.com › OpenFeign › feign › issues › 1035
Log request (and response) in single batch · Issue #1035 · OpenFeign/feign
August 8, 2019 - Feign's Logger is logging once per request / response line item. For example, JavaLogger will log the following request / response pair by invoking java.util.logging.Logger 7 times: [SendsStuff#login] ---> POST http://localhost:61113/ HT...
Author: OpenFeign
🌐
Baeldung
baeldung.com › home › spring › spring boot › feign logging configuration
Feign Logging Configuration | Baeldung
February 26, 2025 - In this case, as it is a GET request, we don’t have a request body. The second part contains the response. It shows the headers and the body of the response. In this short tutorial, we have looked at the Feign client logging mechanism and how we can enable it. We saw that there are multiple ways to configure it based on our needs. The code backing this article is available on GitHub...
🌐
GitHub
github.com › OpenFeign › feign › issues › 598
How to log the server name which the request was sent to? · Issue #598 · OpenFeign/feign
November 3, 2017 - I am using a Feign Client to call a REST endpoint with success, and have logging turned on to FULL. This is helpfully shows me the request sent and the response received. However, I cannot see which server the request was sent to.
Author: OpenFeign
Top answer
1 of 6
83

Feign has out of box logging mechanism and it can be achieved through simple steps.

If you are using spring-cloud-starter-feign

Feign using Slf4jLogger for logging.Feign logging documentation

As per doc, the below logging levels are available to configure,

  • NONE - No logging (DEFAULT).
  • BASIC - Log only the request method and URL and the response status code and execution time.
  • HEADERS - Log the basic information along with request and response headers.
  • FULL - Log the headers, body, and metadata for both requests and responses.

Injecting the Logger.Level bean is enough.

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }

OR

If you prefer using configuration properties to configured all @FeignClient, you can create configuration properties with default feign name.

feign:
  client:
    config:
      default:
        loggerLevel: basic

of if you are using a newer version (Spring Boot 3) the config will be like:

spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            loggerLevel: full

If you are using 'io.github.openfeign:feign-core'

If you are constructing the Feign builder then you can mention logLevel(Level.BASIC) as

Feign.builder()
    .logger(new Slf4jLogger())
    .logLevel(Level.BASIC)
    .target(SomeFeignClient.class, url);

We have the flexibility to customize the logging message

The default feign request and response logging

Request logging

Resopnse logging

we can customize the feign request, response logging pattern by overriding Logger#logRequest and Logger#logAndRebufferResponse methods. In the following example, we have customized request logging pattern

log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) ", request.httpMethod().name(), request.url(), bodyLength);

and response logging pattern

log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);

The Full example is


import feign.Logger;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

import static feign.Logger.Level.HEADERS;

@Slf4j
public class CustomFeignRequestLogging extends Logger {

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {

        if (logLevel.ordinal() >= HEADERS.ordinal()) {
            super.logRequest(configKey, logLevel, request);
        } else {
            int bodyLength = 0;
            if (request.requestBody().asBytes() != null) {
                bodyLength = request.requestBody().asBytes().length;
            }
            log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) ", request.httpMethod().name(), request.url(), bodyLength);
        }
    }

    @Override
    protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime)
            throws IOException {
        if (logLevel.ordinal() >= HEADERS.ordinal()) {
            return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
        } else {
            int status = response.status();
            Request request = response.request();
            log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);
            return response;   
        }        
    }


    @Override
    protected void log(String configKey, String format, Object... args) {
        log.debug(format(configKey, format, args));
    }

    protected String format(String configKey, String format, Object... args) {
        return String.format(methodTag(configKey) + format, args);
    }
}

NOTE: Request payload can be easily logged through

String bodyText =
              request.charset() != null ? new String(request.body(), request.charset()) : null;

but be careful writing the response payload after you are reading the input stream Util.toByteArray(response.body().asInputStream()) then you have to construct the response again like response.toBuilder().body(bodyData).build(). Otherwise, you will end up with the expection. The reason is response streams are read and always closed before returning, thats why the method is named as logAndRebufferResponse

How to use the custom CustomFeignRequestLogging?

If you are building feign client using just 'io.github.openfeign:feign-core'

Feign.builder()
     .logger(new CustomFeignRequestLogging())
     .logLevel(feign.Logger.Level.BASIC);

If you are using 'org.springframework.cloud:spring-cloud-starter-openfeign'

@Configuration
public class FeignLoggingConfiguration {

    @Bean
    public CustomFeignRequestLogging customFeignRequestLogging() {
        return new CustomFeignRequestLogging();
    }

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
}

2 of 6
13

The accepted answer did not work for me until I added the following settings to my application.yml file:

logging:
  level:
    com:
      mypackage1:
        mysubackage1:
          mysubpackage2: DEBUG
🌐
GitHub
github.com › spring-cloud › spring-cloud-netflix › issues › 1769
Feign Logging Configuration Not Working As Documented · Issue #1769 · spring-cloud/spring-cloud-netflix
March 11, 2017 - Yet, when I execute a call to the Reservation Client such as: GET http://localhost:9999/reservations/names, nothing is written to the log. How does one properly enable logging of the Feign Client requests?
Find elsewhere
🌐
Poznachowski
blog.poznachowski.pl › posts › feign-slf4j-logger
Feign Slf4j Logger you wish you had // It's SOAP's Fault...
August 17, 2021 - You can change amount of log data you want, by changing SLF4j log level of a specific Feign client class. ... This Slf4j logger implementation is available at my Github.
🌐
GitHub
github.com › swagger-api › swagger-codegen › issues › 10550
How to add Feign Client Logging in SpringBoot through ...
November 8, 2020 - @Bean public ServicoPagamentoTicket2Api ticketApi() { ApiClient client = new ApiClient(); // https://stackoverflow.com/questions/42751269/feign-logging-not-working/59651045#59651045 client.getFeignBuilder().logLevel(Level.HEADERS); client.setBasePath(properties.getHost()); // Generated from swagger: https://demonstracao.parkingplus.com.br/servicos return client.buildClient(ServicoPagamentoTicket2Api.class); }
Author: swagger-api
🌐
Medium
bvn13.medium.com › normalized-logger-for-openfeign-8727b4e5d776
Normalized Logger for OpenFeign. Standard Feign logger provides the only… | by Vyacheslav Boyko | Medium
August 12, 2022 - feign: client: config: auth: logger-level: FULL · Main code of project is placed into https://gitea.bvn13.me/bvn13/OpenFeign-NormalizedLogger · Github clone of the repo is https://github.com/bvn13/OpenFeign-NormalizedLogger · Java · Feign · Logging · Microservices ·
🌐
GitHub
github.com › OpenFeign › feign › issues › 1215
Allow masking of request and response data when logging · Issue #1215 · OpenFeign/feign
April 24, 2020 - It would be nice to have a mechanism for masking the values of specific headers. if I could give some logging object the name of headers I want masked, then instead of the log events looking like this: [MyConnector#doSomething] Authorization: Bearer sdfsdfsdfsdfsdfsd ... It would also be nice when you have structured requests/responses (such as json or xml) to be able to mask the values at certain paths. ... { "Some Object": { "name": "My Object Name" } "Some Sensitive Object: { "name": "Some Sensitive Name" } } ... Trying to deal with these values after feign has already turned them into log events is very difficult and involves lots of ugly regexes.
Author: OpenFeign
🌐
GitHub
github.com › OpenFeign › feign
GitHub - OpenFeign/feign: Feign makes writing java http clients easier · GitHub
This model will be used by Feign itself throughout and provide clearer direction on how the Logger will be used. ... Refactor the Retry API to support user-supplied conditions and better control over back-off policies. This may result in non-backward-compatible breaking changes ... Allow for Future chaining and executor management for the request/response lifecycle.
Author: OpenFeign
🌐
GitHub
github.com › OpenFeign › feign › issues › 1912
Logging should happen after micrometer instrumentation · Issue #1912 · OpenFeign/feign
January 12, 2023 - Request logging happens at line 96 of SynchronousMethodHandler and client.execute called a few lines after that. However, micrometer observation starts in client.execute (in enriched client code), ...
Author: OpenFeign
🌐
GitHub
github.com › OpenFeign › feign › issues › 874
Log details as one message · Issue #874 · OpenFeign/feign
January 11, 2019 - tl;dr: Call log() only once for each request and response? I'm using feign.client.config.default.loggerLevel: full to log payload of an application deployed to Cloud Foundry in a dev/test environment. In Cloud Foundry, every line of log to stdout is treated as an independent log-event and sent to a log-drain.
Author: OpenFeign
🌐
Junhyunny
junhyunny.github.io › spring-boot › spring-cloud › logging-for-feign-client
FeignClient 로깅 적용하기 - Junhyunny’s Devlogs
April 25, 2026 - package action.in.blog.client; import action.in.blog.domain.Post; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "blog-client", url = "${server-url}") public interface BlogClient { @GetMapping("/health") String health(); @GetMapping("/search") String search(@RequestParam String keyword); @PostMapping("/post") Post createPost(@RequestBody Post post); } 테스트 코드를 통해 각 메서드별로 호출 시 출력되는 로그를 살펴본다.
🌐
GitHub
github.com › OpenFeign › feign › issues › 1888
Log HTTP body, not headers · Issue #1888 · OpenFeign/feign
December 19, 2022 - To do that you could create feign.Logger subclass, and rewrite logRequest and logAndRebufferResponse methods.
Author: OpenFeign
🌐
GitHub
github.com › sharanggupta › feign
GitHub - sharanggupta/feign: Feign makes writing java http clients easier · GitHub
This model will be used by Feign itself throughout and provide clearer direction on how the Logger will be used. ... Refactor the Retry API to support user-supplied conditions and better control over back-off policies. This may result in non-backward-compatible breaking changes ... Allow for Future chaining and executor management for the request/response lifecycle.
🌐
GitHub
github.com › EduardoRadieske › feign
GitHub - EduardoRadieske/feign: Feign makes writing java http clients easier - FORK · GitHub
This model will be used by Feign itself throughout and provide clearer direction on how the Logger will be used. ... Refactor the Retry API to support user-supplied conditions and better control over back-off policies. This may result in non-backward-compatible breaking changes ... Allow for Future chaining and executor management for the request/response lifecycle.
Author: EduardoRadieske