Skip to content

Commit b71cc83

Browse files
Add fallback to W3C trace-id
When no X-CorrelationId header is found, the CorrelationIdFilter now searches for a traceparent header. It will take the trace-id as correlation-id, if the header value follows the W3C definition. This filter can be configured with customisable http header configurations but keeps the old interface for compatibility. Signed-off-by: Karsten Schnitter <[email protected]>
1 parent b50f6b3 commit b71cc83

File tree

2 files changed

+68
-9
lines changed

2 files changed

+68
-9
lines changed

cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/CorrelationIdFilter.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.sap.hcp.cf.logging.servlet.filter;
22

33
import static com.sap.hcp.cf.logging.common.customfields.CustomField.customField;
4+
import static com.sap.hcp.cf.logging.common.request.HttpHeaders.W3C_TRACEPARENT;
5+
import static java.util.Optional.ofNullable;
46

57
import java.util.UUID;
8+
import java.util.function.Predicate;
69

710
import javax.servlet.http.HttpServletRequest;
811
import javax.servlet.http.HttpServletResponse;
@@ -25,13 +28,19 @@ public class CorrelationIdFilter extends AbstractLoggingFilter {
2528

2629
private static final Logger LOG = LoggerFactory.getLogger(CorrelationIdFilter.class);
2730
private HttpHeader correlationHeader;
31+
private HttpHeader traceparentHeader;
2832

2933
public CorrelationIdFilter() {
3034
this(HttpHeaders.CORRELATION_ID);
3135
}
3236

3337
public CorrelationIdFilter(HttpHeader correlationHeader) {
38+
this(correlationHeader, W3C_TRACEPARENT);
39+
}
40+
41+
public CorrelationIdFilter(HttpHeader correlationHeader, HttpHeader traceparentHeader) {
3442
this.correlationHeader = correlationHeader;
43+
this.traceparentHeader = traceparentHeader;
3544
}
3645

3746
@Override
@@ -43,7 +52,10 @@ protected void beforeFilter(HttpServletRequest request, HttpServletResponse resp
4352

4453
private String determineCorrelationId(HttpServletRequest request) {
4554
String correlationId = HttpHeaderUtilities.getHeaderValue(request, correlationHeader);
46-
if (correlationId == null || correlationId.isEmpty() || correlationId.equals(Defaults.UNKNOWN)) {
55+
if (isBlankOrDefault(correlationId)) {
56+
correlationId = getCorrelationIdFromTraceparent(request);
57+
}
58+
if (isBlankOrDefault(correlationId)) {
4759
correlationId = String.valueOf(UUID.randomUUID());
4860
// add correlation-id as custom field, since it is added to MDC only
4961
// in the next step
@@ -53,6 +65,25 @@ private String determineCorrelationId(HttpServletRequest request) {
5365
return correlationId;
5466
}
5567

68+
private boolean isBlankOrDefault(String value) {
69+
return value == null || value.isEmpty() || value.equals(Defaults.UNKNOWN);
70+
}
71+
72+
private String getCorrelationIdFromTraceparent(HttpServletRequest request) {
73+
String traceparent = HttpHeaderUtilities.getHeaderValue(request, traceparentHeader);
74+
return ofNullable(traceparent).filter(not(this::isBlankOrDefault)).map(this::parseTraceparent).orElse(
75+
null);
76+
}
77+
78+
private <T> Predicate<T> not(Predicate<T> p) {
79+
return p.negate();
80+
}
81+
82+
private String parseTraceparent(String value) {
83+
String[] tokens = value.split("-");
84+
return tokens.length >= 2 ? tokens[1] : null;
85+
}
86+
5687
private void addCorrelationIdHeader(HttpServletResponse response, String correlationId) {
5788
if (!response.isCommitted() && response.getHeader(correlationHeader.getName()) == null) {
5889
response.setHeader(correlationHeader.getName(), correlationId);
@@ -63,5 +94,4 @@ private void addCorrelationIdHeader(HttpServletResponse response, String correla
6394
protected void cleanup(HttpServletRequest request, HttpServletResponse response) {
6495
LogContext.remove(correlationHeader.getField());
6596
}
66-
6797
}

cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/CorrelationIdFilterTest.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
@RunWith(MockitoJUnitRunner.class)
3030
public class CorrelationIdFilterTest {
3131

32-
private static String KNOWN_CORRELATION_ID = UUID.randomUUID().toString();
32+
private static final String KNOWN_CORRELATION_ID = UUID.randomUUID().toString();
33+
private static final String KNOWN_TRACE_ID = "4bf92f3577b34da6a3ce929d0e0e4736";
34+
private static final String KNOWN_TRACEPARENT = "00-" + KNOWN_TRACE_ID + "-00f067aa0ba902b7-01";
3335

3436
@Mock
3537
private HttpServletRequest request;
@@ -108,13 +110,40 @@ public void doesNotOverwriteCorrelationIdInResponse() throws Exception {
108110
}
109111

110112
@Test
111-
public void usesCustomHeader() throws Exception {
112-
HttpHeader myHeader = new HttpTestHeader("my-header", "my-field", null, false);
113-
when(request.getHeader("my-header")).thenReturn(KNOWN_CORRELATION_ID);
113+
public void usesCustomCorrelationIdHeader() throws Exception {
114+
HttpHeader myCorrelationIdHeader = new HttpTestHeader("my-correlationId-header", "my-correlationId-field", null,
115+
false);
116+
HttpHeader myTraceparentHeader = new HttpTestHeader("my-traceparent-header", "my-traceparent-field", null,
117+
false);
118+
when(request.getHeader("my-correlationId-header")).thenReturn(KNOWN_CORRELATION_ID);
119+
when(request.getHeader("my-traceparent-header")).thenReturn(KNOWN_TRACEPARENT);
120+
121+
new CorrelationIdFilter(myCorrelationIdHeader, myTraceparentHeader).doFilter(request, response, chain);
122+
123+
assertThat(mdcExtractor.getField("my-correlationId-field"), is(equalTo(KNOWN_CORRELATION_ID)));
124+
verify(response).setHeader("my-correlationId-header", KNOWN_CORRELATION_ID);
125+
}
126+
127+
@Test
128+
public void usesCustomTraceparentHeader() throws Exception {
129+
HttpHeader myCorrelationIdHeader = new HttpTestHeader("my-correlationId-header", "my-correlationId-field", null,
130+
false);
131+
HttpHeader myTraceparentHeader = new HttpTestHeader("my-traceparent-header", "my-traceparent-field", null,
132+
false);
133+
when(request.getHeader("my-traceparent-header")).thenReturn(KNOWN_TRACEPARENT);
114134

115-
new CorrelationIdFilter(myHeader).doFilter(request, response, chain);
135+
new CorrelationIdFilter(myCorrelationIdHeader, myTraceparentHeader).doFilter(request, response, chain);
136+
137+
assertThat(mdcExtractor.getField("my-correlationId-field"), is(equalTo(KNOWN_TRACE_ID)));
138+
verify(response).setHeader("my-correlationId-header", KNOWN_TRACE_ID);
139+
}
140+
141+
@Test
142+
public void usesTraceparentIfCorrelationIdHeaderNotPresent() throws Exception {
143+
when(request.getHeader(HttpHeaders.W3C_TRACEPARENT.getName())).thenReturn(KNOWN_TRACEPARENT);
144+
145+
new CorrelationIdFilter().doFilter(request, response, chain);
116146

117-
assertThat(mdcExtractor.getField("my-field"), is(equalTo(KNOWN_CORRELATION_ID)));
118-
verify(response).setHeader("my-header", KNOWN_CORRELATION_ID);
147+
assertThat(getExtractedCorrelationId(), is(equalTo(KNOWN_TRACE_ID)));
119148
}
120149
}

0 commit comments

Comments
 (0)