/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter; import java.io.File; import java.io.IOException; import java.lang.instrument.Instrumentation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.jar.JarFile; import org.helios.apmrouter.byteman.sockets.impl.SocketImplTransformer; import org.helios.apmrouter.util.SimpleLogger; /** * <p>Title: Agent</p> * <p>Description: The apmrouter client java agent and main entry point</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.Agent</code></p> */ public class Agent { /** The provided instrumentation instance */ protected static Instrumentation instrumentation = null; /** The provided agent argument string */ protected static String agentArgs = null; /** The core classloader */ protected static ClassLoader coreClassLoader = null; /** The name of the boot class */ public static final String BOOT_CLASS = "org.helios.apmrouter.jagent.AgentBoot"; /** * Returns the version of the passed class * @param clazz The class to get the version of * @return the version */ public static String version(Class<?> clazz) { String version = clazz.getPackage().getImplementationVersion(); if(version==null || version.trim().isEmpty()) version = "Development Snapshot"; return version; } /** * The main entry point for javaagents or optional standalone monitor deploy. * @param args One parameter processed which is the URL to an XML config */ public static void main(String[] args) { final long start = System.currentTimeMillis(); appendToBootClassPath(); installBoostrapInstrumentation(); coreClassLoader = getIsolatedClassLoader(); final ClassLoader current = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(coreClassLoader); Class<?> bootClass = Class.forName(BOOT_CLASS, true, coreClassLoader); //Class<?> bootClass = Class.forName(BOOT_CLASS); Method method = bootClass.getDeclaredMethod("boot", URLClassLoader.class, String.class, Instrumentation.class); method.invoke(null, args.length==0 ? null : Thread.currentThread().getContextClassLoader(), args[0], instrumentation); final long elapsed = System.currentTimeMillis()-start; log("\n\t=============================================================================" + "\n\tAPMRouter JavaAgent v " + version(Agent.class) + " Successfully Started" + "\n\tCurrent Server URI:" + System.getProperty("org.helios.apmrouter.uri", "udp://localhost:2094") + "\n\tAgent start time:" + elapsed + " ms" + "\n\t=============================================================================\n"); } catch (Exception e) { System.err.println("Failed to load apmrouter java-agent core. Stack trace follows:"); e.printStackTrace(System.err); } finally { Thread.currentThread().setContextClassLoader(current); } } protected static void appendToBootClassPath() { try { URL jarUrl = Agent.class.getProtectionDomain().getCodeSource().getLocation(); File agentFile = new File(jarUrl.getFile()); JarFile jarFile = new JarFile(agentFile); log("Agent Code Source: [" + jarUrl + "] File: [" + agentFile + "]"); Agent.instrumentation.appendToBootstrapClassLoaderSearch(jarFile); } catch (Exception ex) { ex.printStackTrace(System.err); } } /** * Installs bootstrap instrumentation shims. */ protected static void installBoostrapInstrumentation() { installSocketTracker(); } /** * Starts the socket tracking instrumentation unless disabled by sysprop */ protected static void installSocketTracker() { SocketImplTransformer sit = new SocketImplTransformer(); instrumentation.addTransformer(sit, true); try { Object sock = Class.forName("java.net.Socket").newInstance(); Field f = sock.getClass().getDeclaredField("impl"); f.setAccessible(true); Object sockImpl = f.get(sock); instrumentation.retransformClasses(sockImpl.getClass(), sockImpl.getClass().getSuperclass()); SimpleLogger.info("Retransformed [" + sockImpl.getClass().getName() + "]"); } catch (Exception ex) { ex.printStackTrace(System.err); } } /* String agentFile = System.getProperty("agent.file"); JarFile jarFile = new JarFile(agentFile); Agent.instrumentation.appendToBootstrapClassLoaderSearch(jarFile); ClassFileTransformer transformer = (ClassFileTransformer)Class.forName("org.helios.apmrouter.byteman.sockets.impl.SocketImplTransformer").newInstance(); Agent.instrumentation.addTransformer(transformer); */ /** * Creates an isolated classloader to load the core library underlying the agent * @return a classloader */ private static ClassLoader getIsolatedClassLoader() { try { URL agentURL = Agent.class.getProtectionDomain().getCodeSource().getLocation(); //new URL("jar:file:/C:/proj/parser/jar/parser.jar!/test.xml"); URL coreURL = new URL("jar:" + agentURL + "!/core.jar"); //URL coreURL = new URL(agentURL + "!/core.jar"); log("Core URL:" + coreURL); return new JarClassLoader(new URL[]{agentURL, coreURL}, Agent.class.getClassLoader()); } catch (Exception e) { throw new RuntimeException("Failed to create isolated class loader", e); } } /** * The pre-main entry point * @param agentArgs The agent bootstrap arguments * @param inst The Instrumentation instance */ public static void premain(String agentArgs, Instrumentation inst) { Agent.agentArgs = agentArgs; Agent.instrumentation = inst; main(new String[]{agentArgs}); } /** * The pre-main entry point for JVMs not supporting a <b><code>java.lang.instrument.Instrumentation</code></b> implementation. * @param agentArgs The agent bootstrap arguments */ public static void premain(String agentArgs) { Agent.agentArgs = agentArgs; main(new String[]{agentArgs}); } /** * The agent attach entry point * @param agentArgs The agent bootstrap arguments * @param inst The Instrumentation instance */ public static void agentmain(String agentArgs, Instrumentation inst) { Agent.agentArgs = agentArgs; Agent.instrumentation = inst; main(new String[]{agentArgs}); } /** * The agent attach entry point for JVMs not supporting a <b><code>java.lang.instrument.Instrumentation</code></b> implementation. * @param agentArgs The agent bootstrap arguments */ public static void agentmain(String agentArgs) { Agent.agentArgs = agentArgs; main(new String[]{agentArgs}); } /** * Simple out logger * @param msg the message */ public static void log(Object msg) { System.out.println(msg); } /** * Simple err logger * @param msg the message */ public static void elog(Object msg) { System.err.println(msg); } /** * Error logger * @param msg The error message * @param t The throwable to print the stack trace for */ public static void loge(Object msg, Throwable t) { System.err.println(msg); t.printStackTrace(System.err); } }