fix: - BFI 调用:完整出入参日志
This commit is contained in:
+12
@@ -26,8 +26,13 @@
|
||||
package org.springblade.common.config;
|
||||
|
||||
|
||||
import feign.Logger;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.common.feign.CustomFeignLogger;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* 公共封装包配置类
|
||||
@@ -38,4 +43,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
@AllArgsConstructor
|
||||
public class BladeCommonConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnClass(name = "feign.Logger")
|
||||
public Logger feignLogger() {
|
||||
return new CustomFeignLogger();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.common.feign;
|
||||
|
||||
import feign.Logger;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import feign.Util;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 自定义Feign日志记录器,只记录出入参信息
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
public class CustomFeignLogger extends Logger {
|
||||
|
||||
private static final String BINARY_CONTENT_TYPE_PREFIX = "application/octet-stream";
|
||||
private static final String IMAGE_CONTENT_TYPE_PREFIX = "image/";
|
||||
private static final String AUDIO_CONTENT_TYPE_PREFIX = "audio/";
|
||||
private static final String VIDEO_CONTENT_TYPE_PREFIX = "video/";
|
||||
|
||||
@Override
|
||||
protected void log(String configKey, String format, Object... args) {
|
||||
// 不处理默认日志格式
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void logRequest(String configKey, Level logLevel, Request request) {
|
||||
String url = request.url();
|
||||
String method = request.httpMethod().name();
|
||||
Map<String, Collection<String>> headers = request.headers();
|
||||
byte[] body = request.body();
|
||||
|
||||
String bodyStr;
|
||||
if (body == null || body.length == 0) {
|
||||
bodyStr = "[无]";
|
||||
} else if (isBinaryContent(getContentType(headers))) {
|
||||
bodyStr = "[二进制数据,长度=" + body.length + "字节]";
|
||||
} else {
|
||||
bodyStr = new String(body, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
log.info("===> [{}] {} {} | Headers: {} | Body: {}", configKey, method, url, headers, bodyStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long millis) throws IOException {
|
||||
String url = response.request().url();
|
||||
int status = response.status();
|
||||
Map<String, Collection<String>> headers = response.headers();
|
||||
|
||||
if (response.body() == null) {
|
||||
log.info("<==== [{}] {} | Status: {} | Duration: {}ms | Body: [空响应]", configKey, url, status, millis);
|
||||
return response;
|
||||
}
|
||||
|
||||
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
|
||||
String bodyStr;
|
||||
if (bodyData.length == 0) {
|
||||
bodyStr = "[空响应]";
|
||||
} else if (isBinaryContent(getContentType(headers))) {
|
||||
bodyStr = "[二进制数据]";
|
||||
} else {
|
||||
bodyStr = new String(bodyData, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
log.info("<==== [{}] {} | Status: {} | Duration: {}ms | Body: {}", configKey, url, status, millis, bodyStr);
|
||||
|
||||
return response.toBuilder().body(bodyData).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Content-Type
|
||||
*/
|
||||
private String getContentType(Map<String, Collection<String>> headers) {
|
||||
Collection<String> contentTypes = headers.get("Content-Type");
|
||||
if (contentTypes != null && !contentTypes.isEmpty()) {
|
||||
return contentTypes.iterator().next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为二进制内容
|
||||
*/
|
||||
private boolean isBinaryContent(String contentType) {
|
||||
if (contentType == null || contentType.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String lowerContentType = contentType.toLowerCase();
|
||||
return lowerContentType.startsWith(BINARY_CONTENT_TYPE_PREFIX)
|
||||
|| lowerContentType.startsWith(IMAGE_CONTENT_TYPE_PREFIX)
|
||||
|| lowerContentType.startsWith(AUDIO_CONTENT_TYPE_PREFIX)
|
||||
|| lowerContentType.startsWith(VIDEO_CONTENT_TYPE_PREFIX);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user