Skip to content

Commit cc34116

Browse files
zeitlingertrask
andauthored
support dynamic attach (#13499)
Co-authored-by: Trask Stalnaker <[email protected]>
1 parent 5239984 commit cc34116

File tree

6 files changed

+98
-9
lines changed

6 files changed

+98
-9
lines changed

javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/OpenTelemetryAgent.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.net.URL;
1616
import java.util.jar.JarFile;
1717
import java.util.jar.Manifest;
18+
import javax.annotation.Nullable;
1819

1920
/**
2021
* Premain-Class for the OpenTelemetry Java agent.
@@ -42,19 +43,20 @@
4243
public final class OpenTelemetryAgent {
4344

4445
public static void premain(String agentArgs, Instrumentation inst) {
45-
startAgent(inst, true);
46+
startAgent(inst, agentArgs, true);
4647
}
4748

4849
public static void agentmain(String agentArgs, Instrumentation inst) {
49-
startAgent(inst, false);
50+
startAgent(inst, agentArgs, false);
5051
}
5152

52-
private static void startAgent(Instrumentation inst, boolean fromPremain) {
53+
private static void startAgent(
54+
Instrumentation inst, @Nullable String agentArgs, boolean fromPremain) {
5355
try {
5456
File javaagentFile = installBootstrapJar(inst);
5557
InstrumentationHolder.setInstrumentation(inst);
5658
JavaagentFileHolder.setJavaagentFile(javaagentFile);
57-
AgentInitializer.initialize(inst, javaagentFile, fromPremain);
59+
AgentInitializer.initialize(inst, javaagentFile, fromPremain, agentArgs);
5860
} catch (Throwable ex) {
5961
// Don't rethrow. We don't have a log manager here, so just print.
6062
System.err.println("ERROR " + OpenTelemetryAgent.class.getName());

javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/AgentInitializer.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,24 @@ public final class AgentInitializer {
2828
private static boolean isSecurityManagerSupportEnabled = false;
2929
private static volatile boolean agentStarted = false;
3030

31-
public static void initialize(Instrumentation inst, File javaagentFile, boolean fromPremain)
31+
public static void initialize(
32+
Instrumentation inst, File javaagentFile, boolean fromPremain, String agentArgs)
3233
throws Exception {
3334
if (agentClassLoader != null) {
3435
return;
3536
}
3637

38+
// this call deliberately uses anonymous class instead of lambda because using lambdas too
39+
// early on early jdk8 (see isEarlyOracle18 method) causes jvm to crash. See CrashEarlyJdk8Test.
40+
doPrivileged(
41+
new PrivilegedAction<Void>() {
42+
@Override
43+
public Void run() {
44+
setSystemProperties(agentArgs);
45+
return null;
46+
}
47+
});
48+
3749
// we expect that at this point agent jar has been appended to boot class path and all agent
3850
// classes are loaded in boot loader
3951
if (AgentInitializer.class.getClassLoader() != null) {
@@ -201,4 +213,28 @@ private static AgentStarter createAgentStarter(
201213
}
202214

203215
private AgentInitializer() {}
216+
217+
@SuppressWarnings("SystemOut")
218+
static void setSystemProperties(@Nullable String agentArgs) {
219+
boolean debug = false;
220+
if (agentArgs != null && !agentArgs.isEmpty()) {
221+
for (String option : agentArgs.split(";")) {
222+
int i = option.indexOf('=');
223+
if (i < 0) {
224+
System.err.println("Malformed agent argument: " + option);
225+
continue;
226+
}
227+
228+
String key = option.substring(0, i).trim();
229+
String value = option.substring(i + 1).trim();
230+
System.setProperty(key, value);
231+
if (key.equals("otel.javaagent.debug")) {
232+
debug = Boolean.parseBoolean(value);
233+
}
234+
if (debug) {
235+
System.err.println("Setting property [" + key + "] = " + value);
236+
}
237+
}
238+
}
239+
}
204240
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.bootstrap;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import org.junit.jupiter.api.AfterEach;
11+
import org.junit.jupiter.api.Test;
12+
13+
class AgentInitializerTest {
14+
@AfterEach
15+
void tearDown() {
16+
System.clearProperty("foo");
17+
System.clearProperty("bar");
18+
}
19+
20+
@Test
21+
void agentArgsSystemProperties() {
22+
AgentInitializer.setSystemProperties("foo=bar=baz;bar=b,c");
23+
24+
assertThat(System.getProperty("foo")).isEqualTo("bar=baz");
25+
assertThat(System.getProperty("bar")).isEqualTo("b,c");
26+
}
27+
}

smoke-tests/src/test/groovy/io/opentelemetry/smoketest/AppServerTest.groovy

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import io.opentelemetry.proto.trace.v1.Span
99
import io.opentelemetry.semconv.ClientAttributes
1010
import io.opentelemetry.semconv.NetworkAttributes
1111
import io.opentelemetry.semconv.UrlAttributes
12+
import io.opentelemetry.testing.internal.armeria.common.HttpMethod
13+
import io.opentelemetry.testing.internal.armeria.common.RequestHeaders
1214
import spock.lang.Shared
1315
import spock.lang.Unroll
1416

@@ -34,7 +36,7 @@ abstract class AppServerTest extends SmokeTest {
3436
def setupSpec() {
3537
(serverVersion, jdk) = getAppServer()
3638
isWindows = System.getProperty("os.name").toLowerCase().contains("windows") &&
37-
"1" != System.getenv("USE_LINUX_CONTAINERS")
39+
"1" != System.getenv("USE_LINUX_CONTAINERS")
3840

3941
// ibm-semeru-runtimes doesn't publish windows images
4042
// adoptopenjdk is deprecated and doesn't publish Windows 2022 images
@@ -102,7 +104,9 @@ abstract class AppServerTest extends SmokeTest {
102104
def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name.IMPLEMENTATION_VERSION)
103105

104106
when:
105-
def response = client().get("/app/greeting").aggregate().join()
107+
def response = client()
108+
.execute(RequestHeaders.of(HttpMethod.GET, "/app/greeting", "X-Test-Request", "test"))
109+
.aggregate().join()
106110
TraceInspector traces = new TraceInspector(waitForTraces())
107111
Set<String> traceIds = traces.traceIds
108112
String responseBody = response.contentUtf8()
@@ -141,6 +145,9 @@ abstract class AppServerTest extends SmokeTest {
141145
and: "Number of spans tagged with expected OS type"
142146
traces.countFilteredResourceAttributes(OS_TYPE.key, isWindows ? WINDOWS : LINUX) == 3
143147

148+
and: "Number of spans tagged with attribute set via agentArgs"
149+
traces.countFilteredArrayAttributes("http.request.header.x-test-request", "test") == 1
150+
144151
where:
145152
[appServer, jdk, isWindows] << getTestParams()
146153
}
@@ -392,7 +399,7 @@ abstract class AppServerTest extends SmokeTest {
392399

393400
responseBody.contains("<script>console.log(hi)</script>")
394401

395-
if (expectServerSpan()){
402+
if (expectServerSpan()) {
396403
traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1
397404
traces.countSpansByName('GET /app/jsp') == 1
398405
}
@@ -420,7 +427,7 @@ abstract class AppServerTest extends SmokeTest {
420427

421428
protected List<List<Object>> getTestParams() {
422429
return [
423-
[serverVersion, jdk, isWindows]
430+
[serverVersion, jdk, isWindows]
424431
]
425432
}
426433
}

smoke-tests/src/test/groovy/io/opentelemetry/smoketest/TraceInspector.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ public long countFilteredAttributes(String attributeName, Object attributeValue)
6666
.count();
6767
}
6868

69+
public long countFilteredArrayAttributes(String attributeName, Object attributeValue) {
70+
final Object value;
71+
if (attributeValue instanceof GString) {
72+
value = attributeValue.toString();
73+
} else {
74+
value = attributeValue;
75+
}
76+
return getSpanStream()
77+
.flatMap(s -> s.getAttributesList().stream())
78+
.filter(a -> a.getKey().equals(attributeName))
79+
.map(a -> a.getValue().getArrayValue().getValues(0).getStringValue())
80+
.filter(s -> s.equals(value))
81+
.count();
82+
}
83+
6984
public long countFilteredEventAttributes(String attributeName, Object attributeValue) {
7085
return getSpanStream()
7186
.flatMap(s -> s.getEventsList().stream())

smoke-tests/src/test/java/io/opentelemetry/smoketest/AbstractTestContainerManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ protected Map<String, String> getAgentEnvironment(
2727
jvmArgsEnvVarName,
2828
"-Xmx512m -javaagent:/"
2929
+ TARGET_AGENT_FILENAME
30+
// args passed to the agent directly
31+
+ "=otel.javaagent.debug=true;otel.instrumentation.http.server.capture-request-headers=X-Test-Request"
3032
// Liberty20Jdk11, Payara6Jdk11 and Payara6Jdk17 fail with
3133
// java.util.zip.ZipException: Invalid CEN header (invalid zip64 extra data field size)
3234
+ " -Djdk.util.zip.disableZip64ExtraFieldValidation=true");

0 commit comments

Comments
 (0)