diff --git a/.gitignore b/.gitignore index 385805d2ab8..5ca2bec15ea 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ replay_pid* .bsp/ **/src/*/generated/* !dd-java-agent/benchmark/releases/*.jar +*.jar # Magic for local JMC built /vendor/jmc-libs diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InitializationTelemetry.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InitializationTelemetry.java index d6cf0958ca9..c192d1c4600 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InitializationTelemetry.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InitializationTelemetry.java @@ -8,7 +8,7 @@ * Thread safe wrapper around BootstrapInitializationTelemetry used inside the Datadog ClassLoader. * *
Right now, this is needed because of the build separation between the two portions of the - * bootstrap. We should consider adjusting the build to allow Agent et al to reference + * bootstrap. We should consider adjusting the build to allow Agent et al. to reference * BootstrapInitializationTelemetry, then we could remove this proxy. */ public abstract class InitializationTelemetry { @@ -48,7 +48,7 @@ public static final InitializationTelemetry noOpInstance() { public abstract void onFatalError(Throwable t); /** - * Indicates that an exception conditional occurred during the bootstrapping process. By default + * Indicates that an exception conditional occurred during the bootstrapping process. By default, * the exceptional condition is assumed to NOT have fully stopped the initialization of the * tracer. * diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java index 6e09fa0f30a..a276ff9e8a2 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java @@ -92,6 +92,7 @@ public static final class JsonBased extends BootstrapInitializationTelemetry { // one way false to true private volatile boolean incomplete = false; + private volatile boolean error = false; JsonBased(JsonSender sender) { this.sender = sender; @@ -111,11 +112,14 @@ public void initMetaInfo(String attr, String value) { public void onAbort(String reasonCode) { onPoint("library_entrypoint.abort", "reason:" + reasonCode); markIncomplete(); + setMetadata("abort", mapResultClass(reasonCode), reasonCode); } @Override public void onError(Throwable t) { + error = true; onPoint("library_entrypoint.error", "error_type:" + t.getClass().getName()); + setMetadata("error", "internal_error", t.getMessage()); } @Override @@ -126,7 +130,32 @@ public void onFatalError(Throwable t) { @Override public void onError(String reasonCode) { + error = true; onPoint("library_entrypoint.error", "error_type:" + reasonCode); + setMetadata("error", mapResultClass(reasonCode), reasonCode); + } + + private void setMetadata(String result, String resultClass, String resultReason) { + initMetaInfo("result", result); + initMetaInfo("result_class", resultClass); + initMetaInfo("result_reason", resultReason); + } + + private String mapResultClass(String reasonCode) { + if (reasonCode == null) { + return "success"; + } + + switch (reasonCode) { + case "already_initialized": + return "already_instrumented"; + case "other-java-agents": + return "incompatible_library"; + case "jdk_tool": + return "unsupported_binary"; + default: + return "unknown"; + } } private void onPoint(String name, String tag) { @@ -143,6 +172,10 @@ public void markIncomplete() { @Override public void finish() { + if (!this.incomplete && !this.error) { + setMetadata("success", "success", "Successfully configured ddtrace package"); + } + try (JsonWriter writer = new JsonWriter()) { writer.beginObject(); writer.name("metadata").beginObject(); diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index a2919226eb5..6503ff44d10 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -11,6 +11,7 @@ /** Special lightweight pre-main class that skips installation on incompatible JVMs. */ public class AgentPreCheck { + public static final int MIN_JAVA_VERSION = 8; public static void premain(final String agentArgs, final Instrumentation inst) { agentmain(agentArgs, inst); } @@ -59,6 +60,10 @@ static void sendTelemetry(String forwarderPath, String javaVersion, String agent + "\"points\":[{" + "\"name\":\"library_entrypoint.abort\"," + "\"tags\":[\"reason:incompatible_runtime\"]" + + "\"result:error\"," + + "\"result_class:incompatible_runtime\"," + + "\"result_reason:java version" + MIN_JAVA_VERSION + "+ required\"" + + "]" + "}]" + "}"; @@ -87,7 +92,7 @@ private static boolean compatible() { static boolean compatible(String javaVersion, String javaHome, PrintStream output) { int majorJavaVersion = parseJavaMajorVersion(javaVersion); - if (majorJavaVersion >= 8) { + if (majorJavaVersion >= MIN_JAVA_VERSION) { return true; } diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/BootstrapInitializationTelemetryTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/BootstrapInitializationTelemetryTest.groovy index da0dafa6d4a..2a0cfbcfa74 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/BootstrapInitializationTelemetryTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/BootstrapInitializationTelemetryTest.groovy @@ -26,19 +26,47 @@ class BootstrapInitializationTelemetryTest extends Specification { initTelemetryProxy.setAdaptee(initTelemetry) this.initTelemetry = initTelemetryProxy + this.initTelemetry.initMetaInfo("runtime_name", "java") + this.initTelemetry.initMetaInfo("runtime_version", "1.8.0_382") this.capture = capture } - def "real example"() { + def "test success"() { when: - initTelemetry.initMetaInfo("runtime_name", "java") - initTelemetry.initMetaInfo("runtime_version", "1.8.0_382") + initTelemetry.finish() + + then: + capture.json() == json("success", "success", "Successfully configured ddtrace package", + [[name: "library_entrypoint.complete"]]) + } + def "real example"() { + when: initTelemetry.onError(new Exception("foo")) initTelemetry.finish() then: - capture.json() == '{"metadata":{"runtime_name":"java","runtime_version":"1.8.0_382"},"points":[{"name":"library_entrypoint.error","tags":["error_type:java.lang.Exception"]},{"name":"library_entrypoint.complete"}]}' + capture.json() == json("error", "internal_error", "foo", [ + [name: "library_entrypoint.error", tags: ["error_type:java.lang.Exception"]], + [name: "library_entrypoint.complete"] + ]) + } + + def "test abort"() { + when: + initTelemetry.onAbort(reasonCode) + initTelemetry.finish() + + then: + capture.json() == json("abort", resultClass, reasonCode, + [[name: "library_entrypoint.abort", tags: ["reason:${reasonCode}"]]]) + + where: + reasonCode | resultClass + "jdk_tool" | "unsupported_binary" + "already_initialized" | "already_instrumented" + "other-java-agents" | "incompatible_library" + "foo" | "unknown" } def "trivial completion check"() { @@ -65,6 +93,8 @@ class BootstrapInitializationTelemetryTest extends Specification { then: !capture.json().contains("library_entrypoint.complete") + capture.json() == json("error", "internal_error", "foo", + [[name: "library_entrypoint.error", tags: ["error_type:java.lang.Exception"]]]) } def "incomplete on abort"() { @@ -76,6 +106,10 @@ class BootstrapInitializationTelemetryTest extends Specification { !capture.json().contains("library_entrypoint.complete") } + private String json(String result, String resultClass, String resultReason, List points) { + return """{"metadata":{"runtime_name":"java","runtime_version":"1.8.0_382","result":"${result}","result_class":"${resultClass}","result_reason":"${resultReason}"},"points":${new groovy.json.JsonBuilder(points)}}""" + } + static class Capture implements BootstrapInitializationTelemetry.JsonSender { String json