-
Notifications
You must be signed in to change notification settings - Fork 1k
extension smoke test to avoid regression with indy #15497
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
Open
SylvainJuge
wants to merge
24
commits into
open-telemetry:main
Choose a base branch
from
SylvainJuge:extensions-examples-indy
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+380
−2
Open
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
cabecf0
boostrap app in docker image
SylvainJuge a545981
Merge branch 'main' of github.com:open-telemetry/opentelemetry-java-i…
SylvainJuge dda3c85
start creating instrumentation
SylvainJuge 45a5d60
wip
SylvainJuge 678a6fb
wip
SylvainJuge 7c907ce
add missing dependencies
SylvainJuge 9c9d3de
add missing task dependency for tests
SylvainJuge 9766b9f
fix instrumentation
SylvainJuge 352431d
it's working !!
SylvainJuge b0a8052
further simplify and modify arguments
SylvainJuge a157d64
wip: test with virtual fields
SylvainJuge 00e8b59
add wip changes
SylvainJuge 04d5252
simplify things without custom docker image
SylvainJuge 27c951c
fix virtual fields and make it work again
SylvainJuge 31ecfc2
fix test assertions + impl local variable
SylvainJuge 4fe6a4b
local value support working
SylvainJuge 6d3508f
spotless
SylvainJuge f280d72
Merge branch 'main' of github.com:open-telemetry/opentelemetry-java-i…
SylvainJuge 936f40c
update readme
SylvainJuge cf39a5a
Merge branch 'main' of github.com:open-telemetry/opentelemetry-java-i…
SylvainJuge 4f01f70
rename and simplify
SylvainJuge 2a1fae5
Merge branch 'main' of github.com:open-telemetry/opentelemetry-java-i…
SylvainJuge 94916f4
Merge branch 'main' of github.com:open-telemetry/opentelemetry-java-i…
SylvainJuge c254070
Merge branch 'main' of github.com:open-telemetry/opentelemetry-java-i…
SylvainJuge File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| plugins { | ||
| id("otel.java-conventions") | ||
| id("io.opentelemetry.instrumentation.javaagent-instrumentation") | ||
| } | ||
|
|
||
| dependencies { | ||
| compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") | ||
| compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api") | ||
| compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator") | ||
| compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api") | ||
|
|
||
| compileOnly("com.google.auto.service:auto-service") | ||
| compileOnly("com.google.auto.service:auto-service-annotations") | ||
|
|
||
| annotationProcessor("com.google.auto.service:auto-service") | ||
|
|
||
| // Used by byte-buddy but not brought in as a transitive dependency | ||
| compileOnly("com.google.code.findbugs:annotations") | ||
| } |
104 changes: 104 additions & 0 deletions
104
.../main/java/io/opentelemetry/smoketest/extensions/inlined/SmokeInlinedInstrumentation.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.smoketest.extensions.inlined; | ||
|
|
||
| import static net.bytebuddy.matcher.ElementMatchers.named; | ||
| import static net.bytebuddy.matcher.ElementMatchers.returns; | ||
| import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
|
||
| import io.opentelemetry.instrumentation.api.util.VirtualField; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
| import java.util.Arrays; | ||
| import net.bytebuddy.asm.Advice; | ||
| import net.bytebuddy.description.type.TypeDescription; | ||
| import net.bytebuddy.matcher.ElementMatcher; | ||
|
|
||
| public class SmokeInlinedInstrumentation implements TypeInstrumentation { | ||
|
|
||
| @Override | ||
| public ElementMatcher<TypeDescription> typeMatcher() { | ||
| return named("io.opentelemetry.smoketest.extensions.app.AppMain"); | ||
| } | ||
|
|
||
| @Override | ||
| public void transform(TypeTransformer transformer) { | ||
| transformer.applyAdviceToMethod( | ||
| named("returnValue").and(takesArgument(0, int.class)), | ||
| this.getClass().getName() + "$ModifyReturnValueAdvice"); | ||
| transformer.applyAdviceToMethod( | ||
| named("methodArguments").and(takesArgument(0, int.class)), | ||
| this.getClass().getName() + "$ModifyArgumentsAdvice"); | ||
| transformer.applyAdviceToMethod( | ||
| named("setVirtualFieldValue") | ||
| .and(takesArgument(0, Object.class)) | ||
| .and(takesArgument(1, Integer.class)), | ||
| this.getClass().getName() + "$VirtualFieldSetAdvice"); | ||
| transformer.applyAdviceToMethod( | ||
| named("getVirtualFieldValue") | ||
| .and(takesArgument(0, Object.class)) | ||
| .and(returns(Integer.class)), | ||
| this.getClass().getName() + "$VirtualFieldGetAdvice"); | ||
| transformer.applyAdviceToMethod( | ||
| named("localValue").and(takesArgument(0, int[].class)).and(returns(int[].class)), | ||
| this.getClass().getName() + "$LocalVariableAdvice"); | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class ModifyReturnValueAdvice { | ||
|
|
||
| @Advice.OnMethodExit(suppress = Throwable.class) | ||
| public static void onExit(@Advice.Return(readOnly = false) int returnValue) { | ||
| returnValue = returnValue + 1; | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class ModifyArgumentsAdvice { | ||
| @Advice.OnMethodEnter(suppress = Throwable.class) | ||
| public static void onEnter(@Advice.Argument(value = 0, readOnly = false) int argument) { | ||
| argument = argument - 1; | ||
| } | ||
| } | ||
|
|
||
| public static class VirtualFieldSetAdvice { | ||
| @Advice.OnMethodEnter(suppress = Throwable.class) | ||
| public static void onEnter( | ||
| @Advice.Argument(0) Object target, @Advice.Argument(1) Integer value) { | ||
| VirtualField<Object, Integer> field = VirtualField.find(Object.class, Integer.class); | ||
| field.set(target, value); | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class VirtualFieldGetAdvice { | ||
| @SuppressWarnings("UnusedVariable") | ||
| @Advice.OnMethodExit(suppress = Throwable.class) | ||
| public static void onExit( | ||
| @Advice.Argument(0) Object target, @Advice.Return(readOnly = false) Integer returnValue) { | ||
| VirtualField<Object, Integer> field = VirtualField.find(Object.class, Integer.class); | ||
| returnValue = field.get(target); | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class LocalVariableAdvice { | ||
|
|
||
| @SuppressWarnings("UnusedVariable") | ||
| @Advice.OnMethodEnter(suppress = Throwable.class) | ||
| public static void onEnter( | ||
| @Advice.Argument(0) int[] array, @Advice.Local("backup") int[] backupArray) { | ||
| backupArray = Arrays.copyOf(array, array.length); | ||
| } | ||
|
|
||
| @SuppressWarnings("UnusedVariable") | ||
| @Advice.OnMethodExit(suppress = Throwable.class) | ||
| public static void onExit( | ||
| @Advice.Return(readOnly = false) int[] array, @Advice.Local("backup") int[] backupArray) { | ||
| array = Arrays.copyOf(backupArray, backupArray.length); | ||
| } | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
...java/io/opentelemetry/smoketest/extensions/inlined/SmokeInlinedInstrumentationModule.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.smoketest.extensions.inlined; | ||
|
|
||
| import com.google.auto.service.AutoService; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| @AutoService(InstrumentationModule.class) | ||
| public class SmokeInlinedInstrumentationModule extends InstrumentationModule { | ||
|
|
||
| public SmokeInlinedInstrumentationModule() { | ||
| super("smoke-test-extension-inlined"); | ||
| } | ||
|
|
||
| @Override | ||
| public List<TypeInstrumentation> typeInstrumentations() { | ||
| return Collections.singletonList(new SmokeInlinedInstrumentation()); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| plugins { | ||
| id("otel.java-conventions") | ||
| } | ||
|
|
||
| dependencies { | ||
| } | ||
|
|
||
| java { | ||
| sourceCompatibility = JavaVersion.VERSION_1_8 | ||
| targetCompatibility = JavaVersion.VERSION_1_8 | ||
| } | ||
|
|
||
| tasks { | ||
| jar { | ||
| manifest { | ||
| attributes("Main-Class" to "io.opentelemetry.smoketest.extensions.app.AppMain") | ||
| } | ||
| } | ||
| } |
97 changes: 97 additions & 0 deletions
97
...s/extensions/testapp/src/main/java/io/opentelemetry/smoketest/extensions/app/AppMain.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.smoketest.extensions.app; | ||
|
|
||
| import com.google.errorprone.annotations.CanIgnoreReturnValue; | ||
| import java.io.PrintStream; | ||
| import java.util.Arrays; | ||
|
|
||
| public class AppMain { | ||
|
|
||
| private AppMain() {} | ||
|
|
||
| public static void main(String[] args) { | ||
| testReturnValue(); | ||
| testMethodArguments(); | ||
| testVirtualFields(); | ||
| testLocalValue(); | ||
| } | ||
|
|
||
| private static void msg(String msg) { | ||
| // avoid checkstyle to complain | ||
| PrintStream out = System.out; | ||
| out.println(msg); | ||
| } | ||
|
|
||
| private static void testReturnValue() { | ||
| int returnValue = returnValue(42); | ||
| if (returnValue != 42) { | ||
| msg("return value has been modified"); | ||
| } else { | ||
| msg("return value not modified"); | ||
| } | ||
| } | ||
|
|
||
| private static int returnValue(int value) { | ||
| // method return value should be modified by instrumentation | ||
| return value; | ||
| } | ||
|
|
||
| private static void testMethodArguments() { | ||
| methodArguments(42, 42); | ||
| } | ||
|
|
||
| private static void methodArguments(int argument, int originalArgument) { | ||
| // method first argument should be modified by instrumentation | ||
| if (argument != originalArgument) { | ||
| msg("argument has been modified"); | ||
| } else { | ||
| msg("argument not modified"); | ||
| } | ||
| } | ||
|
|
||
| private static void testVirtualFields() { | ||
| Object target = new Object(); | ||
| setVirtualFieldValue(target, 42); | ||
| Integer fieldValue = getVirtualFieldValue(target); | ||
| if (fieldValue == null || fieldValue != 42) { | ||
| msg("virtual field not supported"); | ||
| } else { | ||
| msg("virtual field supported"); | ||
| } | ||
| } | ||
|
|
||
| public static void setVirtualFieldValue(Object target, Integer value) { | ||
| // implementation should be provided by instrumentation | ||
| } | ||
|
|
||
| public static Integer getVirtualFieldValue(Object target) { | ||
| // implementation should be provided by instrumentation | ||
| return null; | ||
| } | ||
|
|
||
| private static void testLocalValue() { | ||
| int[] input = new int[] {1, 2, 3}; | ||
| int[] result = localValue(input); | ||
| if (result.length != 3) { | ||
| throw new IllegalStateException(); | ||
| } | ||
| // assumption on the instrumentation implementation to use a local value to preserve original | ||
| // array | ||
| boolean preserved = result[0] == 1 && result[1] == 2 && result[2] == 3; | ||
| if (!preserved) { | ||
| msg("local advice variable not supported"); | ||
| } else { | ||
| msg("local advice variable supported"); | ||
| } | ||
| } | ||
|
|
||
| @CanIgnoreReturnValue | ||
| private static int[] localValue(int[] array) { | ||
| Arrays.fill(array, 0); | ||
| return array; | ||
| } | ||
| } |
99 changes: 99 additions & 0 deletions
99
smoke-tests/src/test/java/io/opentelemetry/smoketest/ExtensionsSmokeTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.smoketest; | ||
|
|
||
| import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; | ||
|
|
||
| import java.time.Duration; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import org.junit.jupiter.params.ParameterizedTest; | ||
| import org.junit.jupiter.params.provider.ValueSource; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.testcontainers.containers.GenericContainer; | ||
| import org.testcontainers.containers.output.OutputFrame; | ||
| import org.testcontainers.containers.output.Slf4jLogConsumer; | ||
| import org.testcontainers.utility.DockerImageName; | ||
| import org.testcontainers.utility.MountableFile; | ||
|
|
||
| public class ExtensionsSmokeTest { | ||
|
|
||
| private static final Logger logger = LoggerFactory.getLogger(ExtensionsSmokeTest.class); | ||
|
|
||
| private static final String TARGET_AGENT_FILENAME = "/opentelemetry-javaagent.jar"; | ||
| private static final String agentPath = | ||
| System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path"); | ||
|
|
||
| private static final String TARGET_EXTENSION_FILENAME = "/opentelemetry-extension.jar"; | ||
| private static final String extensionInlinePath = | ||
| System.getProperty("io.opentelemetry.smoketest.extension.inline.path"); | ||
|
|
||
| private static final String TARGET_APP_FILENAME = "/app.jar"; | ||
| private static final String appPath = | ||
| System.getProperty("io.opentelemetry.smoketest.extension.testapp.path"); | ||
|
|
||
| private static final String IMAGE = "eclipse-temurin:21"; | ||
|
|
||
| @ParameterizedTest | ||
| @ValueSource(booleans = {true, false}) | ||
| void inlinedExtension(boolean indy) throws InterruptedException { | ||
|
|
||
| List<String> cmd = new ArrayList<>(); | ||
| cmd.add("java"); | ||
| cmd.add("-javaagent:" + TARGET_AGENT_FILENAME); | ||
|
|
||
| Map<String, String> config = new HashMap<>(); | ||
| // disable export as we only instrument | ||
| config.put("otel.logs.exporter", "none"); | ||
| config.put("otel.metrics.exporter", "none"); | ||
| config.put("otel.traces.exporter", "none"); | ||
| // add extension | ||
| config.put("otel.javaagent.extensions", TARGET_EXTENSION_FILENAME); | ||
| // toggle indy on/off | ||
| config.put("otel.javaagent.experimental.indy", Boolean.toString(indy)); | ||
| // toggle debug if needed | ||
| config.put("otel.javaagent.debug", "false"); | ||
| config.forEach((k, v) -> cmd.add(String.format("-D%s=%s", k, v))); | ||
|
|
||
| cmd.add("-jar"); | ||
| cmd.add(TARGET_APP_FILENAME); | ||
|
|
||
| GenericContainer<?> target = | ||
| new GenericContainer<>(DockerImageName.parse(IMAGE)) | ||
| .withStartupTimeout(Duration.ofMinutes(1)) | ||
| .withLogConsumer(new Slf4jLogConsumer(logger)) | ||
| .withCopyFileToContainer(MountableFile.forHostPath(agentPath), TARGET_AGENT_FILENAME) | ||
| .withCopyFileToContainer( | ||
| MountableFile.forHostPath(extensionInlinePath), TARGET_EXTENSION_FILENAME) | ||
| .withCopyFileToContainer(MountableFile.forHostPath(appPath), TARGET_APP_FILENAME) | ||
| .withCommand(String.join(" ", cmd)); | ||
|
|
||
| logger.info("starting JVM with command: " + String.join(" ", cmd)); | ||
| target.start(); | ||
| while (target.isRunning()) { | ||
| Thread.sleep(100); | ||
| } | ||
|
|
||
| List<String> appOutput = | ||
| Arrays.asList(target.getLogs(OutputFrame.OutputType.STDOUT).split("\n")); | ||
| assertThat(appOutput) | ||
| .describedAs("return value instrumentation") | ||
| .contains("return value has been modified"); | ||
| assertThat(appOutput) | ||
| .describedAs("argument value instrumentation") | ||
| .contains("argument has been modified"); | ||
| assertThat(appOutput) | ||
| .describedAs("virtual field support") | ||
| .contains("virtual field supported"); | ||
| assertThat(appOutput) | ||
| .describedAs("local advice variable support") | ||
| .contains("local advice variable supported"); | ||
|
Comment on lines
84
to
95
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] I know parsing the output can be brittle, but the application is elementary so this should be fine. |
||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[for reviewer] for now we only test with a single rather recent JVM, as far as I know we don't have things that might be influenced by the JVM version that relate to indy instrumentation.