Skip to content

Commit

Permalink
Indy plugins (#1230)
Browse files Browse the repository at this point in the history
  • Loading branch information
felixbarny authored Jul 2, 2020
1 parent 5168a49 commit b0dbda2
Show file tree
Hide file tree
Showing 120 changed files with 3,898 additions and 2,100 deletions.
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) {
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);
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

0 comments on commit b0dbda2

Please sign in to comment.