期望:
輸出自己想要的日誌格式,包含請求參數,響應參數,響應時間,請求URL
處理方法:
1、打開日誌
2、繼承: feign.Logger
實現:logAndRebufferResponse
/**
*打開日誌
*/
@Configuration
public class FeignLogConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}
/**
*繼承: feign.Logger
*實現:logAndRebufferResponse
**/
@Component
public class RemoteLogger extends Logger {
private static final PosLogger logger = new PosLogger(RemoteLogger.class);
@Override
protected void log(String s, String s1, Object... objects) {
}
@Override
protected void logRequest(String configKey, Logger.Level logLevel, Request request) {
}
@Override
protected Response logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime) throws IOException {
if (response.body() != null) {
String result="";
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
int bodyLength = bodyData.length;
if (bodyLength > 0) {
result = Util.decodeOrDefault(bodyData, Util.UTF_8, "Binary data");
}
Response build = response.toBuilder().body(bodyData).build();
Request request = build.request();
String bodyText = request.charset() != null ? new String(request.body(), request.charset()) : null;
// 請求URL request.url()
// 請求參數 bodyText
// 請求結果 result
// 請求耗時 elapsedTime
//logger.info();
return build;
}
return response;
}
protected IOException logIOException(String configKey,
Level logLevel,
IOException ioe,
long elapsedTime) {
//IOException 自帶log輸出即可 logger.error();
// com.netflix.client.ClientException: Load balancer does not have available server for client: lzh-cloud-test 服務沒發現未進IO異常
return ioe;
}
}
日誌級別:
NONE,無記錄(DEFAULT)。
BASIC,只記錄請求方法和URL以及響應狀態代碼和執行時間。
HEADERS,記錄基本信息以及請求和響應標頭。
FULL,記錄請求和響應的頭文件,正文和元數據。
特定類指定特定日誌級別:
logging:
level:
com.lzh.cloud.feign.UserFeignClient: DEBUG
feign.Logger 源碼簡單解讀
Logger
//構造方法
Logger();
//請求configKey長度處理
methodTag(String configKey);
//輸出log日誌
log(String var1, String var2, Object... var3);
//輸出請求相關信息
logRequest(String configKey, Logger.Level logLevel, Request request)
//輸出重試信息
logRetry(String configKey, Logger.Level logLevel)
//輸出響應信息
logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime)
//輸出IO異常信息
logIOException(String configKey, Logger.Level logLevel, IOException ioe, long elapsedTime)
//默認的幾個類實現
NoOpLogger
JavaLogger
ErrorLogger
//日誌不同級別
Level
源碼:
public abstract class Logger {
public Logger() {
}
protected static String methodTag(String configKey) {
return '[' + configKey.substring(0, configKey.indexOf(40)) + "] ";
}
protected abstract void log(String var1, String var2, Object... var3);
protected void logRequest(String configKey, Logger.Level logLevel, Request request) {
this.log(configKey, "---> %s %s HTTP/1.1", request.method(), request.url());
if (logLevel.ordinal() >= Logger.Level.HEADERS.ordinal()) {
Iterator var4 = request.headers().keySet().iterator();
String bodyText;
while(var4.hasNext()) {
bodyText = (String)var4.next();
Iterator var6 = Util.valuesOrEmpty(request.headers(), bodyText).iterator();
while(var6.hasNext()) {
String value = (String)var6.next();
this.log(configKey, "%s: %s", bodyText, value);
}
}
int bodyLength = 0;
if (request.body() != null) {
bodyLength = request.body().length;
if (logLevel.ordinal() >= Logger.Level.FULL.ordinal()) {
bodyText = request.charset() != null ? new String(request.body(), request.charset()) : null;
this.log(configKey, "");
this.log(configKey, "%s", bodyText != null ? bodyText : "Binary data");
}
}
this.log(configKey, "---> END HTTP (%s-byte body)", bodyLength);
}
}
protected void logRetry(String configKey, Logger.Level logLevel) {
this.log(configKey, "---> RETRYING");
}
protected Response logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime) throws IOException {
String reason = response.reason() != null && logLevel.compareTo(Logger.Level.NONE) > 0 ? " " + response.reason() : "";
int status = response.status();
this.log(configKey, "<--- HTTP/1.1 %s%s (%sms)", status, reason, elapsedTime);
if (logLevel.ordinal() >= Logger.Level.HEADERS.ordinal()) {
Iterator var8 = response.headers().keySet().iterator();
while(var8.hasNext()) {
String field = (String)var8.next();
Iterator var10 = Util.valuesOrEmpty(response.headers(), field).iterator();
while(var10.hasNext()) {
String value = (String)var10.next();
this.log(configKey, "%s: %s", field, value);
}
}
int bodyLength = 0;
if (response.body() != null && status != 204 && status != 205) {
if (logLevel.ordinal() >= Logger.Level.FULL.ordinal()) {
this.log(configKey, "");
}
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
int bodyLength = bodyData.length;
if (logLevel.ordinal() >= Logger.Level.FULL.ordinal() && bodyLength > 0) {
this.log(configKey, "%s", Util.decodeOrDefault(bodyData, Util.UTF_8, "Binary data"));
}
this.log(configKey, "<--- END HTTP (%s-byte body)", bodyLength);
return response.toBuilder().body(bodyData).build();
}
this.log(configKey, "<--- END HTTP (%s-byte body)", Integer.valueOf(bodyLength));
}
return response;
}
protected IOException logIOException(String configKey, Logger.Level logLevel, IOException ioe, long elapsedTime) {
this.log(configKey, "<--- ERROR %s: %s (%sms)", ioe.getClass().getSimpleName(), ioe.getMessage(), elapsedTime);
if (logLevel.ordinal() >= Logger.Level.FULL.ordinal()) {
StringWriter sw = new StringWriter();
ioe.printStackTrace(new PrintWriter(sw));
this.log(configKey, sw.toString());
this.log(configKey, "<--- END ERROR");
}
return ioe;
}
public static class NoOpLogger extends Logger {
public NoOpLogger() {
}
protected void logRequest(String configKey, Logger.Level logLevel, Request request) {
}
protected Response logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime) throws IOException {
return response;
}
protected void log(String configKey, String format, Object... args) {
}
}
public static class JavaLogger extends Logger {
final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(Logger.class.getName());
public JavaLogger() {
}
protected void logRequest(String configKey, Logger.Level logLevel, Request request) {
if (this.logger.isLoggable(java.util.logging.Level.FINE)) {
super.logRequest(configKey, logLevel, request);
}
}
protected Response logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime) throws IOException {
return this.logger.isLoggable(java.util.logging.Level.FINE) ? super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime) : response;
}
protected void log(String configKey, String format, Object... args) {
if (this.logger.isLoggable(java.util.logging.Level.FINE)) {
this.logger.fine(String.format(methodTag(configKey) + format, args));
}
}
public Logger.JavaLogger appendToFile(String logfile) {
this.logger.setLevel(java.util.logging.Level.FINE);
try {
FileHandler handler = new FileHandler(logfile, true);
handler.setFormatter(new SimpleFormatter() {
public String format(LogRecord record) {
return String.format("%s%n", record.getMessage());
}
});
this.logger.addHandler(handler);
return this;
} catch (IOException var3) {
throw new IllegalStateException("Could not add file handler.", var3);
}
}
}
public static class ErrorLogger extends Logger {
public ErrorLogger() {
}
protected void log(String configKey, String format, Object... args) {
System.err.printf(methodTag(configKey) + format + "%n", args);
}
}
public static enum Level {
NONE,
BASIC,
HEADERS,
FULL;
private Level() {
}
}
}