From f3ec22bfa77edebb9f3e0071b02497e658f641e2 Mon Sep 17 00:00:00 2001 From: levinkerschberger <126667618+levinkerschberger@users.noreply.github.com> Date: Thu, 4 Jul 2024 16:05:04 +0200 Subject: [PATCH] Add compatibility with Java 21 (#1655) * Bumped ByteBuddy-Version and fixed Lambda-Problem in InstrumentationConfigurationResolver. * - Added Java 21 to Agent Test Matrix - Made Lambda-Check simpler * bumped gradle-version to 8.7 * made java 21 test independend. * test-workflow update. * moved docker plugin version to props. * updated workflow * changed jdk determination step to bash * clean gradle cache before executing assemble. * changed default wrapper to 8.7 * added DockerPlugin-Version to clean-step * added Downgrade Step for Java 8 * cahnged order of clean and downgrade * set shell to bash * deleted property from downgrade step. * Chaynged to other downgrade strat. * Downgraded Default Gradle Version * Downgraded Default Palantir Docker Version * add comments * change image * update spring config * fix: more lambda-problems solved * fix: auto-tracing test for java 21 * fix: auto-tracing test for java 21 * fix: HttpInMetric test for java 21 and AutoTracing for IBM JDK * fix: disable debug log might solve oom-issue on ibm-java * fix: changed max-heap-size for systemTest --------- Co-authored-by: EddeCCC --- .github/workflows/agent_test.yml | 32 ++++++++++++++++--- build.gradle | 6 ++-- .../build.gradle | 2 +- gradle.properties | 5 +++ gradle/libs.versions.toml | 5 +-- inspectit-ocelot-agent/build.gradle | 12 ++++++- .../http/HttpInMetricTest.java | 5 +-- .../tracing/AutoTracingTest.java | 28 ++++++++++++++-- .../tracing/TraceTestBase.java | 9 ++++++ .../config/spring/SpringConfiguration.java | 2 +- .../autotracing/StackTrace.java | 2 +- .../InstrumentationConfigurationResolver.java | 2 +- .../ExecutorContextPropagationSensor.java | 2 +- ...duledExecutorContextPropagationSensor.java | 2 +- settings.gradle | 2 +- 15 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 gradle.properties diff --git a/.github/workflows/agent_test.yml b/.github/workflows/agent_test.yml index 882730e9b2..95159933ed 100644 --- a/.github/workflows/agent_test.yml +++ b/.github/workflows/agent_test.yml @@ -24,21 +24,45 @@ jobs: fail-fast: false matrix: dockerimage: - - 'ibmcom/ibmjava:8-sdk' + - 'ibmjava:8-sdk' - 'eclipse-temurin:8' - 'eclipse-temurin:11' - 'eclipse-temurin:17' + - 'eclipse-temurin:21' container: ${{ matrix.dockerimage }} steps: - uses: actions/checkout@v3 - name: Grant execute permission for gradlew run: chmod +x gradlew + - name: Determine JDK version + id: determine-jdk + # if Java 21 is used, update com.palantir.docker to 0.36.0, because 0.34.0 is not compatible with gradle 8 + # Java 21 needs at least gradle 8 + shell: bash + run: | + java_version=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}') + echo "Java version: $java_version" + if [[ "$java_version" == 21* ]]; then + echo "::set-output name=gradle_property::comPalantirDockerVersion=0.36.0" + else + echo "::set-output name=gradle_property::comPalantirDockerVersion=0.34.0" + fi + - name: Upgrade Wrapper to 8.7 for Java 21 + # Java 21 needs at least gradle 8 + shell: bash + run: | + if [[ "${{ matrix.dockerimage }}" == "eclipse-temurin:21" ]]; then + sed -i 's/gradle-7.6-bin.zip/gradle-8.7-bin.zip/' gradle/wrapper/gradle-wrapper.properties + cat gradle/wrapper/gradle-wrapper.properties + fi + - name: Clean Gradle cache + run: ./gradlew -P${{ steps.determine-jdk.outputs.gradle_property }} clean - name: assemble - run: ./gradlew :inspectit-ocelot-core:assemble + run: ./gradlew -P${{ steps.determine-jdk.outputs.gradle_property }} :inspectit-ocelot-core:assemble - name: test - run: ./gradlew :inspectit-ocelot-core:test --no-daemon + run: ./gradlew -P${{ steps.determine-jdk.outputs.gradle_property }} :inspectit-ocelot-core:test --no-daemon - name: systemTest - run: ./gradlew :inspectit-ocelot-agent:systemTest + run: ./gradlew -P${{ steps.determine-jdk.outputs.gradle_property }} :inspectit-ocelot-agent:systemTest - name: upload test results uses: actions/upload-artifact@v2 if: ${{ failure() }} diff --git a/build.gradle b/build.gradle index b1d28c8264..bd731d13f2 100644 --- a/build.gradle +++ b/build.gradle @@ -140,10 +140,10 @@ tasks.register('codeCoverageReport', JacocoReport) { } reports { - xml.enabled true + xml.required = true xml.destination file("${buildDir}/reports/jacoco/report.xml") - html.enabled true + html.required = true html.destination file("${buildDir}/reports/jacoco/html") - csv.enabled false + csv.required = false } } diff --git a/components/inspectit-ocelot-configurationserver/build.gradle b/components/inspectit-ocelot-configurationserver/build.gradle index 8827a6ef45..27ffcef477 100644 --- a/components/inspectit-ocelot-configurationserver/build.gradle +++ b/components/inspectit-ocelot-configurationserver/build.gradle @@ -1,7 +1,7 @@ import org.springframework.boot.gradle.tasks.bundling.BootJar plugins { - alias(libs.plugins.comPalantirDocker) + id("com.palantir.docker") version "${comPalantirDockerVersion}" alias(configServerLibs.plugins.orgSpringframeworkBoot) alias(libs.plugins.orgCyclonedxBom) alias(configServerLibs.plugins.ioSpringDependencyManagement) diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..744ec8e2eb --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +# Select Docker Plugin Version +# For JDK Version < 21 we need to set this to "0.34.0" +# For JDK Version >= 21 we need to set this to "0.36.0" +# Above, we need "0.36.0". Cause this is experimental, we will keep it at 0.34.0 for now. +comPalantirDockerVersion=0.34.0 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d7268b7af1..b8a9913541 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,7 +65,7 @@ ioOpentelemetryOpentelemetrySemconv = { module = "io.opentelemetry:opentelemetry ioPrometheusSimpleclientHttpserver = "io.prometheus:simpleclient_httpserver:0.15.0" javaxAnnotationJavaxAnnotationApi = "javax.annotation:javax.annotation-api:1.3.2" log4j = "log4j:log4j:1.2.17" -netBytebuddyByteBuddy = "net.bytebuddy:byte-buddy:1.12.23" +netBytebuddyByteBuddy = "net.bytebuddy:byte-buddy:1.14.15" netLogstashLogbackLogstashLogbackEncoder = "net.logstash.logback:logstash-logback-encoder:7.4" orgApacheCommonsCommonsCollections4 = "org.apache.commons:commons-collections4:4.4" orgApacheCommonsCommonsLang3 = "org.apache.commons:commons-lang3:3.13.0" @@ -76,7 +76,7 @@ orgApacheLoggingLog4jLog4jCore = { module = "org.apache.logging.log4j:log4j-core orgApacheTomcatEmbedTomcatEmbedEl = "org.apache.tomcat.embed:tomcat-embed-el:9.0.85" orgAssertjAssertjCore = "org.assertj:assertj-core:3.22.0" orgAssertjAssertjGuava = "org.assertj:assertj-guava:3.24.2" -orgAwaitility = "org.awaitility:awaitility:4.2.0" +orgAwaitility = "org.awaitility:awaitility:4.2.1" orgEclipseJettyJettyServer = { module = "org.eclipse.jetty:jetty-server", version.ref = "orgEclipseJetty" } orgHibernateValidatorHibernateValidator = "org.hibernate.validator:hibernate-validator:6.2.5.Final" orgInfluxdbInfluxdbJava = "org.influxdb:influxdb-java:2.23" @@ -117,6 +117,7 @@ comGithubBenManesVersions = "com.github.ben-manes.versions:0.48.0" comGithubJk1DependencyLicenseReport = "com.github.jk1.dependency-license-report:2.0" comGithubNodeGradleNode = "com.github.node-gradle.node:7.0.1" # @pin There is a newer Version 0.35.0, but it is not Java 8 compatible +# For the Agent, this is currently provided via gradle.properties to make it dynamic. comPalantirDocker = "com.palantir.docker:0.34.0" ioSpringDependencyManagement = "io.spring.dependency-management:1.1.4" meChampeauJmh = "me.champeau.jmh:0.7.2" diff --git a/inspectit-ocelot-agent/build.gradle b/inspectit-ocelot-agent/build.gradle index 553e0b91b9..8df8d3db85 100644 --- a/inspectit-ocelot-agent/build.gradle +++ b/inspectit-ocelot-agent/build.gradle @@ -3,11 +3,13 @@ import org.springframework.boot.gradle.plugin.SpringBootPlugin plugins { alias(libs.plugins.meChampeauJmh) id 'maven-publish' - alias(libs.plugins.comPalantirDocker) + id("com.palantir.docker") version "${comPalantirDockerVersion}" alias(libs.plugins.orgSpringframeworkBoot) apply false alias(libs.plugins.ioSpringDependencyManagement) } + + dependencyManagement { imports { mavenBom(SpringBootPlugin.BOM_COORDINATES) @@ -260,6 +262,10 @@ task systemTest { includes = ["rocks/inspectit/*"] } + minHeapSize = "128m" + maxHeapSize = "2048m" + + // The JaCoCo agent must be specified first so that it can instrument our agent. // This is a work around for the issue that the JaCoCo agent is added last, cf. @@ -289,6 +295,9 @@ task systemTest { // that they are not garbage collected before being closed. jvmArgs "-Dio.opentelemetry.context.enableStrictContext=true" + minHeapSize = "128m" + maxHeapSize = "2048m" + // enable reflection used in TestUtils#initializeOpenTelemetryForSystemTesting for JDK 11 and later if(JavaVersion.current() >= JavaVersion.VERSION_11) { // --add-opens has the following syntax: {A}/{package}={B} @@ -309,6 +318,7 @@ task systemTest { systemTest.dependsOn perVersionSystemTest } } + systemTest.mustRunAfter test check.dependsOn systemTest diff --git a/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/http/HttpInMetricTest.java b/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/http/HttpInMetricTest.java index 89595db488..ced316cf39 100644 --- a/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/http/HttpInMetricTest.java +++ b/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/http/HttpInMetricTest.java @@ -43,7 +43,8 @@ public static class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - resp.setStatus(123); + // 123 was not a valid status code and rejected by jdk 21 + resp.setStatus(200); } } @@ -68,7 +69,7 @@ void testRequestRecorded() throws Exception { Map tags = new HashMap<>(); tags.put("http_path", "/servletapi"); - tags.put("http_status", "123"); + tags.put("http_status", "200"); long cnt = ((AggregationData.CountData) TestUtils.getDataForView("http/in/count", tags)).getCount(); double respSum = ((AggregationData.SumDataDouble) TestUtils.getDataForView("http/in/responsetime/sum", tags)) diff --git a/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/AutoTracingTest.java b/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/AutoTracingTest.java index dc46a92fdb..a300336e8a 100644 --- a/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/AutoTracingTest.java +++ b/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/AutoTracingTest.java @@ -1,5 +1,6 @@ package rocks.inspectit.ocelot.instrumentation.tracing; +import io.opentelemetry.sdk.trace.data.SpanData; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import rocks.inspectit.ocelot.utils.TestUtils; @@ -27,15 +28,36 @@ io.opentelemetry.sdk.trace.data.SpanData getSpanWithName(Collection { + io.opentelemetry.sdk.trace.data.SpanData root = getSpanWithName(spans, "AutoTracingTest.instrumentMe"); io.opentelemetry.sdk.trace.data.SpanData activeWait = getSpanWithName(spans, "*AutoTracingTest.activeWait"); - io.opentelemetry.sdk.trace.data.SpanData passiveWait = getSpanWithName(spans, "*Thread.sleep"); - assertThat(activeWait.getParentSpanId()).isEqualTo(root.getSpanId()); - assertThat(passiveWait.getParentSpanId()).isEqualTo(root.getSpanId()); + io.opentelemetry.sdk.trace.data.SpanData passiveWait; + + io.opentelemetry.sdk.trace.data.SpanData compareSpan; + + // Thread.sleep method appears as Thread.sleep0 in Java 21 + if(System.getProperty("java.version").startsWith("21")) { + // In Java 21 the root span AutoTracingTest.instrumentMe is followed by a child-span *AutoTracingTest.instrumentMe + compareSpan = getSpanWithName(spans, "*AutoTracingTest.instrumentMe"); + passiveWait = getSpanWithName(spans, "*Thread.sleep0"); + + } + else if(System.getProperty("java.vendor").startsWith("IBM")){ + compareSpan = root; + passiveWait = getSpanWithName(spans, "*Thread.sleepImpl"); + } + else { + compareSpan = root; + passiveWait = getSpanWithName(spans, "*Thread.sleep"); + } + + assertThat(activeWait.getParentSpanId()).isEqualTo(compareSpan.getSpanId()); + assertThat(passiveWait.getParentSpanId()).isEqualTo(compareSpan.getSpanId()); assertThat(activeWait.getEndEpochNanos()).isLessThan(passiveWait.getEndEpochNanos()); }); diff --git a/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/TraceTestBase.java b/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/TraceTestBase.java index 70986e8c28..ae6813866b 100644 --- a/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/TraceTestBase.java +++ b/inspectit-ocelot-agent/src/system-test/java/rocks/inspectit/ocelot/instrumentation/tracing/TraceTestBase.java @@ -40,6 +40,15 @@ void assertTraceExported(Consumer> assertions) await().atMost(15, TimeUnit.SECONDS).untilAsserted(() -> { Map> traces = getExportedSpans().stream() .collect(Collectors.groupingBy(s -> s.getSpanContext().getTraceId(), Collectors.toList())); + // Print all traces for debugging + // traces.forEach((traceId, spans) -> { + // System.out.println("----------------- Trace Start ---------------"); + // System.out.println("Trace " + traceId); + // spans.forEach(span -> System.out.println(" " + span.getName())); + // spans.forEach(span -> System.out.println(" Span ID: " + span.getSpanId())); + // spans.forEach(span -> System.out.println("Parent Span ID: " + span.getParentSpanId())); + // System.out.println("----------------- Trace End -----------------"); + // }); assertThat(traces.values()).anySatisfy(assertions); assertThat(traces.values()).filteredOnAssertions(assertions).hasSize(1); }); diff --git a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/config/spring/SpringConfiguration.java b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/config/spring/SpringConfiguration.java index 4476a30fe6..7296a43aeb 100644 --- a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/config/spring/SpringConfiguration.java +++ b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/config/spring/SpringConfiguration.java @@ -19,7 +19,7 @@ public class SpringConfiguration { private ScheduledExecutorService activeExecutor = null; - @Bean + @Bean(destroyMethod = "shutdown") public ScheduledExecutorService getScheduledExecutorService(@Value("#{#inspectit.threadPoolSize}") int poolSize) { AtomicInteger threadCount = new AtomicInteger(); activeExecutor = Executors.newScheduledThreadPool(poolSize, (runnable) -> { diff --git a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/autotracing/StackTrace.java b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/autotracing/StackTrace.java index a98d0c4b0b..d79283db16 100644 --- a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/autotracing/StackTrace.java +++ b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/autotracing/StackTrace.java @@ -104,7 +104,7 @@ private boolean isHiddenTop(StackTraceElement element) { private boolean isLambda(StackTraceElement element) { String className = element.getClassName(); - return className.contains("$Lambda$"); + return className.contains("$Lambda"); } public StackTraceElement get(int indexFromRoot) { diff --git a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/config/InstrumentationConfigurationResolver.java b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/config/InstrumentationConfigurationResolver.java index 69937b290b..b55f92bc13 100644 --- a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/config/InstrumentationConfigurationResolver.java +++ b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/config/InstrumentationConfigurationResolver.java @@ -277,7 +277,7 @@ boolean isIgnoredClass(TypeDescriptionWithClassLoader typeWithLoader, Instrument return true; } - if (config.getSource().isExcludeLambdas() && type.getName().contains("$$Lambda$")) { + if (config.getSource().isExcludeLambdas() && type.getName().contains("$$Lambda")) { return true; } return isClassFromIgnoredPackage(config.getSource(), type.getName(), loader); diff --git a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ExecutorContextPropagationSensor.java b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ExecutorContextPropagationSensor.java index 51eff6d39b..70e5429166 100644 --- a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ExecutorContextPropagationSensor.java +++ b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ExecutorContextPropagationSensor.java @@ -52,7 +52,7 @@ private static class ExecutorAdvice { @Advice.OnMethodEnter public static void enter(@Advice.Argument(value = 0, readOnly = false) Runnable runnable) { if (Instances.contextManager.enterCorrelation()) { - if (runnable.getClass().getName().contains("$$Lambda$")) { + if (runnable.getClass().getName().contains("$$Lambda")) { // order is important because the log-correlator requires the restored context, thus, have to be // called after the context wrapper (needs to be nested by it) runnable = Instances.logTraceCorrelator.wrap(runnable); diff --git a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ScheduledExecutorContextPropagationSensor.java b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ScheduledExecutorContextPropagationSensor.java index 0ca46621e1..c5693d2902 100644 --- a/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ScheduledExecutorContextPropagationSensor.java +++ b/inspectit-ocelot-core/src/main/java/rocks/inspectit/ocelot/core/instrumentation/special/ScheduledExecutorContextPropagationSensor.java @@ -53,7 +53,7 @@ public class ScheduledExecutorContextPropagationSensor implements SpecialSensor /** * Identifier for lambda classes. */ - private static final String LAMBDA = "$$Lambda$"; + private static final String LAMBDA = "$$Lambda"; private static final ElementMatcher CLASSES_MATCHER = isSubTypeOf(ScheduledExecutorService.class); diff --git a/settings.gradle b/settings.gradle index 7647b0fdf0..408947dbee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,4 +22,4 @@ if(JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { } } } -} +} \ No newline at end of file