From 83f3613f1cb1de869d471557392fec28006853d5 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Thu, 21 Jul 2022 22:02:23 +0200 Subject: [PATCH] Use more OTel code for runtime attachment (#2414) --- agent/runtime-attach/build.gradle.kts | 3 +- .../attach/AppInsightAgentFileProvider.java | 87 ------------ .../attach/ApplicationInsights.java | 33 +++-- .../attach/RuntimeAttach.java | 126 ------------------ 4 files changed, 22 insertions(+), 227 deletions(-) delete mode 100644 agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/AppInsightAgentFileProvider.java delete mode 100644 agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/RuntimeAttach.java diff --git a/agent/runtime-attach/build.gradle.kts b/agent/runtime-attach/build.gradle.kts index 8908efb7134..4198a79b963 100644 --- a/agent/runtime-attach/build.gradle.kts +++ b/agent/runtime-attach/build.gradle.kts @@ -10,8 +10,7 @@ val otelVersion: String by project val agent: Configuration by configurations.creating dependencies { - implementation("net.bytebuddy:byte-buddy-agent") // To replace with implementation("io.opentelemetry.contrib:opentelemetry-runtime-attach:$otelContribAlphaVersion") - // after next OTel java contrib release + implementation("io.opentelemetry.contrib:opentelemetry-runtime-attach-core:$otelContribAlphaVersion") agent(project(":agent:agent", configuration = "shadow")) } diff --git a/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/AppInsightAgentFileProvider.java b/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/AppInsightAgentFileProvider.java deleted file mode 100644 index ca2c7b8c7a3..00000000000 --- a/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/AppInsightAgentFileProvider.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.attach; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Properties; - -final class AppInsightAgentFileProvider { - - static File getAgentFile() { - - Path tempDirPath = createTempDir(); - - Path tempAgentJarPath = createTempAgentJarFileIn(tempDirPath); - - deleteTempDirOnJvmExit(tempDirPath, tempAgentJarPath); - - return tempAgentJarPath.toFile(); - } - - private static void deleteTempDirOnJvmExit(Path tempDirPath, Path tempAgentJarPath) { - tempAgentJarPath.toFile().deleteOnExit(); - tempDirPath.toFile().deleteOnExit(); - } - - private static Path createTempDir() { - Path tempDir; - try { - tempDir = Files.createTempDirectory("otel-agent"); - } catch (IOException e) { - throw new IllegalStateException( - "Runtime attachment can't create a temp directory. You may use a read-only file system.", - e); - } - return tempDir; - } - - private static Path createTempAgentJarFileIn(Path tempDir) { - Path agentJarPath = tempDir.resolve("agent.jar"); - String appInsightVersion = findAppInsightVersion(); - try (InputStream jarAsInputStream = - ApplicationInsights.class.getResourceAsStream( - "/applicationinsights-agent-" + appInsightVersion + ".jar")) { - Files.copy(jarAsInputStream, agentJarPath); - } catch (IOException e) { - throw new IllegalStateException( - "Runtime attachment has failed. Are you using a JRE (not a JDK)?", e); - } - return agentJarPath; - } - - private static String findAppInsightVersion() { - try (InputStream jarAsInputStream = - ApplicationInsights.class.getResourceAsStream("/ai.sdk-version.properties")) { - Properties props = new Properties(); - props.load(jarAsInputStream); - return props.getProperty("version"); - } catch (IOException e) { - throw new IllegalStateException("Unable to fight Application Insights version", e); - } - } - - private AppInsightAgentFileProvider() {} -} diff --git a/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/ApplicationInsights.java b/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/ApplicationInsights.java index f1239197fbe..17ee8e0d0b8 100644 --- a/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/ApplicationInsights.java +++ b/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/ApplicationInsights.java @@ -21,13 +21,14 @@ package com.microsoft.applicationinsights.attach; +import io.opentelemetry.contrib.attach.CoreRuntimeAttach; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Optional; +import java.util.Properties; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -62,18 +63,10 @@ public static void attach() { System.setProperty(RUNTIME_ATTACHED_JSON_PROPERTY, jsonConfig.get()); } - File agentFile = AppInsightAgentFileProvider.getAgentFile(); + String appInsightResourceName = findAppInsightResourceName(); + CoreRuntimeAttach runtimeAttach = new CoreRuntimeAttach(appInsightResourceName); - try { - RuntimeAttach.attachJavaagentToCurrentJvm(agentFile); - } catch (IllegalStateException e) { - if (e.getMessage() != null - && e.getMessage() - .contains("No compatible attachment provider is available")) { // Byte Buddy exception - throw new IllegalStateException("Runtime attachment was not done. You may use a JRE.", e); - } - throw e; - } + runtimeAttach.attachJavaagentToCurrentJVM(); } private static Optional findJsonConfig() { @@ -102,4 +95,20 @@ private static boolean agentIsAttached() { return false; } } + + private static String findAppInsightResourceName() { + String appInsightVersion = findAppInsightVersion(); + return "/applicationinsights-agent-" + appInsightVersion + ".jar"; + } + + private static String findAppInsightVersion() { + try (InputStream jarAsInputStream = + ApplicationInsights.class.getResourceAsStream("/ai.sdk-version.properties")) { + Properties props = new Properties(); + props.load(jarAsInputStream); + return props.getProperty("version"); + } catch (IOException e) { + throw new IllegalStateException("Unable to find Application Insights version", e); + } + } } diff --git a/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/RuntimeAttach.java b/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/RuntimeAttach.java deleted file mode 100644 index 77ac2948777..00000000000 --- a/agent/runtime-attach/src/main/java/com/microsoft/applicationinsights/attach/RuntimeAttach.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.attach; - -import java.io.File; -import java.lang.management.ManagementFactory; -import net.bytebuddy.agent.ByteBuddyAgent; - -/** To remove after next OTel java contrib release */ -final class RuntimeAttach { - - private static final String AGENT_ENABLED_PROPERTY = "otel.javaagent.enabled"; - private static final String AGENT_ENABLED_ENV_VAR = "OTEL_JAVAAGENT_ENABLED"; - static final String MAIN_METHOD_CHECK_PROP = - "otel.javaagent.testing.runtime-attach.main-method-check"; - - /** - * Attach the OpenTelemetry Java agent to the current JVM. The attachment must be requested at the - * beginning of the main method. - * - * @param otelAgentFile OpenTelemetry agent file - */ - public static void attachJavaagentToCurrentJvm(File otelAgentFile) { - if (!shouldAttach()) { - return; - } - ByteBuddyAgent.attach(otelAgentFile, getPid()); - - if (!agentIsAttached()) { - printError("Agent was not attached. An unexpected issue has happened."); - } - } - - @SuppressWarnings("SystemOut") - private static void printError(String message) { - System.err.println(message); - } - - private static boolean shouldAttach() { - if (agentIsDisabledWithProp()) { - return false; - } - if (agentIsDisabledWithEnvVar()) { - return false; - } - if (agentIsAttached()) { - return false; - } - if (mainMethodCheckIsEnabled() && !isMainThread()) { - printError( - "Agent is not attached because runtime attachment was not requested from main thread."); - return false; - } - if (mainMethodCheckIsEnabled() && !isMainMethod()) { - printError( - "Agent is not attached because runtime attachment was not requested from main method."); - return false; - } - return true; - } - - private static boolean agentIsDisabledWithProp() { - String agentEnabledPropValue = System.getProperty(AGENT_ENABLED_PROPERTY); - return "false".equalsIgnoreCase(agentEnabledPropValue); - } - - private static boolean agentIsDisabledWithEnvVar() { - String agentEnabledEnvVarValue = System.getenv(AGENT_ENABLED_ENV_VAR); - return "false".equals(agentEnabledEnvVarValue); - } - - private static boolean agentIsAttached() { - try { - Class.forName("io.opentelemetry.javaagent.OpenTelemetryAgent", false, null); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - - private static boolean mainMethodCheckIsEnabled() { - String mainThreadCheck = System.getProperty(MAIN_METHOD_CHECK_PROP); - return !"false".equals(mainThreadCheck); - } - - private static boolean isMainThread() { - Thread currentThread = Thread.currentThread(); - return "main".equals(currentThread.getName()); - } - - static boolean isMainMethod() { - StackTraceElement bottomOfStack = findBottomOfStack(Thread.currentThread()); - String methodName = bottomOfStack.getMethodName(); - return "main".equals(methodName); - } - - private static StackTraceElement findBottomOfStack(Thread thread) { - StackTraceElement[] stackTrace = thread.getStackTrace(); - return stackTrace[stackTrace.length - 1]; - } - - private static String getPid() { - return ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; - } - - private RuntimeAttach() {} -}