@Bean
public FilterRegistrationBean<CompositeFilter> requestResponseLoggingFilter() {
CompositeFilter compositeFilter = new CompositeFilter();
compositeFilter.setFilters(List.of(
new SneakingPastTeeFilterException.UnwrappingFilter(),
new TeeFilter(),
new SneakingPastTeeFilterException.WrappingFilter()
));
FilterRegistrationBean<CompositeFilter> filterRegBean = new FilterRegistrationBean<>(compositeFilter);
filterRegBean.setName("Logback access-logging request response filter");
filterRegBean.setOrder(OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER);
return filterRegBean;
}
/**
* Workaround for TeeFilter printing stack trace of unchecked exceptions.
*
* @see <a href="" class="code-quote" style="color: #009100">"https:>Logback issue</a>
*/
private static class SneakingPastTeeFilterException extends RuntimeException {
private final Exception wrapped;
public SneakingPastTeeFilterException(IOException e) {
this.wrapped = e;
}
public SneakingPastTeeFilterException(ServletException e) {
this.wrapped = e;
}
void unwrap() throws IOException, ServletException {
if (wrapped instanceof IOException) {
throw (IOException) wrapped;
} else {
throw (ServletException) wrapped;
}
}
private static class WrappingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
chain.doFilter(request, response);
} catch (IOException e) {
throw new SneakingPastTeeFilterException(e);
} catch (ServletException e) {
throw new SneakingPastTeeFilterException(e);
}
}
}
private static class UnwrappingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (SneakingPastTeeFilterException e) {
e.unwrap();
}
}
}
}