1. 程式人生 > >去除Dubbox LoggingFilter自動列印response內容

去除Dubbox LoggingFilter自動列印response內容

Dubbox自帶日誌列印問題

dubbo配置檔案配置protocol引入LoggingFilter:

	<dubbo:protocol accepts="500" contextpath="xxx" name="rest" port="xxx" server="tomcat" 
	 threads="500" extension="com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter"/>

LoggingFilter原始碼:

	public class LoggingFilter implements ContainerRequestFilter
, ClientRequestFilter, ContainerResponseFilter, ClientResponseFilter, WriterInterceptor, ReaderInterceptor { // 省略其他程式碼 ··· public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException { ServerReaderInterceptorContext scontext =(ServerReaderInterceptorContext)
context; Field fd = null; String path =""; try { fd = ServerReaderInterceptorContext.class.getDeclaredField("request"); fd.setAccessible(true); HttpRequest rm = (HttpRequest) fd.get(scontext); path = rm.getUri().getPath(); } catch (Exception e) { logger.warn("Get url path is exception,but your code is OK! "
,e); } byte[] buffer = IOUtils.toByteArray(context.getInputStream()); logger.info("The HTTP("+path+") request body are: \nBody:"+new String(buffer, "UTF-8")); context.setInputStream(new ByteArrayInputStream(buffer)); return context.proceed(); } public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { ServerWriterInterceptorContext scontext = (ServerWriterInterceptorContext)context; Field fd = null; String path =""; try { fd = ServerWriterInterceptorContext.class.getDeclaredField("request"); fd.setAccessible(true); HttpRequest rm = (HttpRequest) fd.get(scontext); path = rm.getUri().getPath(); } catch (Exception e) { logger.warn("Get url path is exception,but your code is OK! ",e); } OutputStreamWrapper wrapper = new OutputStreamWrapper(context.getOutputStream()); context.setOutputStream(wrapper); context.proceed(); logger.info("The url("+path+") of response body is: \n" + new String(wrapper.getBytes(), "UTF-8") + "\n"); } protected void logHttpHeaders(String url,MultivaluedMap<String, String> headers) { StringBuilder msg = new StringBuilder("The HTTP("+url+") request body are: \nHeader:"); for (Map.Entry<String, List<String>> entry : headers.entrySet()) { msg.append(entry.getKey()).append(": "); for (int i = 0; i < entry.getValue().size(); i++) { msg.append(entry.getValue().get(i)); if (i < entry.getValue().size() - 1) { msg.append(", "); } } msg.append("\n"); } logger.info(msg.toString()); } // 省略其他程式碼 ··· }
	其中大量的log info日誌列印request body和response body,在實際應用中,這些不起眼的日誌有可能會撐爆
整個服務的檔案記憶體,拖垮介面的請求響應效率。如檔案上傳與下載介面,將檔案內容列印到日誌中時完全沒有必要的。
	因此,需要對預設的日誌記錄進行改造,去掉不需要的日誌記錄。

自定義日誌記錄類

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;

import org.apache.commons.io.IOUtils;
import org.jboss.resteasy.core.interception.ServerReaderInterceptorContext;
import org.jboss.resteasy.core.interception.ServerWriterInterceptorContext;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;

public class CustomLogFilter implements ContainerRequestFilter, ClientRequestFilter, ContainerResponseFilter, ClientResponseFilter, WriterInterceptor, ReaderInterceptor {
	private Logger logger = LoggerFactory.getLogger(CustomLogFilter.class);

	public void filter(ClientRequestContext context) throws IOException {
		logHttpHeaders(context.getUri().getPath(), context.getStringHeaders());
	}

	public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
		logHttpHeaders(requestContext.getUri().getPath(), responseContext.getHeaders());
	}

	public void filter(ContainerRequestContext context) throws IOException {
		logHttpHeaders(context.getUriInfo().getPath(), context.getHeaders());
	}

	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
		logHttpHeaders(requestContext.getUriInfo().getPath(), responseContext.getStringHeaders());
	}

	public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
		Field fd = null;
		try {
			fd = ServerReaderInterceptorContext.class.getDeclaredField("request");
			fd.setAccessible(true);
		} catch (Exception e) {
			logger.warn("Get url path is exception,but your code is OK! ", e);
		}
		byte[] buffer = IOUtils.toByteArray(context.getInputStream());
		context.setInputStream(new ByteArrayInputStream(buffer));
		return context.proceed();
	}

	public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
		Field fd = null;
		try {
			fd = ServerWriterInterceptorContext.class.getDeclaredField("request");
			fd.setAccessible(true);
		} catch (Exception e) {
			logger.warn("Get url path is exception,but your code is OK! ", e);
		}
		OutputStreamWrapper wrapper = new OutputStreamWrapper(context.getOutputStream());
		context.setOutputStream(wrapper);
		context.proceed();
	}

	protected void logHttpHeaders(String url, MultivaluedMap<String, String> headers) {
		StringBuilder msg = new StringBuilder("The HTTP(" + url + ") request body are: \nHeader:");
		for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
			msg.append(entry.getKey()).append(": ");
			for (int i = 0; i < entry.getValue().size(); i++) {
				msg.append(entry.getValue().get(i));
				if (i < entry.getValue().size() - 1) {
					msg.append(", ");
				}
			}
			msg.append("\n");
		}
		logger.info(msg.toString());
	}

	protected static class OutputStreamWrapper extends OutputStream {

		private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		private final OutputStream output;

		private OutputStreamWrapper(OutputStream output) {
			this.output = output;
		}

		@Override
		public void write(int i) throws IOException {
			buffer.write(i);
			output.write(i);
		}

		@Override
		public void write(byte[] b) throws IOException {
			buffer.write(b);
			output.write(b);
		}

		@Override
		public void write(byte[] b, int off, int len) throws IOException {
			buffer.write(b, off, len);
			output.write(b, off, len);
		}

		@Override
		public void flush() throws IOException {
			output.flush();
		}

		@Override
		public void close() throws IOException {
			output.close();
		}

		public byte[] getBytes() {
			return buffer.toByteArray();
		}
	}
}
	為了不影響其他介面,參照LoggingFilter類,實現的類和方法內容不變,直接刪除log.info部分的內容,即可去
除不必要的request和response日誌列印。
	再將dubbo配置檔案的中的extension配置替換為自定義的日誌類即可。

修改dubbo配置檔案

	<dubbo:protocol accepts="500" contextpath="xxx" extension="xxxxxx.CustomLogFilter"
    name="rest" port="xxx" server="tomcat" threads="500"/>

測試

找到專案的日誌檔案,清空內容,重新啟動服務,呼叫介面,檢視日誌檔案中是否還包含“request body”或“response body”內容。