-
Notifications
You must be signed in to change notification settings - Fork 0
/
TraceLogFilter.java
169 lines (132 loc) · 6.46 KB
/
TraceLogFilter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package com.springapp.mvc.web;
import com.springapp.mvc.trace.ErrorLogType;
import com.springapp.mvc.trace.TraceLogInfo;
import com.springapp.mvc.trace.TraceLogInfoThreadLocalManager;
import com.springapp.mvc.trace.TraceLogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.NestedServletException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.springapp.mvc.web.TraceAsyncRequestInterceptor.LOG_INFO_ATTRIBUTE_NAME;
/**
* @author songkejun
* @create 2018-01-03 13:54
**/
public class TraceLogFilter extends OncePerRequestFilter {
private static Logger log = LoggerFactory.getLogger(TraceLogFilter.class);
public static final String DEFAULT_ENCODING = "UTF-8";
public static final String DEFAULT_TRACE_LOG_MANAGER_NAME = "traceLogManager";
private String traceLogManagerBeanName = DEFAULT_TRACE_LOG_MANAGER_NAME;
private volatile TraceLogManager traceLogManager;
private TraceAsyncRequestInterceptor interceptor = new TraceAsyncRequestInterceptor();
public void setTraceLogManagerBeanName(String traceLogManagerBeanName) {
this.traceLogManagerBeanName = traceLogManagerBeanName;
}
public String getTraceLogManagerBeanName() {
return traceLogManagerBeanName;
}
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
@Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
boolean isFirstRequest = !isAsyncDispatch(request);
TraceLogManager logManager = lookupTraceLogManager(request);
Exception exception = null;
if (isFirstRequest) {
request = wrapMultiReadableRequest(request);
registerAsyncInterceptor(request);
logManager.writeStartLog(buildRequestLog(request));
//for Servlet3 async
request.setAttribute(LOG_INFO_ATTRIBUTE_NAME, TraceLogInfoThreadLocalManager.getTraceLogInfo());
}
try {
filterChain.doFilter(request, response);
} catch (Exception e) {
exception = e;
e.printStackTrace();
} finally {
if (isAsyncStarted(request)) {return;}
//for Servlet3 async
if (!isFirstRequest) {
TraceLogInfoThreadLocalManager.bindTraceLogInfo((TraceLogInfo) request.getAttribute(LOG_INFO_ATTRIBUTE_NAME));
}
setErrorLogTypeByHttpStatus(response, logManager, exception);
if (exception == null) {
logManager.writeEndLog(buildResponseLog(request, response, null, logManager.getResponseTime()));
} else {
logManager.writeExceptionLog(buildResponseLog(request, response, exception, logManager.getResponseTime()), exception);
}
}
}
private void setErrorLogTypeByHttpStatus(HttpServletResponse response, TraceLogManager logManager, Exception exception) {
//스프링에서 처리되지 않은 예외
if (exception instanceof NestedServletException) {
logManager.setErrorLogType(ErrorLogType.APP_ERROR);
return;
}
//사용자 예외
if (response.getStatus() >= 400 && response.getStatus() <= 499) {
logManager.setErrorLogType(ErrorLogType.USER_ERROR);
} else if (response.getStatus() >= 500 && response.getStatus() <= 599) {
//애플리케이션 예외
logManager.setErrorLogType(ErrorLogType.APP_ERROR);
} else {
logManager.setErrorLogType(ErrorLogType.NONE);
}
}
private HttpServletRequest wrapMultiReadableRequest(HttpServletRequest request) throws IOException {
if(HttpReadUtils.isReadableHttpBody(request.getMethod())) {
request.getParameterMap();//
return new MultiReadHttpServletRequest(request, DEFAULT_ENCODING);
} else {
return request;
}
}
private void registerAsyncInterceptor(HttpServletRequest request) {
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
String key = getAlreadyFilteredAttributeName();
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
private String buildRequestLog(HttpServletRequest request) {
String remoteHost = request.getRemoteHost();
String method = request.getMethod();
String requestURLWithQueryString = HttpReadUtils.getRequestURLWithQueryString(request);
String body = HttpReadUtils.getHttpBody(request, DEFAULT_ENCODING);
return "[REQ] host=" + remoteHost + ", method=" + method + ", url=" + requestURLWithQueryString + ", body=" + body + "";
}
private String buildResponseLog(HttpServletRequest request, HttpServletResponse response, Exception e, long resultTime) {
return "[RES] host=" + request.getRemoteHost() + ", method=" + request.getMethod() + ", url=" + HttpReadUtils.getRequestURLWithQueryString(request) + ", status=" + response.getStatus() + ", time=" + resultTime + "ms, ex=" + e + "\n";
}
protected TraceLogManager lookupTraceLogManager(HttpServletRequest request) {
if (traceLogManager == null) {
traceLogManager = lookupTraceLogManager();
}
return traceLogManager;
}
protected TraceLogManager lookupTraceLogManager() {
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
String beanName = getTraceLogManagerBeanName();
if (StringUtils.hasLength(beanName)) {
return wac.getBean(beanName, TraceLogManager.class);
} else {
throw new IllegalStateException("traceLogManager가 등록되어 있지 않습니다.");
}
}
}