Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Indy plugins #1230

Merged
merged 40 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
39e25ae
Use non-inlined advices where possible
felixbarny Jun 2, 2020
aaf059c
Isolated @AssignToArgument test
felixbarny Jun 2, 2020
dc2955a
Fix AssignToFieldPostProcessorFactory by loading this on stack before…
felixbarny Jun 2, 2020
ed3109f
Add workaround for VerifyError
felixbarny Jun 2, 2020
24614be
Fix compile errors and tests
felixbarny Jun 2, 2020
c5e92f9
Add ability to assign to multiple arguments, fields and return value
felixbarny Jun 3, 2020
543f3ae
Use indy dispatcher for Servlet and JDBC plugins
felixbarny Jun 6, 2020
d80e36f
java.lang.IndyBootstrap: take this OSGi!
felixbarny Jun 7, 2020
3e68d7e
Avoid NoClassDefFoundErrors when using OSGi CLs without bootdelegatio…
felixbarny Jun 7, 2020
75b5a29
Fix IndyBootstrapDispatcher noop MethodHandle
felixbarny Jun 8, 2020
4b3aa01
Polish and documentation
felixbarny Jun 12, 2020
98d5fb0
Add test for updating class file version while retransforming
felixbarny Jun 12, 2020
019ad45
Add tests for patching class file version
felixbarny Jun 14, 2020
90d1320
Add validations for indy advices
felixbarny Jun 14, 2020
b1648ca
Remove inline=false from non-indy advices
felixbarny Jun 14, 2020
f061612
Merge remote-tracking branch 'origin/master' into indy-dispatch
felixbarny Jun 14, 2020
42d4839
Add docs, rename indyDispatch to indyPlugin
felixbarny Jun 14, 2020
6771a07
Fix tests
felixbarny Jun 14, 2020
87f324f
Update Byte Buddy
felixbarny Jun 15, 2020
8553bb6
Use MutableInt instead of AtomicInteger for CallDepth
felixbarny Jun 16, 2020
cdafeaf
Merge remote-tracking branch 'origin/master' into indy-dispatch
felixbarny Jun 17, 2020
6abbf01
Make concurrent, process, and HttpUrlConnection indy plugins
felixbarny Jun 18, 2020
8f156cf
Make @AssignTo* annotations inner classes of @AssignTo
felixbarny Jun 18, 2020
d47f768
Update Byte Buddy to 1.10.12
felixbarny Jun 18, 2020
e2d1e23
Merge remote-tracking branch 'origin/master' into indy-dispatch
felixbarny Jun 18, 2020
d4d09b2
Fix JMS tests
felixbarny Jun 19, 2020
3437036
Fix Kafka instrumentation
felixbarny Jun 19, 2020
0d10839
Fix ITs by lazily resolving type descriptions
felixbarny Jun 19, 2020
b1c69b4
Fix another test
felixbarny Jun 19, 2020
8c8b5f4
Fix bootstrap method signature
felixbarny Jun 19, 2020
960146a
Fix Payara and WebSphere tests
felixbarny Jun 22, 2020
c55474b
Fix Spring Boot tests
felixbarny Jun 22, 2020
a016876
Add bytecode examples
felixbarny Jun 25, 2020
2dec53f
Merge remote-tracking branch 'origin/master' into indy-dispatch
felixbarny Jun 25, 2020
076f116
Apply suggestions from code review
felixbarny Jun 25, 2020
eb12fb1
Implement suggestions from review
felixbarny Jun 29, 2020
ec53de6
Disallow ThreadLocals in instrumentation plugins
felixbarny Jun 29, 2020
c4bfd97
Add no shading to benefits
felixbarny Jun 30, 2020
4f56565
Allow trace_methods to instrument core java classes
felixbarny Jun 30, 2020
55d987b
Merge remote-tracking branch 'origin/master' into indy-dispatch
felixbarny Jul 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion apm-agent-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,14 @@
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<artifactId>byte-buddy-dep</artifactId>
<version>${version.byte-buddy}</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>org.hdrhistogram</groupId>
<artifactId>HdrHistogram</artifactId>
Expand Down Expand Up @@ -139,6 +144,18 @@
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
103 changes: 69 additions & 34 deletions apm-agent-core/src/main/java/co/elastic/apm/agent/bci/AgentMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package co.elastic.apm.agent.bci;

