Spring Cloud OpenFeign自定義日誌

期望:
	輸出自己想要的日誌格式,包含請求參數,響應參數,響應時間,請求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() {
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章