/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.common.filter; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import java.io.IOException; import java.util.Enumeration; import java.util.UUID; import javax.inject.Singleton; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * LoggingFilter * * This class must be a Singleton as described in * <a href="http://code.google.com/p/google-guice/wiki/ServletModule#Filter_Mapping"> * the Guice documentation</a>. */ @Singleton public class LoggingFilter implements Filter { private static Logger log = LoggerFactory.getLogger(LoggingFilter.class); private String customHeaderName; private final int CORRELATION_ID_LENGTH = 40; public static final String CSID = "csid"; @Override public void init(FilterConfig filterConfig) throws ServletException { customHeaderName = filterConfig.getInitParameter("header.name"); } @Override public void destroy() { customHeaderName = null; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long startTime = System.currentTimeMillis(); TeeHttpServletRequest req = new TeeHttpServletRequest( (HttpServletRequest) request); TeeHttpServletResponse resp = new TeeHttpServletResponse( (HttpServletResponse) response); try { // Generate a UUID for this request and store in the thread local MDC. // Will be logged with every request if the ConversionPattern uses it. MDC.put("requestType", "req"); String requestUUID = UUID.randomUUID().toString(); MDC.put("requestUuid", requestUUID); String correlationId = ""; Enumeration<String> headerNames = (Enumeration<String>) ((HttpServletRequest) request) .getHeaderNames(); while (headerNames.hasMoreElements()) { String name = (String) headerNames.nextElement(); if ("X-Correlation-ID".equalsIgnoreCase(name)) { correlationId = ((HttpServletRequest) request).getHeader(name); } } if (correlationId.matches("^([a-zA-Z0-9-])+$") && correlationId.length() <= CORRELATION_ID_LENGTH) { MDC.put(CSID, correlationId); } else if (!StringUtils.isBlank(correlationId)) { log.info("Correlation Id must contain alphanumeric characters or hypens and " + "be {} or fewer characters in length.", CORRELATION_ID_LENGTH); } // Add requestUuid to the serverRequest as an attribute, so Tomcat can // log it to the access log with "%{requestUuid}r" req.setAttribute("requestUuid", requestUUID); // Report the requestUuid to the client in the response. // Not sure this is useful yet. resp.setHeader(customHeaderName, requestUUID); if (log.isDebugEnabled()) { log.debug("{}", ServletLogger.logRequest(req)); } else { log.info("{}", ServletLogger.logBasicRequestInfo(req)); } chain.doFilter(req, resp); if (log.isDebugEnabled()) { log.debug("{}", ServletLogger.logResponse(resp, startTime)); } else { log.info("{}", ServletLogger.logBasicResponseInfo(resp, startTime)); } resp.finish(); } finally { MDC.clear(); } } }