Forked from thegeekyasian/HttpRequestLoggingFilter.java
Created
November 23, 2022 18:15
-
-
Save AlexRogalskiy/2705be55a79ae411cba042de1b991738 to your computer and use it in GitHub Desktop.
Spring Boot HttpServletRequest Logging Filter. A Request Logging Filter for Spring Boot applications, that allows you to read the request body multiple times. The request body is cached using an overridden HttpServletRequestWrapper. Then a reader that allows the client to read the body multiple times is returned.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.core.Ordered; | |
import org.springframework.core.annotation.Order; | |
import org.springframework.stereotype.Component; | |
import org.springframework.util.StreamUtils; | |
import javax.servlet.*; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletRequestWrapper; | |
import java.io.*; | |
import java.util.*; | |
/** | |
* @author TheGeekyAsian | |
* Created at 2:22 PM, 2/18/20 | |
* | |
* See <a href="http://thegeekyasian.com">TheGeekyAsian.com</a> | |
* @see <a href="http://github.com/thegeekyasian/">TheGeekyAsian on GitHub</a> | |
*/ | |
@Component | |
@Order(value = Ordered.HIGHEST_PRECEDENCE) | |
public class HttpRequestLoggingFilter implements Filter { | |
/* Just to avoid logging credentials or related details. You can empty this list or remove it completely if you | |
want to log the security details too. */ | |
private static final List<String> HEADERS_TO_SKIP = Arrays.asList("authorization", "token", "security", "oauth", "auth"); | |
@Override | |
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { | |
CachedRequestHttpServletRequest cachedRequestHttpServletRequest = | |
new CachedRequestHttpServletRequest((HttpServletRequest) servletRequest); | |
String log = String.format("URL: %s | Requester: %s | HTTP Method: %s | Headers: %s | QueryStringParams: %s | RequestBody: %s", | |
cachedRequestHttpServletRequest.getRequestURL(), cachedRequestHttpServletRequest.getRemoteAddr(), | |
cachedRequestHttpServletRequest.getMethod(), getRequestHeaders(cachedRequestHttpServletRequest), | |
cachedRequestHttpServletRequest.getQueryString(), getBody(cachedRequestHttpServletRequest)); | |
// Log your request here! | |
System.out.println(log); //Try using a logger instead of the print statement. | |
chain.doFilter(cachedRequestHttpServletRequest, servletResponse); | |
} | |
private Map<String, String> getRequestHeaders(HttpServletRequest request) { | |
Map<String, String> headersMap = new HashMap<>(); | |
Enumeration<String> headerEnumeration = request.getHeaderNames(); | |
while (headerEnumeration.hasMoreElements()) { | |
String header = headerEnumeration.nextElement(); | |
// Filter the headers that you need to skip. | |
// If you don't want to filter any headers and want to log all of them, | |
// you can remove the condition below. | |
if (HEADERS_TO_SKIP.stream().noneMatch(h -> h.toLowerCase().contains(header.toLowerCase()) | |
|| header.toLowerCase().contains(h.toLowerCase()))) { | |
headersMap.put(header, request.getHeader(header)); | |
} | |
} | |
return headersMap; | |
} | |
private String getBody(CachedRequestHttpServletRequest request) throws IOException { | |
StringBuilder body = new StringBuilder(); | |
String line; | |
BufferedReader reader = request.getReader(); | |
while ((line = reader.readLine()) != null) { | |
body.append(line); | |
} | |
return body.toString(); | |
} | |
private static class CachedRequestHttpServletRequest extends HttpServletRequestWrapper { | |
private byte[] cachedBody; | |
public CachedRequestHttpServletRequest(HttpServletRequest request) throws IOException { | |
super(request); | |
this.cachedBody = StreamUtils.copyToByteArray(request.getInputStream()); | |
} | |
@Override | |
public ServletInputStream getInputStream() { | |
return new CachedRequestServletInputStream(this.cachedBody); | |
} | |
@Override | |
public BufferedReader getReader() { | |
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(this.cachedBody))); | |
} | |
} | |
private static class CachedRequestServletInputStream extends ServletInputStream { | |
private InputStream cachedBodyInputStream; | |
public CachedRequestServletInputStream(byte[] cachedBody) { | |
this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody); | |
} | |
@Override | |
public boolean isFinished() { | |
try { | |
return cachedBodyInputStream.available() == 0; | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
return false; | |
} | |
@Override | |
public boolean isReady() { | |
return true; | |
} | |
@Override | |
public void setReadListener(ReadListener readListener) { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public int read() throws IOException { | |
return cachedBodyInputStream.read(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment