/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame.trace; import java.lang.reflect.Method; import org.threeten.bp.Duration; import com.opengamma.sesame.config.EngineUtils; import com.opengamma.sesame.proxy.ProxyNodeDecorator; import com.opengamma.util.ArgumentChecker; /** * A proxy that records method calls, arguments and return values. * <p> * This can be used in front of all interface nodes. */ public final class TracingProxy extends ProxyNodeDecorator { /** * Singleton instance of the tracing proxy. */ public static final TracingProxy INSTANCE = new TracingProxy(); /** * The thread-local for the tracer. */ private static final ThreadLocal<Tracer> s_tracer = new ThreadLocal<Tracer>() { @Override protected Tracer initialValue() { return NoOpTracer.INSTANCE; } }; //------------------------------------------------------------------------- /** * Starts the process of tracing. * * @param tracer the tracer to use, not null */ public static void start(Tracer tracer) { s_tracer.set(ArgumentChecker.notNull(tracer, "tracer")); } /** * Ends the process of tracing. * * @return the call graph, null if not available */ public static CallGraph end() { Tracer tracer = s_tracer.get(); s_tracer.remove(); CallGraphBuilder callGraphBuilder = tracer.getRoot(); return callGraphBuilder == null ? null : callGraphBuilder.createTrace(); } //------------------------------------------------------------------------- /** * Restricted constructor. */ private TracingProxy() { } //------------------------------------------------------------------------- @Override protected boolean decorate(Class<?> interfaceType, Class<?> implementationType) { return true; } @Override protected Object invoke(Object proxy, Object delegate, Method method, Object[] args) throws Throwable { // this avoids recording calls to toString() in the debugger if (method.getName().equals("toString")) { return method.invoke(delegate, args); } Tracer tracer = s_tracer.get(); tracer.called(method, args); long start = System.nanoTime(); try { Object retVal = method.invoke(delegate, args); tracer.returned(retVal, Duration.ofNanos(System.nanoTime() - start)); return retVal; } catch (Exception ex) { long end = System.nanoTime(); Throwable cause = EngineUtils.getCause(ex); tracer.threw(cause, Duration.ofNanos(end - start)); throw cause; } } }