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() {
        }
    }
}

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