package at.gv.egiz.eaaf.utils.springboot.ajp.logging; import java.io.IOException; import java.util.HashMap; import java.util.Optional; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.slf4j.MDC; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; import lombok.Getter; @Component @EnableConfigurationProperties(LoggingProperties.class) public class MdcEnhancerFilter implements Filter { /** * Logging properties. */ private LoggingProperties loggingProperties; /** * To reduce the overhead of building the final "headerMap". * *

* The map is to be built when the object is initiated. *

*/ private final HashMap headerMap; /** * Create a new instance of {@link MdcEnhancerFilter}. * * @param loggingProperties an instance of {@link LoggingProperties} */ public MdcEnhancerFilter(LoggingProperties loggingProperties) { this.loggingProperties = loggingProperties; this.headerMap = new HashMap<>(this.loggingProperties.getMdc().getHeaderMap()); // add TXID into map (no overrides) for (final Txid txid : Txid.values()) { this.headerMap.putIfAbsent(txid.getFieldName(), txid.getHeaderName()); } } /** * Filter the request headers based on the configured MDC properties. * * @param request incoming {@link HttpServletRequest} */ private void filterHeader(final HttpServletRequest request) { this.headerMap.forEach((field, header) -> { // to provide backwards compatibility we have to put the "null-value" into the // MDC if it is not present final String value = Optional.ofNullable(request.getHeader(header)) .orElse(this.loggingProperties.getMdc().getNullValue()); MDC.put(field, value); }); } /** * {@inheritDoc} */ @Override public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; filterHeader(request); String key; String value; for (final String cookie : loggingProperties.getMdc().getCookies()) { key = loggingProperties.getMdc().getCookiePrefix() + cookie + loggingProperties.getMdc() .getCookiePostfix(); value = getCookie(cookie, request.getCookies()); if (StringUtils.isNotBlank(value)) { MDC.put(key, value); } else if (loggingProperties.getMdc().getNullValue() != null) { MDC.put(key, loggingProperties.getMdc().getNullValue()); } } Object object; for (final String attribute : loggingProperties.getMdc().getSessionAttributes()) { key = loggingProperties.getMdc().getSessionAttributePrefix() + attribute + loggingProperties.getMdc() .getSessionAttributePostfix(); object = request.getSession(true).getAttribute(attribute); if (object != null) { MDC.put(key, object.toString()); } else if (loggingProperties.getMdc().getNullValue() != null) { MDC.put(key, loggingProperties.getMdc().getNullValue()); } } try { filterChain.doFilter(servletRequest, servletResponse); } finally { for (final String field : this.headerMap.keySet()) { MDC.remove(field); } for (final String cookie : loggingProperties.getMdc().getCookies()) { MDC.remove(cookie); } for (final String attribute : loggingProperties.getMdc().getSessionAttributes()) { MDC.remove(attribute); } } } private static String getCookie(final String cookie, final Cookie[] cookies) { if (cookies == null || !StringUtils.isNotBlank(cookie)) { return null; } for (final Cookie c : cookies) { if (c.getName().equals(cookie)) { return c.getValue(); } } return null; } /** * Enumeration of default TXIDs handled by the auto-configuration. */ @Getter private enum Txid { HTTP_REQUEST("AM-TXID-HTTP-Request", "amTxidHttpRequest"), BROWSER("AM-TXID-Browser-Session", "amTxidBrowserSession"), IDP("AM-TXID-IdP-Session", "amTxidIdpSession"), SP("AM-TXID-SP-Session", "amTxidSpSession"); private final String headerName; private final String fieldName; Txid(final String headerName, final String fieldName) { this.headerName = headerName; this.fieldName = fieldName; } } }