001 // Copyright 2008 Waterken Inc. under the terms of the MIT X license 002 // found at http://www.opensource.org/licenses/mit-license.html 003 package org.waterken.trace.application; 004 005 import java.io.Serializable; 006 import java.lang.reflect.Member; 007 import java.lang.reflect.Proxy; 008 009 import org.joe_e.Struct; 010 import org.joe_e.array.IntArray; 011 import org.joe_e.array.PowerlessArray; 012 import org.ref_send.log.CallSite; 013 import org.ref_send.log.Trace; 014 import org.waterken.trace.Tracer; 015 016 /** 017 * Produces a stack trace composed of only calls initiated by application code. 018 */ 019 public final class 020 ApplicationTracer { 021 private ApplicationTracer() {} 022 023 /** 024 * Constructs an instance. 025 * @param code application class loader 026 */ 027 static public Tracer 028 make(final ClassLoader code) { 029 class TracerX extends Struct implements Tracer, Serializable { 030 static private final long serialVersionUID = 1L; 031 032 public long 033 timestamp() { return System.currentTimeMillis(); } 034 035 public String 036 readException(final Throwable e) { return e.getMessage(); } 037 038 public Trace 039 traceException(final Throwable e) {return trace(e.getStackTrace());} 040 041 public Trace 042 traceMember(final Member lambda) { 043 return trace(new StackTraceElement( 044 lambda.getDeclaringClass().getName(), lambda.getName(), 045 null, -1)); 046 // TODO: want the line number of the method declaration 047 } 048 049 public Trace 050 traceHere() {return trace(Thread.currentThread().getStackTrace());} 051 052 private Trace 053 trace(final StackTraceElement... frames) { 054 final PowerlessArray.Builder<CallSite> sites = 055 PowerlessArray.builder(frames.length); 056 for (final StackTraceElement frame : frames) { 057 final int line = frame.getLineNumber(); 058 if (1 == line) { continue; } // skip synthetic method 059 060 // Is this frame from application code or system code? 061 boolean included = false; 062 try { 063 final Class<?> c = code.loadClass(frame.getClassName()); 064 if (!Proxy.isProxyClass(c)) { 065 final ClassLoader lib = c.getClassLoader(); 066 final ClassLoader sys = 067 ApplicationTracer.class.getClassLoader(); 068 for (ClassLoader i=code; i!=sys; i=i.getParent()) { 069 if (lib == i) { 070 included = true; 071 break; 072 } 073 } 074 } 075 } catch (final ClassNotFoundException e) { 076 // Assume it's not an application code class. 077 } 078 if (!included) { continue; } 079 080 // Describe the application stack frame. 081 final String name; { 082 final String fqn = frame.getClassName(); 083 final String cn = fqn.substring(fqn.lastIndexOf('.')+1); 084 final String sn = cn.replace("$1",".").replace("$","."); 085 name = sn + "." + frame.getMethodName(); 086 } 087 final String source; { 088 final String fqn = frame.getClassName(); 089 final int end = fqn.indexOf('$'); 090 final String top = -1==end ? fqn : fqn.substring(0,end); 091 source = top.replace('.', '/') + ".java"; 092 } 093 sites.append(new CallSite(name, source, line > 1 094 ? PowerlessArray.array(IntArray.array(line)) : null)); 095 } 096 return sites.length() != 0 ? new Trace(sites.snapshot()) : null; 097 } 098 } 099 return new TracerX(); 100 } 101 }