Skip to content

Commit 15556d6

Browse files
Support MDC and Request Logging in Async Dispatch
1 parent a17d91a commit 15556d6

File tree

7 files changed

+681
-161
lines changed

7 files changed

+681
-161
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package com.sap.hcp.cf.logging.servlet.filter;
2+
3+
import java.io.IOException;
4+
import java.util.Collections;
5+
import java.util.Map;
6+
7+
import javax.servlet.AsyncContext;
8+
import javax.servlet.AsyncEvent;
9+
import javax.servlet.AsyncListener;
10+
import javax.servlet.ServletContext;
11+
import javax.servlet.ServletException;
12+
import javax.servlet.ServletRequest;
13+
import javax.servlet.ServletResponse;
14+
import javax.servlet.http.HttpServletRequest;
15+
import javax.servlet.http.HttpServletResponse;
16+
17+
import org.slf4j.MDC;
18+
19+
public class LoggingAsyncContextImpl implements AsyncContext {
20+
21+
private AsyncContext asyncContext;
22+
23+
public LoggingAsyncContextImpl(AsyncContext asyncContext, final RequestLoggingVisitor loggingVisitor) {
24+
this.asyncContext = asyncContext;
25+
asyncContext.addListener(new AsyncListener() {
26+
27+
@Override
28+
public void onTimeout(AsyncEvent event) throws IOException {
29+
generateLog(loggingVisitor);
30+
}
31+
32+
private void generateLog(final RequestLoggingVisitor loggingVisitor) {
33+
ServletRequest request = getRequest();
34+
ServletResponse response = getResponse();
35+
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
36+
HttpServletRequest httpRequest = (HttpServletRequest) request;
37+
HttpServletResponse httpResponse = (HttpServletResponse) response;
38+
Map<String, String> contextMap = getContextMap();
39+
Map<String, String> currentContextMap = MDC.getCopyOfContextMap();
40+
try {
41+
MDC.setContextMap(contextMap);
42+
loggingVisitor.logRequest(httpRequest, httpResponse);
43+
} finally {
44+
if (currentContextMap != null) {
45+
MDC.setContextMap(currentContextMap);
46+
}
47+
}
48+
}
49+
}
50+
51+
52+
@Override
53+
public void onStartAsync(AsyncEvent event) throws IOException {
54+
}
55+
56+
@Override
57+
public void onError(AsyncEvent event) throws IOException {
58+
generateLog(loggingVisitor);
59+
}
60+
61+
@Override
62+
public void onComplete(AsyncEvent event) throws IOException {
63+
generateLog(loggingVisitor);
64+
}
65+
});
66+
}
67+
68+
private Map<String, String> getContextMap() {
69+
try {
70+
@SuppressWarnings("unchecked")
71+
Map<String, String> fromRequest = (Map<String, String>) getRequest().getAttribute(MDC.class.getName());
72+
return fromRequest != null ? fromRequest : Collections.emptyMap();
73+
} catch (ClassCastException ignored) {
74+
return Collections.emptyMap();
75+
}
76+
}
77+
78+
@Override
79+
public void start(Runnable run) {
80+
try {
81+
Map<String, String> contextMap = getContextMap();
82+
asyncContext.start(new Runnable() {
83+
84+
@Override
85+
public void run() {
86+
Map<String, String> currentContextMap = MDC.getCopyOfContextMap();
87+
try {
88+
MDC.setContextMap(contextMap);
89+
run.run();
90+
} finally {
91+
if (currentContextMap != null) {
92+
MDC.setContextMap(currentContextMap);
93+
}
94+
}
95+
}
96+
});
97+
} catch (ClassCastException ignored) {
98+
asyncContext.start(run);
99+
}
100+
}
101+
102+
@Override
103+
public ServletRequest getRequest() {
104+
return asyncContext.getRequest();
105+
}
106+
107+
@Override
108+
public ServletResponse getResponse() {
109+
return asyncContext.getResponse();
110+
}
111+
112+
@Override
113+
public boolean hasOriginalRequestAndResponse() {
114+
return asyncContext.hasOriginalRequestAndResponse();
115+
}
116+
117+
@Override
118+
public void dispatch() {
119+
asyncContext.dispatch();
120+
}
121+
122+
@Override
123+
public void dispatch(String path) {
124+
asyncContext.dispatch(path);
125+
}
126+
127+
@Override
128+
public void dispatch(ServletContext context, String path) {
129+
asyncContext.dispatch(context, path);
130+
}
131+
132+
@Override
133+
public void complete() {
134+
asyncContext.complete();
135+
}
136+
137+
@Override
138+
public void addListener(AsyncListener listener) {
139+
asyncContext.addListener(listener);
140+
}
141+
142+
@Override
143+
public void addListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) {
144+
asyncContext.addListener(listener, servletRequest, servletResponse);
145+
}
146+
147+
@Override
148+
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException {
149+
return asyncContext.createListener(clazz);
150+
}
151+
152+
@Override
153+
public void setTimeout(long timeout) {
154+
asyncContext.setTimeout(timeout);
155+
}
156+
157+
@Override
158+
public long getTimeout() {
159+
return asyncContext.getTimeout();
160+
}
161+
162+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.sap.hcp.cf.logging.servlet.filter;
2+
3+
import javax.servlet.AsyncContext;
4+
import javax.servlet.ServletRequest;
5+
import javax.servlet.ServletResponse;
6+
import javax.servlet.http.HttpServletRequest;
7+
import javax.servlet.http.HttpServletRequestWrapper;
8+
9+
public class LoggingContextRequestWrapper extends HttpServletRequestWrapper {
10+
11+
private RequestLoggingVisitor loggingVisitor;
12+
13+
public LoggingContextRequestWrapper(HttpServletRequest request, RequestLoggingVisitor loggingVisitor) {
14+
super(request);
15+
this.loggingVisitor = loggingVisitor;
16+
}
17+
18+
@Override
19+
public AsyncContext startAsync() throws IllegalStateException {
20+
return new LoggingAsyncContextImpl(super.startAsync(), loggingVisitor);
21+
}
22+
23+
@Override
24+
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
25+
throws IllegalStateException {
26+
return new LoggingAsyncContextImpl(super.startAsync(servletRequest, servletResponse), loggingVisitor);
27+
}
28+
}

0 commit comments

Comments
 (0)