Skip to content

Instantly share code, notes, and snippets.

@pismy
Last active September 20, 2018 07:23
Show Gist options
  • Save pismy/9356098055444f83741e to your computer and use it in GitHub Desktop.
Save pismy/9356098055444f83741e to your computer and use it in GitHub Desktop.
SLF4J & Apache Http tool: propagates MDC context over client Http requests (suitable for micro-services architecture)
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
/**
* Apache Http {@link HttpRequestHandler} that enables propagating part or all of the {@link MDC} context over Http requests
* <p>
* Requires SLF4J as the logging facade API and Apache Http as the client Http stack.
* <p>
* By default propagates {@code requestId} MDC attribute as {@code X-Track-RequestId} header but it can be overridden using the
* {@code slf4j.tools.propagate.mdc.fields} Java property formatted as:
* <pre class=code>&lt;mdc name 1&gt;: &lt;header name 1&gt;, &lt;mdc name 2&gt;: &lt;header name 2&gt;, &lt;mdc name 3&gt;: &lt;header name 3&gt;</pre>
* <p>
* Example:
* <pre class=code>requestId: X-Track-RequestId, sessionId: X-Track-SessionId, time: X-Track-Time</pre>
*
* @author pismy
*
*/
public class HttpRequestHandlerWithMdcPropagation implements HttpRequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MdcPropagatorOverHttpRequests.class);
private final Map<String, String> mdcName2HeaderName;
public MdcPropagatorOverHttpRequests() {
mdcName2HeaderName = new HashMap<>();
String mdcFieldsConfig = System.getProperty("slf4j.tools.propagate.mdc.fields", "requestId: X-Track-RequestId").trim();
String[] mdcFields = mdcFieldsConfig.split(",");
for (String mdc2Header : mdcFields) {
int idx = mdc2Header.indexOf(':');
if (idx <= 0) {
LOGGER.warn("Unexpected configuration format in '{}': items should be formatted as '<mdc name>: <header name>'", mdcFieldsConfig);
} else {
String mdc = mdc2Header.substring(0, idx).trim();
String header = mdc2Header.substring(idx + 1).trim();
if (mdc.isEmpty() || header.isEmpty()) {
LOGGER.warn("Unexpected configuration format in '{}': items should be formatted as '<mdc name>: <header name>'", mdcFieldsConfig);
} else {
mdcName2HeaderName.put(mdc, header);
}
}
}
}
@Override
public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
for (Entry<String, String> e : mdcName2HeaderName.entrySet()) {
String mdcValue = MDC.get(e.getKey());
if (mdcValue != null) {
request.addHeader(new BasicHeader(e.getValue(), mdcValue));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment