去除Dubbox LoggingFilter自動列印response內容
阿新 • • 發佈:2018-12-19
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”內容。