import javax.annotation.Nullable;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -74,12 +75,13 @@ public synchronized static void init(String agentArguments, Instrumentation inst

String javaVersion = System.getProperty("java.version");
String javaVmName = System.getProperty("java.vm.name");
if (!isJavaVersionSupported(javaVersion, javaVmName)) {
String javaVmVersion = System.getProperty("java.vm.version");
if (!isJavaVersionSupported(javaVersion, javaVmName, javaVmVersion)) {
// Gracefully abort agent startup is better than unexpected failure down the road when we known a given JVM
// version is not supported. Agent might trigger known JVM bugs causing JVM crashes, notably on early Java 8
// versions (but fixed in later versions), given those versions are obsolete and agent can't have workarounds
// for JVM internals, there is no other option but to use an up-to-date JVM instead.
System.err.println(String.format("Failed to start agent - JVM version not supported: %s", javaVersion));
System.err.println(String.format("Failed to start agent - JVM version not supported: %s %s %s", javaVersion, javaVmName, javaVmVersion));
return;
}

Expand All @@ -97,7 +99,7 @@ public synchronized static void init(String agentArguments, Instrumentation inst
.getMethod("initialize", String.class, Instrumentation.class, File.class, boolean.class)
.invoke(null, agentArguments, instrumentation, agentJarFile, premain);
System.setProperty("ElasticApm.attached", Boolean.TRUE.toString());
} catch (Exception e) {
} catch (Exception | LinkageError e) {
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
System.err.println("Failed to start agent");
e.printStackTrace();
}
Expand All @@ -110,47 +112,80 @@ public synchronized static void init(String agentArguments, Instrumentation inst
* unknown version format, we assume it's supported, thus this method might return false positives, but never false
* negatives.
*
* @param version jvm version, from {@code System.getProperty("java.version")}
* @param vmName jvm name, from {@code System.getProperty("java.vm.name")}
* @param version jvm version, from {@code System.getProperty("java.version")}
* @param vmName jvm name, from {@code System.getProperty("java.vm.name")}
* @param vmVersion jvm version, from {@code System.getProperty("java.vm.version")}
* @return true if the version is supported, false otherwise
*/
// package-protected for testing
static boolean isJavaVersionSupported(String version, String vmName) {
boolean postJsr223 = !version.startsWith("1.");
static boolean isJavaVersionSupported(String version, String vmName, @Nullable String vmVersion) {
// new scheme introduced in java 9, thus we can use it as a shortcut
if (postJsr223) {
return true;
int major;
if (version.startsWith("1.")) {
major = Character.digit(version.charAt(2), 10);
} else {
major = Integer.parseInt(version.split("\\.")[0]);
}

char major = version.charAt(2);
if (major < '7') {
boolean isHotSpot = vmName.contains("HotSpot(TM)") || vmName.contains("OpenJDK");
boolean isIbmJ9 = vmName.contains("IBM J9");
if (major < 7) {
// given code is compiled with java 7, this one is unlikely in practice
return false;
} else if (major == '7' || major > '8') {
return true;
} else if (!vmName.contains("HotSpot(TM)")) {
// non-hotspot JVMs are not concerned (yet)
return true;
} else {
// HotSpot 8
int updateIndex = version.lastIndexOf("_");
if (updateIndex <= 0) {
// GA release '1.8.0'
}
if (isHotSpot) {
return isHotSpotVersionSupported(version, major);
} else if (isIbmJ9) {
return isIbmJ9VersionSupported(vmVersion, major);
}
// innocent until proven guilty
return true;
}

private static boolean isHotSpotVersionSupported(String version, int major) {
switch (major) {
case 7:
// versions prior to that have unreliable invoke dynamic support according to https://groovy-lang.org/indy.html
return isUpdateVersionAtLeast(version, 60);
case 8:
return isUpdateVersionAtLeast(version, 40);
default:
return true;
}
}

private static boolean isIbmJ9VersionSupported(@Nullable String vmVersion, int major) {
switch (major) {
case 7:
return false;
case 8:
// early versions crash during invokedynamic bootstrap
// the exact version that fixes that error is currently not known
// presumably, service refresh 5 (build 2.8) fixes the issue
return !"2.8".equals(vmVersion);
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
default:
return true;
}
}

private static boolean isUpdateVersionAtLeast(String version, int minimumUpdateVersion) {
int updateIndex = version.lastIndexOf("_");
if (updateIndex <= 0) {
// GA release '1.8.0'
return false;
} else {
int versionSuffixIndex = version.indexOf('-', updateIndex + 1);
String updateVersion;
if (versionSuffixIndex <= 0) {
updateVersion = version.substring(updateIndex + 1);
} else {
int versionSuffixIndex = version.indexOf('-', updateIndex + 1);
String updateVersion;
if (versionSuffixIndex <= 0) {
updateVersion = version.substring(updateIndex + 1);
} else {
updateVersion = version.substring(updateIndex + 1, versionSuffixIndex);
}
try {
return Integer.parseInt(updateVersion) >= 40;
} catch (NumberFormatException e) {
// in case of unknown format, we just support by default
return true;
}
updateVersion = version.substring(updateIndex + 1, versionSuffixIndex);
}
try {
return Integer.parseInt(updateVersion) >= minimumUpdateVersion;
} catch (NumberFormatException e) {
// in case of unknown format, we just support by default
return true;
}
}
}
Expand Down
Loading