Skip to content

Instantly share code, notes, and snippets.

@PiotrPodsiadly
Last active October 11, 2015 13:02
Show Gist options
  • Select an option

  • Save PiotrPodsiadly/5f5e1a6aed5a105297e7 to your computer and use it in GitHub Desktop.

Select an option

Save PiotrPodsiadly/5f5e1a6aed5a105297e7 to your computer and use it in GitHub Desktop.
Profiling Filter
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
private int pos = 0;
private int n = 0;
private void internalDoFilter(ServletRequest request, ServletResponse response) {
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null;
try {
filter = filterConfig.getFilter();
...
filter.doFilter(request, response, this);
private transient Filter filter = null;
Filter getFilter(){
if (this.filter != null) return this.filter;
String filterClass = filterDef.getFilterClass();
this.filter = (Filter) getInstanceManager().newInstance(filterClass);
initFilter();
return this.filter;
}
void init(FilterConfig filterConfig)
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
void destroy()
void doFilter(ServletRequest request, ServletResponse response)
String getFilterName()
ServletContext getServletContext()
String getInitParameter(String name)
Enumeration<String> getInitParameterNames()
package biz.podsiadly.instrumentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Measures time used by each javax.servlet.Filter
*/
public class FilterPerformanceProfilingFilter implements Filter {
static final ThreadLocal<Long> lastFilterTime = new ThreadLocal<>();
private static Logger log = LoggerFactory.getLogger(FilterPerformanceProfilingFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
final Class<? extends FilterChain> chainClass = filterChain.getClass();
if (chainClass.getName().equals("org.apache.catalina.core.ApplicationFilterChain")) {
try {
final Field filtersField = chainClass.getDeclaredField("filters");
final Field nField = chainClass.getDeclaredField("n");
final Field posField = chainClass.getDeclaredField("pos");
final Class<?> configClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
final Method getFilterMethod = configClass.getDeclaredMethod("getFilter");
final Field filterField = configClass.getDeclaredField("filter");
getFilterMethod.setAccessible(true);
Arrays.asList(filtersField, nField, posField, filterField).stream().
forEach(f -> f.setAccessible(true));
final Object filterConfigs = filtersField.get(filterChain);
final int n = (int) nField.get(filterChain);
final int pos = (int) posField.get(filterChain);
if (pos != 1) {
throw new RuntimeException("This filter should be run as first to measure every other filter performance");
}
for (int i = 1; i < n; i++) {
final Object filterConfig = Array.get(filterConfigs, i);
final Filter realFilter = (Filter) getFilterMethod.invoke(filterConfig);
if (!ProfilingFilterWrapper.class.equals(realFilter.getClass())) {
final Filter wrappedFilter = new ProfilingFilterWrapper(realFilter);
filterField.set(filterConfig, wrappedFilter);
log.debug("Injected profiling filter wrapper into " + realFilter.getClass());
}
}
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException("Unexpected application container");
}
lastFilterTime.set(System.currentTimeMillis());
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
class ProfilingFilterWrapper implements Filter {
final Filter realFilter;
public ProfilingFilterWrapper(Filter realFilter) {
this.realFilter = realFilter;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
long startTime = System.currentTimeMillis();
realFilter.doFilter(req, resp, filterChain);
final long now = System.currentTimeMillis();
long executionTime = now - startTime;
long delta = now - lastFilterTime.get();
lastFilterTime.set(now);
log.debug(delta + " taken by class: " + realFilter.getClass() + " (total including other filters: " + executionTime);
}
@Override
public void destroy() {
}
}
}
static final ThreadLocal<Long> lastFilterTime = new ThreadLocal<>();
class ProfilingFilterWrapper implements Filter {
final Filter realFilter;
public ProfilingFilterWrapper(Filter realFilter) {
this.realFilter = realFilter;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
long startTime = System.currentTimeMillis();
realFilter.doFilter(req, resp, filterChain);
final long now = System.currentTimeMillis();
long executionTime = now - startTime;
long delta = now - lastFilterTime.get();
lastFilterTime.set(now);
log.debug(delta + " taken by class: " + realFilter.getClass() + " (total including other filters: " + executionTime);
}
@Override
public void destroy() {
}
}
final Class<? extends FilterChain> chainClass = filterChain.getClass();
if (chainClass.getName().equals("org.apache.catalina.core.ApplicationFilterChain")) {
final Field filtersField = chainClass.getDeclaredField("filters");
final Field nField = chainClass.getDeclaredField("n");
final Field posField = chainClass.getDeclaredField("pos");
final Class<?> configClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
final Method getFilterMethod = configClass.getDeclaredMethod("getFilter");
final Field filterField = configClass.getDeclaredField("filter")
getFilterMethod.setAccessible(true);
Arrays.asList(filtersField, nField, posField, filterField).stream().
forEach(f -> f.setAccessible(true));
final Object filterConfigs = filtersField.get(filterChain);
final int n = (int) nField.get(filterChain);
final int pos = (int) posField.get(filterChain);
if (pos != 1) {
throw new RuntimeException("This filter should be run as first to measure every other filter performance");
}
for (int i = 1; i < n; i++) {
final Object filterConfig = Array.get(filterConfigs, i);
final Filter realFilter = (Filter) getFilterMethod.invoke(filterConfig);
if (!ProfilingFilterWrapper.class.equals(realFilter.getClass())) {
final Filter wrappedFilter = new ProfilingFilterWrapper(realFilter);
filterField.set(filterConfig, wrappedFilter);
log.debug("Injected profiling filter wrapper into " + realFilter.getClass());
}
}
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
lastFilterTime.set(System.currentTimeMillis());
filterChain.doFilter(request, response);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment