Skip to content

Commit 5607509

Browse files
Add Correlation Id Filter
1 parent df23745 commit 5607509

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.sap.hcp.cf.logging.servlet.filter;
2+
3+
import java.util.UUID;
4+
5+
import javax.servlet.http.HttpServletRequest;
6+
import javax.servlet.http.HttpServletResponse;
7+
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
import com.sap.hcp.cf.logging.common.Defaults;
12+
import com.sap.hcp.cf.logging.common.LogContext;
13+
import com.sap.hcp.cf.logging.common.request.HttpHeader;
14+
import com.sap.hcp.cf.logging.common.request.HttpHeaders;
15+
16+
/**
17+
* The {@link CorrelationIdFilter} extracts a correlation id according to
18+
* {@link HttpHeaders#CORRELATION_ID}. It will generate a random uuid, if no
19+
* correlation id is found in the headers. In any case the correlation id is set
20+
* as a response header, if possible
21+
*/
22+
public class CorrelationIdFilter extends AbstractLoggingFilter {
23+
24+
private static final Logger LOG = LoggerFactory.getLogger(CorrelationIdFilter.class);
25+
private HttpHeader correlationHeader;
26+
27+
public CorrelationIdFilter() {
28+
this(HttpHeaders.CORRELATION_ID);
29+
}
30+
31+
public CorrelationIdFilter(HttpHeader correlationHeader) {
32+
this.correlationHeader = correlationHeader;
33+
}
34+
35+
@Override
36+
protected void preProcess(HttpServletRequest request, HttpServletResponse response) {
37+
String correlationId = determineCorrelationId(request);
38+
LogContext.add(correlationHeader.getField(), correlationId);
39+
addCorrelationIdHeader(response, correlationId);
40+
}
41+
42+
private String determineCorrelationId(HttpServletRequest request) {
43+
String correlationId = HttpHeaderUtilities.getHeaderValue(request, correlationHeader);
44+
if (correlationId == null || correlationId.isEmpty() || correlationId.equals(Defaults.UNKNOWN)) {
45+
correlationId = String.valueOf(UUID.randomUUID());
46+
LOG.debug("Generated new correlation-id <{}>", correlationId);
47+
}
48+
return correlationId;
49+
}
50+
51+
private void addCorrelationIdHeader(HttpServletResponse response, String correlationId) {
52+
if (!response.isCommitted() && response.getHeader(correlationHeader.getName()) == null) {
53+
response.setHeader(correlationHeader.getName(), correlationId);
54+
}
55+
}
56+
57+
@Override
58+
protected void postProcess(HttpServletRequest request, HttpServletResponse response) {
59+
LogContext.remove(correlationHeader.getField());
60+
}
61+
62+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package com.sap.hcp.cf.logging.servlet.filter;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.equalTo;
5+
import static org.hamcrest.Matchers.is;
6+
import static org.hamcrest.Matchers.not;
7+
import static org.hamcrest.Matchers.nullValue;
8+
import static org.mockito.Mockito.doAnswer;
9+
import static org.mockito.Mockito.verify;
10+
import static org.mockito.Mockito.verifyNoMoreInteractions;
11+
import static org.mockito.Mockito.when;
12+
13+
import java.util.Collections;
14+
import java.util.List;
15+
import java.util.UUID;
16+
17+
import javax.servlet.FilterChain;
18+
import javax.servlet.http.HttpServletRequest;
19+
import javax.servlet.http.HttpServletResponse;
20+
21+
import org.junit.Before;
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.mockito.Mock;
25+
import org.mockito.invocation.InvocationOnMock;
26+
import org.mockito.runners.MockitoJUnitRunner;
27+
import org.mockito.stubbing.Answer;
28+
import org.slf4j.MDC;
29+
30+
import com.sap.hcp.cf.logging.common.request.HttpHeader;
31+
import com.sap.hcp.cf.logging.common.request.HttpHeaders;
32+
33+
@RunWith(MockitoJUnitRunner.class)
34+
public class CorrelationIdFilterTest {
35+
36+
private static String KNOWN_CORRELATION_ID = UUID.randomUUID().toString();
37+
38+
@Mock
39+
private HttpServletRequest request;
40+
@Mock
41+
private HttpServletResponse response;
42+
@Mock
43+
private FilterChain chain;
44+
45+
private CorrelationIdFromMDCExtractor mdcExtractor;
46+
47+
@Before
48+
public void setUp() throws Exception {
49+
mdcExtractor = new CorrelationIdFromMDCExtractor(HttpHeaders.CORRELATION_ID.getField());
50+
doAnswer(mdcExtractor).when(chain).doFilter(request, response);
51+
}
52+
53+
@Test
54+
public void addsKnownCorrelationIdToMDC() throws Exception {
55+
when(request.getHeader(HttpHeaders.CORRELATION_ID.getName())).thenReturn(KNOWN_CORRELATION_ID);
56+
57+
new CorrelationIdFilter().doFilter(request, response, chain);
58+
59+
assertThat(mdcExtractor.getCorrelationId(), is(equalTo(KNOWN_CORRELATION_ID)));
60+
}
61+
62+
@Test
63+
public void addsGeneratedCorrelationIdToMDC() throws Exception {
64+
65+
new CorrelationIdFilter().doFilter(request, response, chain);
66+
67+
assertThat(mdcExtractor.getCorrelationId(), is(not(nullValue())));
68+
assertThat(mdcExtractor.getCorrelationId(), is(not(equalTo(KNOWN_CORRELATION_ID))));
69+
}
70+
71+
@Test
72+
public void removesCorrelationIdAfterFiltering() throws Exception {
73+
new CorrelationIdFilter().doFilter(request, response, chain);
74+
75+
assertThat(MDC.get(HttpHeaders.CORRELATION_ID.getField()), is(nullValue()));
76+
}
77+
78+
@Test
79+
public void addsKnownCorrelationIdAsResponseHeader() throws Exception {
80+
when(request.getHeader(HttpHeaders.CORRELATION_ID.getName())).thenReturn(KNOWN_CORRELATION_ID);
81+
82+
new CorrelationIdFilter().doFilter(request, response, chain);
83+
84+
verify(response).setHeader(HttpHeaders.CORRELATION_ID.getName(), KNOWN_CORRELATION_ID);
85+
}
86+
87+
@Test
88+
public void doesNotAddCorrelationIdToCommittedResponse() throws Exception {
89+
when(response.isCommitted()).thenReturn(true);
90+
91+
new CorrelationIdFilter().doFilter(request, response, chain);
92+
93+
verify(response).isCommitted();
94+
verifyNoMoreInteractions(response);
95+
}
96+
97+
@Test
98+
public void doesNotOverwriteCorrelationIdInResponse() throws Exception {
99+
when(response.isCommitted()).thenReturn(false);
100+
when(response.getHeader(HttpHeaders.CORRELATION_ID.getName())).thenReturn("preexisting-correlation-id");
101+
102+
new CorrelationIdFilter().doFilter(request, response, chain);
103+
104+
verify(response).isCommitted();
105+
verify(response).getHeader(HttpHeaders.CORRELATION_ID.getName());
106+
verifyNoMoreInteractions(response);
107+
}
108+
109+
@Test
110+
public void usesCustomHeader() throws Exception {
111+
HttpHeader myHeader = new HttpHeader() {
112+
113+
@Override
114+
public boolean isPropagated() {
115+
return true;
116+
}
117+
118+
@Override
119+
public String getName() {
120+
return "my-header";
121+
}
122+
123+
@Override
124+
public String getFieldValue() {
125+
return null;
126+
}
127+
128+
@Override
129+
public String getField() {
130+
return "my-field";
131+
}
132+
133+
@Override
134+
public List<HttpHeader> getAliases() {
135+
return Collections.emptyList();
136+
}
137+
};
138+
when(request.getHeader("my-header")).thenReturn(KNOWN_CORRELATION_ID);
139+
CorrelationIdFromMDCExtractor myMdcExtractor = new CorrelationIdFromMDCExtractor("my-field");
140+
doAnswer(myMdcExtractor).when(chain).doFilter(request, response);
141+
142+
new CorrelationIdFilter(myHeader).doFilter(request, response, chain);
143+
144+
assertThat(myMdcExtractor.getCorrelationId(), is(equalTo(KNOWN_CORRELATION_ID)));
145+
verify(response).setHeader("my-header", KNOWN_CORRELATION_ID);
146+
147+
}
148+
149+
private static class CorrelationIdFromMDCExtractor implements Answer<Void> {
150+
151+
private String correlationId;
152+
private String field;
153+
154+
private CorrelationIdFromMDCExtractor(String field) {
155+
this.field = field;
156+
}
157+
158+
public String getCorrelationId() {
159+
return correlationId;
160+
}
161+
162+
@Override
163+
public Void answer(InvocationOnMock invocation) throws Throwable {
164+
correlationId = MDC.get(field);
165+
return null;
166+
}
167+
}
168+
169+
}

0 commit comments

Comments
 (0)