You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by rm...@apache.org on 2013/12/08 22:07:12 UTC
svn commit: r1549252 - in /incubator/sirona/trunk/agent/javaagent/src:
main/java/org/apache/sirona/javaagent/
main/java/org/apache/sirona/javaagent/listener/
test/java/org/apache/sirona/javaagent/
test/java/org/apache/test/sirona/javaagent/ test/resour...
Author: rmannibucau
Date: Sun Dec 8 21:07:11 2013
New Revision: 1549252
URL: http://svn.apache.org/r1549252
Log:
SIRONA-17 get rid of includes/excludes on javaagent and use listeners to instrument only if needed
Added:
incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/Instrumented.java
incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaTransformer.java
incubator/sirona/trunk/agent/javaagent/src/test/resources/sirona.properties
Removed:
incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/test/sirona/javaagent/IncludeExcludeTest.java
Modified:
incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java
incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java
incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java
incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java
incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java
Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java?rev=1549252&r1=1549251&r2=1549252&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/AgentContext.java Sun Dec 8 21:07:11 2013
@@ -24,13 +24,7 @@ import org.apache.sirona.javaagent.spi.I
import org.apache.sirona.javaagent.spi.Order;
import org.apache.sirona.spi.SPI;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -88,10 +82,14 @@ public class AgentContext {
listeners.add(autoset);
}
- private static InvocationListener[] listeners(final String key) {
+ public static InvocationListener[] listeners(final String key) {
InvocationListener[] listeners = LISTENERS_BY_KEY.get(key);
if (listeners == null) {
listeners = findListeners(key);
+ if (listeners.length == 0) {
+ return null;
+ }
+
final InvocationListener[] old = LISTENERS_BY_KEY.putIfAbsent(key, listeners);
if (old != null) {
listeners = old;
Added: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/Instrumented.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/Instrumented.java?rev=1549252&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/Instrumented.java (added)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/Instrumented.java Sun Dec 8 21:07:11 2013
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.javaagent;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Instrumented {
+}
Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java?rev=1549252&r1=1549251&r2=1549252&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaAgent.java Sun Dec 8 21:07:11 2013
@@ -16,28 +16,15 @@
*/
package org.apache.sirona.javaagent;
-import org.apache.sirona.configuration.predicate.PredicateEvaluator;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
-
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
-import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
+import java.lang.annotation.Annotation;
import java.lang.instrument.Instrumentation;
-import java.lang.reflect.InvocationTargetException;
import java.net.URL;
-import java.security.ProtectionDomain;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.jar.JarFile;
public class SironaAgent {
- private static final Collection<String> JVM_ENHANCED = Arrays.asList(
- "sun/net/www/protocol/http/HttpURLConnection"
- );
-
public static void premain(final String agentArgs, final Instrumentation instrumentation) {
agentmain(agentArgs, instrumentation);
}
@@ -77,23 +64,32 @@ public class SironaAgent {
}
}
- try { // eager init
- loader.loadClass("org.apache.sirona.javaagent.AgentContext")
- .getMethod("touch").invoke(null);
- loader.loadClass("org.apache.sirona.configuration.Configuration")
- .getMethod("is", String.class, boolean.class).invoke(null, "", true);
+ try { // eager init of static blocks
+ Class.forName("org.apache.sirona.configuration.Configuration", true, loader);
+ Class.forName("org.apache.sirona.javaagent.AgentContext", true, loader);
} catch (final Exception e) {
e.printStackTrace();
}
try {
- instrumentation.addTransformer(
- ClassFileTransformer.class.cast(loader.loadClass("org.apache.sirona.javaagent.SironaAgent$SironaTransformer")
- .getConstructor(String.class).newInstance(agentArgs)),
- instrumentation.isRetransformClassesSupported());
+ final SironaTransformer transformer = SironaTransformer.class.cast(loader.loadClass("org.apache.sirona.javaagent.SironaTransformer").newInstance());
+ instrumentation.addTransformer(transformer, instrumentation.isRetransformClassesSupported());
- for (final String jvm : JVM_ENHANCED) {
- instrumentation.retransformClasses(loader.loadClass(jvm.replace('/', '.')));
+ final Class<? extends Annotation> instrumentedMarker = (Class<? extends Annotation>) loader.loadClass("org.apache.sirona.javaagent.Instrumented");
+ final Class<?> listener = loader.loadClass("org.apache.sirona.javaagent.spi.InvocationListener");
+ if (instrumentation.isRetransformClassesSupported()) {
+ for (final Class<?> jvm : instrumentation.getAllLoadedClasses()) {
+ if (!jvm.isArray()
+ && !listener.isAssignableFrom(jvm)
+ && jvm.getAnnotation(instrumentedMarker) == null
+ && instrumentation.isModifiableClass(jvm)) {
+ try {
+ instrumentation.retransformClasses(jvm);
+ } catch (final Exception e) {
+ System.err.println("Can't instrument: " + jvm.getName() + "[" + e.getMessage() + "]");
+ }
+ }
+ }
}
} catch (final Exception e) {
e.printStackTrace();
@@ -153,62 +149,4 @@ public class SironaAgent {
}
return null;
}
-
- public static class SironaTransformer implements ClassFileTransformer {
- private static final String DELEGATING_CLASS_LOADER = "sun.reflect.DelegatingClassLoader";
-
- private final PredicateEvaluator includeEvaluator;
- private final PredicateEvaluator excludeEvaluator;
-
- // used by reflection so don't change visibility without testing
- public SironaTransformer(final String agentArgs) {
- includeEvaluator = createEvaluator(agentArgs, "includes=", new PredicateEvaluator("true:true", ","));
- excludeEvaluator = createEvaluator(agentArgs, "excludes=", new PredicateEvaluator(null, null)); // no matching
- }
-
- private PredicateEvaluator createEvaluator(final String agentArgs, final String str, final PredicateEvaluator defaultEvaluator) {
- final String configuration = extractConfig(agentArgs, str);
- if (configuration != null) {
- return new PredicateEvaluator(configuration, ",");
- }
- return defaultEvaluator;
- }
-
- @Override
- public byte[] transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined,
- final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
- if (shouldTransform(className, loader)) {
- return doTransform(className, classfileBuffer);
- }
- return classfileBuffer;
- }
-
- private byte[] doTransform(final String className, final byte[] classfileBuffer) {
- try {
- final ClassReader reader = new ClassReader(classfileBuffer);
- final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
- final SironaClassVisitor advisor = new SironaClassVisitor(writer, className);
- reader.accept(advisor, ClassReader.SKIP_DEBUG);
- return writer.toByteArray();
- } catch (final RuntimeException re) {
- if (Boolean.getBoolean("sirona.agent.debug")) {
- re.printStackTrace();
- }
- throw re;
- }
- }
-
- private boolean shouldTransform(final String className, final ClassLoader loader) {
- return JVM_ENHANCED.contains(className)
- || !(loader == null // bootstrap classloader
- || className == null // framework with bug
- || loader.getClass().getName().equals(DELEGATING_CLASS_LOADER)
- || className.startsWith("sun/reflect")
- || className.startsWith("com/sun/proxy")
- || className.startsWith("org/apache/sirona"))
-
- && includeEvaluator.matches(className.replace("/", "."))
- && !excludeEvaluator.matches(className.replace("/", "."));
- }
- }
}
Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java?rev=1549252&r1=1549251&r2=1549252&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaClassVisitor.java Sun Dec 8 21:07:11 2013
@@ -61,6 +61,12 @@ public class SironaClassVisitor extends
}
@Override
+ public void visitSource(final String source, final String debug) {
+ super.visitSource(source, debug);
+ visitAnnotation("L" + Instrumented.class.getName().replace('.', '/') + ";", true).visitEnd();
+ }
+
+ @Override
public MethodVisitor visitMethod(int access, final String name, final String desc, final String signature, final String[] exceptions) {
final MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
if (!isSironable(access, name)) {
@@ -68,25 +74,27 @@ public class SironaClassVisitor extends
}
final String label = javaName.replace("/", ".") + "." + name;
-
- { // generate "proxy" method and store the associated field for counter key (generated at the end)
- final String fieldName = name + FIELD_SUFFIX;
- if (!keys.containsKey(fieldName)) {
- keys.put(fieldName, label);
+ if (AgentContext.listeners(label) != null) {
+ { // generate "proxy" method and store the associated field for counter key (generated at the end)
+ final String fieldName = name + FIELD_SUFFIX;
+ if (!keys.containsKey(fieldName)) {
+ keys.put(fieldName, label);
+ }
+
+ final ProxyMethodsVisitor sironaVisitor = new ProxyMethodsVisitor(visitor, access, new Method(name, desc), classType);
+ sironaVisitor.visitCode();
+ sironaVisitor.visitEnd();
}
- final ProxyMethodsVisitor sironaVisitor = new ProxyMethodsVisitor(visitor, access, new Method(name, desc), classType);
- sironaVisitor.visitCode();
- sironaVisitor.visitEnd();
+ // generate internal method - the proxy (previous one) delegates to this one
+ return super.visitMethod(forcePrivate(access), name + METHOD_SUFFIX, desc, signature, exceptions);
}
-
- // generate internal method - the proxy (previous one) delegates to this one
- return super.visitMethod(forcePrivate(access), name + METHOD_SUFFIX, desc, signature, exceptions);
+ return visitor;
}
@Override
public void visitEnd() {
- if (!keys.isEmpty()) {
+ if (hasAdviced()) {
for (final String key : keys.keySet()) {
visitField(CONSTANT_ACCESS, key, KEY_TYPE.getDescriptor(), null, null).visitEnd();
}
@@ -96,13 +104,15 @@ public class SironaClassVisitor extends
visitor.visitInsn(RETURN);
visitor.visitMaxs(0, 0);
visitor.visitEnd();
-
- keys.clear();
}
super.visitEnd();
}
+ public boolean hasAdviced() {
+ return !keys.isEmpty();
+ }
+
private static int forcePrivate(final int access) {
return (access & ~(Modifier.PRIVATE | Modifier.PUBLIC | Modifier.PROTECTED)) | Modifier.PRIVATE;
}
Added: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaTransformer.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaTransformer.java?rev=1549252&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaTransformer.java (added)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/SironaTransformer.java Sun Dec 8 21:07:11 2013
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.javaagent;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+
+public class SironaTransformer implements ClassFileTransformer {
+ private static final String DELEGATING_CLASS_LOADER = "sun.reflect.DelegatingClassLoader";
+
+ @Override
+ public byte[] transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined,
+ final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
+ if (shouldTransform(className, loader)) {
+ return doTransform(className, classfileBuffer);
+ }
+ return classfileBuffer;
+ }
+
+ private byte[] doTransform(final String className, final byte[] classfileBuffer) {
+ try {
+ final ClassReader reader = new ClassReader(classfileBuffer);
+ final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+ final SironaClassVisitor advisor = new SironaClassVisitor(writer, className);
+ reader.accept(advisor, ClassReader.SKIP_DEBUG);
+ if (advisor.hasAdviced()) {
+ return writer.toByteArray();
+ }
+ return classfileBuffer;
+ } catch (final RuntimeException re) {
+ if (Boolean.getBoolean("sirona.agent.debug")) {
+ re.printStackTrace();
+ }
+ throw re;
+ }
+ }
+
+ private static boolean shouldTransform(final String className, final ClassLoader loader) {
+ return !(className == null // framework with bug
+ || (loader != null && loader.getClass().getName().equals(DELEGATING_CLASS_LOADER))
+ || className.startsWith("sun/reflect")
+ || className.startsWith("com/sun/proxy")
+ || className.startsWith("org/apache/sirona"));
+ }
+}
Modified: incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java?rev=1549252&r1=1549251&r2=1549252&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/main/java/org/apache/sirona/javaagent/listener/CounterListener.java Sun Dec 8 21:07:11 2013
@@ -30,7 +30,7 @@ public class CounterListener extends Abs
private static final int KEY = 0;
private PredicateEvaluator includes = new PredicateEvaluator("true:true", ",");
- private PredicateEvaluator excludes = new PredicateEvaluator(null, null);
+ private PredicateEvaluator excludes = new PredicateEvaluator("prefix:java,prefix:sun,prefix:com.sun", ",");
@Override
public boolean accept(final String key) {
Modified: incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java?rev=1549252&r1=1549251&r2=1549252&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java (original)
+++ incubator/sirona/trunk/agent/javaagent/src/test/java/org/apache/sirona/javaagent/JavaAgentRunner.java Sun Dec 8 21:07:11 2013
@@ -119,9 +119,9 @@ public class JavaAgentRunner extends Blo
private static String[] buildProcessArgs(final FrameworkMethod mtd) throws IOException {
final Collection<String> args = new ArrayList<String>();
args.add(findJava());
- args.add("-javaagent:" + buildJavaagent() + "=excludes=regex:org.apache.test.*Test,prefix:org.junit,prefix:junit" /*+ "|=includes=regex:org.apache.test.sirona.*Transform"*/);
+ args.add("-javaagent:" + buildJavaagent());
if (Boolean.getBoolean("test.debug.remote")) {
- args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005");
+ args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + System.getProperty("test.debug.remote.port", "5005"));
}
args.add("-cp");
args.add(removeAgentFromCp(System.getProperty("surefire.test.class.path", System.getProperty("java.class.path"))));
@@ -129,6 +129,8 @@ public class JavaAgentRunner extends Blo
args.add(mtd.getMethod().getDeclaringClass().getName());
args.add(mtd.getName());
+ // System.out.println("Running " + args.toString().replace(",", "").substring(1).replace("]", ""));
+
return args.toArray(new String[args.size()]);
}
Added: incubator/sirona/trunk/agent/javaagent/src/test/resources/sirona.properties
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/javaagent/src/test/resources/sirona.properties?rev=1549252&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/javaagent/src/test/resources/sirona.properties (added)
+++ incubator/sirona/trunk/agent/javaagent/src/test/resources/sirona.properties Sun Dec 8 21:07:11 2013
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+org.apache.sirona.javaagent.listener.CounterListener.excludes = \
+ prefix:java,\
+ prefix:sun,\
+ prefix:com,\
+ regex:org.apache.test.*Test\\..*,\
+ prefix:org.junit,\
+ prefix:junit