在微服务架构体系中,利用SpringMVC打印单服务日志的实现形式有多种方式,本人了解的如下几种。
1.继承DispatcherServlet.
2.利用拦截器。
3.利用过滤器。
本章直接介绍用过滤器实现简单的打印请求上的输入输出日志,废话不多说了,直接贴干货吧,代码简单易懂!
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* 在过滤器中打印输入输出日志
* @Author
* @Date 2019-08-06
*/
@Component
@Slf4j
public class LoggingFilter extends OncePerRequestFilter {
ObjectMapper objectMapper=new ObjectMapper();
/**
* 支持打印的MediaType
*/
private static final Set<MediaType> supportMediaTypes=new HashSet<>();
{
supportMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportMediaTypes.add(MediaType.APPLICATION_JSON);
supportMediaTypes.add(MediaType.TEXT_HTML);
supportMediaTypes.add(MediaType.TEXT_PLAIN);
supportMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
}
final List<String> resourceRequestsURI = Arrays.asList(
"/css/", "/js/", "/scss/", "/fonts/",
".css", ".js", ".scss", ".eot",
".svg", ".ttf", ".woff", ".otf", ".ico", ".png");
final List<String> swaggerRequestURI = Arrays.asList(
"/v2/api-docs", "/swagger-resources","swagger-ui");
@Override
protected void doFilterInternal( HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) {
try {
doLog(httpServletRequest,httpServletResponse,filterChain);
}
catch (Exception e){
log.error("do log filter has a error:{} ", ExceptionUtils.getRootCause(e));
}
}
void doLog(final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse,
final FilterChain filterChain) throws IOException, ServletException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(httpServletRequest);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(httpServletResponse);
filterChain.doFilter(requestWrapper, responseWrapper);
String requestUrl = requestWrapper.getRequestURL().toString();
String requestId=UUID.randomUUID().toString();
HttpMethod httpMethod = HttpMethod.valueOf(requestWrapper.getMethod());
log.info(" request id is: {},http method is:{}",requestId,httpMethod.name());
log.info("request id is: {},requestUrl is:{}",requestId, requestUrl);
Enumeration<String> parameterEnum=requestWrapper.getParameterNames();
if(!ObjectUtils.isEmpty(parameterEnum)) {
log.info("request id is: {},request param is:{}",requestId,getRequestParamJSON(requestWrapper));
}
log.info("request id is: {},request header is:{}", requestId,getRequestHeader(requestWrapper));
if(HttpMethod.valueOf(httpServletRequest.getMethod())!=HttpMethod.GET) {
if(supportMediaTypes.contains(MediaType.valueOf(httpServletRequest.getContentType()))) {
log.info("request id is: {},request body is:\n{}",requestId, new String(requestWrapper.getContentAsByteArray()));
}
}
HttpStatus responseStatus = HttpStatus.valueOf(responseWrapper.getStatusCode());
log.info("request id is: {},response status is:{}",requestId ,responseStatus.value());
String responseBody = IOUtils.toString(responseWrapper.getContentInputStream(), UTF_8);
if(httpServletRequest.isAsyncSupported()){
log.info("request id is: {}, response payLoad is:\n{}",requestId, responseBody);
}
else if(!isAsyncStarted(httpServletRequest)&&httpServletRequest.getDispatcherType()!= DispatcherType.ASYNC) {
log.info("request id is: {},response body is:{}",requestId ,objectMapper.readTree(responseBody));
}
else {
log.info("request id is: {}, cause by request is async:response body is:{}", requestId,"empty");
}
responseWrapper.copyBodyToResponse();
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String requestUrl=request.getRequestURL().toString();
return isResourceUrl(requestUrl)||isSwaggerResource(requestUrl);
}
/**
* 请求参数列表
* @param requestWrapper
* @return
*/
private JSONObject getRequestParamJSON(ContentCachingRequestWrapper requestWrapper){
Enumeration<String> parameterEnum=requestWrapper.getParameterNames();
JSONObject paramJsonObject=new JSONObject();
if(!ObjectUtils.isEmpty(parameterEnum)) {
while (parameterEnum.hasMoreElements()) {
String name= parameterEnum.nextElement();
String []value=requestWrapper.getParameterValues(name);
paramJsonObject.put(name,value);
}
}
return paramJsonObject;
}
/**
*
* @param requestWrapper
* @return 请求头参数列表
*/
private JSONObject getRequestHeader(ContentCachingRequestWrapper requestWrapper){
Enumeration headerNames = requestWrapper.getHeaderNames();
JSONObject headerJsonObject=new JSONObject();
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
headerJsonObject.put(headerName,requestWrapper.getHeader(headerName));
}
return headerJsonObject;
}
private boolean isResourceUrl(String url) {
return resourceRequestsURI.stream().anyMatch(e->url.contains(e));
}
private boolean isSwaggerResource(String url) {
return swaggerRequestURI.stream().anyMatch(e->url.contains(e));
}
}
附带继承DispatchServlet实现日志打印
package com.application.config;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.BaseJsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
public class CustLoggingDispatcherServlet extends DispatcherServlet {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger("logging");
private static final ObjectMapper mapper = new ObjectMapper();
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
//创建一个 json 对象,用来存放 http 日志信息
ObjectNode rootNode = mapper.createObjectNode();
rootNode.put("uri", requestWrapper.getRequestURI());
rootNode.put("clientIp", requestWrapper.getRemoteAddr());
rootNode.set("requestHeaders", mapper.valueToTree(getRequestHeaders(requestWrapper)));
String method = requestWrapper.getMethod();
rootNode.put("method", method);
try {
super.doDispatch(requestWrapper, responseWrapper);
} finally {
if(method.equals("GET")) {
rootNode.set("request", mapper.valueToTree(requestWrapper.getParameterMap()));
}
else {
JsonNode newNode = mapper.readTree(requestWrapper.getContentAsByteArray());
rootNode.set("request", newNode);
}
if(response.getContentType().equals(MediaType.APPLICATION_JSON.getType())
&&response.getContentType().equals( MediaType.APPLICATION_JSON_UTF8.getType())) {
JsonNode newNode = mapper.readTree(responseWrapper.getContentInputStream());
rootNode.set("response", newNode);
}
else{
JsonNode newNode = JsonNodeFactory.instance.textNode(new String(responseWrapper.getContentAsByteArray()));
rootNode.set("response", newNode);
}
responseWrapper.copyBodyToResponse();
rootNode.set("responseHeaders", mapper.valueToTree(getResponsetHeaders(responseWrapper)));
logger.info(rootNode.toString());
}
}
private Map<String, Object> getRequestHeaders(HttpServletRequest request) {
Map<String, Object> headers = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.put(headerName, request.getHeader(headerName));
}
return headers;
}
private Map<String, Object> getResponsetHeaders(ContentCachingResponseWrapper response) {
Map<String, Object> headers = new HashMap<>();
Collection<String> headerNames = response.getHeaderNames();
for (String headerName : headerNames) {
headers.put(headerName, response.getHeader(headerName));
}
return headers;
}
}
@Bean
public ServletRegistrationBean dispatcherRegistration() {
return new ServletRegistrationBean(dispatcherServlet());
}
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new CustLoggingDispatcherServlet();
}
网友评论