通常在集成feign的时候,都希望能够打印请求和相应日志。feign自有的日志打印不够友好
自定义feign.Client代理类
import com.google.common.collect.Sets;
import feign.Client;
import feign.Request;
import feign.Response;
import feign.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
public class FeignClientLoggerWrapper implements Client {
private static final Logger DEFAULT_LOGGER = LoggerFactory.getLogger(FeignClientLoggerWrapper.class);
private static final Set<String> LOGGER_HEADERS = Sets.newHashSet("req_id");
private static final int MAX_BODY_LENGTH = 4096;
private final Client client;
public FeignClientLoggerWrapper(Client client) {
this.client = client;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
// 打印请求
Logger logger = getLogger(request);
if (request.body() != null) {
logger.info("{} {} body={}", request.httpMethod(), request.url(), new String(request.body()));
} else {
logger.info("{} {} ", request.httpMethod(), request.url());
}
long start = System.currentTimeMillis();
Response response = client.execute(request, options);
// 打印response相应头
logHeader(response, logger);
long timeUsed = System.currentTimeMillis() - start;
try {
if (response.body().length() == null) {
logger.info("response size unknown");
return response;
} else {
if (response.body().length() > MAX_BODY_LENGTH) {
logger.info("response ignore size > {}", MAX_BODY_LENGTH);
return response;
} else {
// 打印返回
final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
logger.info("response {}", new String(bodyData));
return response.toBuilder().body(bodyData).build();
}
}
} finally {
// 打印耗时
logger.info("timeUsed = {}ms", timeUsed);
}
}
/**
* 获取client对应的Logger对象
*/
private Logger getLogger(Request request) {
if (request.requestTemplate() != null && request.requestTemplate().methodMetadata() != null && request.requestTemplate().methodMetadata().method() != null) {
return LoggerFactory.getLogger(request.requestTemplate().methodMetadata().method().getDeclaringClass().getName());
}
return DEFAULT_LOGGER;
}
private void logHeader(Response response, Logger logger) {
for (String loggerHeader : LOGGER_HEADERS) {
Collection<String> value = response.headers().get(loggerHeader);
if (value != null) {
logger.info("response Header:{} = {} ", loggerHeader, value);
}
}
}
}
针对单个Client使用
@FeignClient(name = "test-client", url = "${test.url}", configuration = {FeignClientLoggerWrapper.class})
public interface TestClient {
@PostMapping("/query")
BaseResp<XXXInfo> query(@RequestBody BaseRequest req);
}
基于AOP代理增强
配置feign.Client对象aop切面(略)。
基于全局配置
@Bean
public FeignClientLoggerWrapper feignClientLoggerWrapper(HttpClient httpClient) {
return new FeignClientLoggerWrapper(new ApacheHttpClient(httpClient));
}