본문 바로가기

Backend/SpringBoot

[Spring Boot] Feign Client 로그 미동작 해결

Feign Client의 logLevel을 FULL로 설정하면 통신과정에서 주고받는 정보 등을 모두 log로 확인할 수 있습니다.

하지만 jar로 빌드 후 서비스를 배포하면 log가 보이지 않게 됩니다.

해당 현상에 대해 원인 파악 후 알게 된 해결방법을 작성합니다.

문제

  • Jar File로 배포 후 서비스 동작 시 Feign Client의 log가 확인되지 않는다.

원인

Feign Client를 만드는 과정에서부터 시작됩니다.

@Configuration
public class VCAClientConfig {
    @Bean
    public VCAClient vcaClient(@Autowired ObjectMapper objectMapper,
                               @Value("${client.vca.url}") String url) {
        return Feign.builder()
                .client(new OkHttpClient())
                .encoder(new JacksonEncoder(objectMapper))
                .decoder(new JacksonDecoder(objectMapper))
                .contract(new SpringMvcContract())
                .logger(new Slf4jLogger())
                .logLevel(Logger.Level.FULL)
                .target(VCAClient.class, url);
    }
}

 

Feign Client를 직접 Bean객체로 명시하여 만들게 되었는데, 해당 코드에 작성된 것처럼 logger를 직접 지정하였고, logLevel을 FULL로 지정하였습니다.

이렇게만 보면 문제 되는 사항은 없어 보이는데, 내부 동작을 살펴보니 원인을 알게 되었습니다.

 

우선 확인할 곳은 Feign Class의 Build 함수입니다.

public abstract class Feign {
    ...
    
    public Feign build() {
      ...
      // 생성과정에 logger가 전달된다.
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
              
      ...
    }
  }
  
  ...
}

코드 블록에서 확인할 수 있듯 Feign Client가 빌드되는 과정에서 제가 직접 지정한 loggerSynchronousMethodHandler의 생성에 전달되는 것을 확인할 수 있습니다.

 

그러면 이 SynchronousMethodHandler를 확인해봅시다.

디버그 상태로 FeignClient를 동작시키면 SynchronousMethodHandler에서 executeAndDecode 함수가 호출되는 것을 확인할 수 있습니다.

final class SynchronousMethodHandler implements MethodHandler {
	...
    
    Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
        Request request = targetRequest(template);
		
        // log Level이 NONE이 아니여야만 동작한다.
        if (logLevel != Logger.Level.NONE) {
          // Build과정에서 전달한 logger의 logRequest 함수가 호출되는 것이 확인.
          logger.logRequest(metadata.configKey(), logLevel, request);
        }

        ...
      }
      
  	...
  }

해당 함수에는 logLevel이 NONE이 아니면 앞서 제가 전달한 logger의 logRequest 함수를 호출하는 것을 확인할 수 있습니다.

저는 logLevel을 FULL로 명시했으므로 당연히 logger의 logRequest함수가 호출되게 됩니다.

그럼 처음으로 다시 돌아와서 FeignClient에게 전달한 Slf4jLogger의 logRequest함수를 확인해봅시다.

public class Slf4jLogger extends feign.Logger {
  ...
  
  @Override
  protected void logRequest(String configKey, Level logLevel, Request request) {
  	// logger의 모드가 Debug시에만 동작하는 것을 확인할 수 있다.
    if (logger.isDebugEnabled()) {
      super.logRequest(configKey, logLevel, request);
    }
  }
  
  ...
}

최종적으로 Log가 노출되지 않는 문제는 서비스 배포 시 동작 모드를 debug로 지정하지 않아서, 결국 Slf4jLogger를 사용 중인 Feign Client는 log를 출력하지 않게 됩니다.

해결방법

원인을 파악했으니 해결방법은 간단합니다.

실행 시 Logger가 동작할 수 있도록 Debug상태로 변경해주면 되는데, 서비스 전체를 debug로 동작할 필요는 없습니다.

log를 실제로 호출하는 패키지는 package faign입니다. 해당 패키지만 debug로 지정하면 되므로 application.properties에 아래와 같이 작성하면 됩니다.

logging.level.feign=debug