diff --git a/docs/supported-libraries.md b/docs/supported-libraries.md index 5e080187caf3..9096e2ba9901 100644 --- a/docs/supported-libraries.md +++ b/docs/supported-libraries.md @@ -145,6 +145,7 @@ These are the supported libraries and frameworks: | [Vert.x SQL Client](https://github.com/eclipse-vertx/vertx-sql-client/) | 4.0+ | N/A | [Database Client Spans] | | [Vert.x Web](https://vertx.io/docs/vertx-web/java/) | 3.0+ | N/A | Provides `http.route` [2] | | [Vibur DBCP](https://www.vibur.org/) | 11.0+ | [opentelemetry-vibur-dbcp-11.0](../instrumentation/vibur-dbcp-11.0/library) | [Database Pool Metrics] | +| [XXL-JOB](https://www.xuxueli.com/xxl-job/en/) | 1.9.2+ | N/A | none | | [ZIO](https://zio.dev/) | 2.0+ | N/A | Context propagation | **[1]** Standalone library instrumentation refers to instrumentation that can be used without the Java agent. diff --git a/instrumentation/xxl-job/README.md b/instrumentation/xxl-job/README.md new file mode 100644 index 000000000000..66f867b76fb8 --- /dev/null +++ b/instrumentation/xxl-job/README.md @@ -0,0 +1,5 @@ +# Settings for the XXL-JOB instrumentation + +| System property | Type | Default | Description | +|-------------------------------------------------------------|---------|---------|-----------------------------------------------------| +| `otel.instrumentation.xxl-job.experimental-span-attributes` | Boolean | `false` | Enable the capture of experimental span attributes. | diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/build.gradle.kts b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/build.gradle.kts new file mode 100644 index 000000000000..57cbcd6c422f --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("com.xuxueli") + module.set("xxl-job-core") + versions.set("[1.9.2, 2.1.2)") + assertInverse.set(true) + } +} + +dependencies { + library("com.xuxueli:xxl-job-core:1.9.2") { + exclude("org.codehaus.groovy", "groovy") + } + implementation(project(":instrumentation:xxl-job:xxl-job-common:javaagent")) + + testInstrumentation(project(":instrumentation:xxl-job:xxl-job-2.1.2:javaagent")) + testInstrumentation(project(":instrumentation:xxl-job:xxl-job-2.3.0:javaagent")) + + // It needs the javax.annotation-api in xxl-job-core 1.9.2. + testImplementation("javax.annotation:javax.annotation-api:1.3.2") + testImplementation(project(":instrumentation:xxl-job:xxl-job-common:testing")) + latestDepTestLibrary("com.xuxueli:xxl-job-core:2.1.1") { + exclude("org.codehaus.groovy", "groovy") + } +} + +tasks.withType().configureEach { + // required on jdk17 + jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") + jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") + jvmArgs("-Dotel.instrumentation.xxl-job.experimental-span-attributes=true") +} diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/GlueJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/GlueJobHandlerInstrumentation.java new file mode 100644 index 000000000000..5c737335ebcb --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/GlueJobHandlerInstrumentation.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.xxl.job.core.handler.IJobHandler; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class GlueJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.GlueJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesArguments(String.class)), + GlueJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("jobHandler") IJobHandler handler, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createGlueJobRequest(handler); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/ScriptJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/ScriptJobHandlerInstrumentation.java new file mode 100644 index 000000000000..7e947a24ffec --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/ScriptJobHandlerInstrumentation.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class ScriptJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.ScriptJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesArguments(1).and(takesArgument(0, String.class))), + ScriptJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("glueType") GlueTypeEnum glueType, + @Advice.FieldValue("jobId") int jobId, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createScriptJobRequest(glueType, jobId); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/SimpleJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/SimpleJobHandlerInstrumentation.java new file mode 100644 index 000000000000..5adf7a4f7f35 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/SimpleJobHandlerInstrumentation.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_GLUE_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_METHOD_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_SCRIPT_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.xxl.job.core.handler.IJobHandler; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class SimpleJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return hasSuperType(named("com.xxl.job.core.handler.IJobHandler")) + .and(not(namedOneOf(XXL_GLUE_JOB_HANDLER, XXL_SCRIPT_JOB_HANDLER, XXL_METHOD_JOB_HANDLER))); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesArguments(1).and(takesArgument(0, String.class))), + SimpleJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + public static class ScheduleAdvice { + + @SuppressWarnings("unused") + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.This IJobHandler handler, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createSimpleJobRequest(handler); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @SuppressWarnings("unused") + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobInstrumentationModule.java b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobInstrumentationModule.java new file mode 100644 index 000000000000..fd72669efb73 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobInstrumentationModule.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Arrays.asList; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class XxlJobInstrumentationModule extends InstrumentationModule { + + public XxlJobInstrumentationModule() { + super("xxl-job", "xxl-job-1.9.2"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + // Class was added in 2.1.2 + return not(hasClassesNamed("com.xxl.job.core.handler.impl.MethodJobHandler")); + } + + @Override + public List typeInstrumentations() { + return asList( + new ScriptJobHandlerInstrumentation(), + new SimpleJobHandlerInstrumentation(), + new GlueJobHandlerInstrumentation()); + } +} diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobSingletons.java b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobSingletons.java new file mode 100644 index 000000000000..2488b109e438 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobSingletons.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobHelper; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobInstrumenterFactory; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; + +public final class XxlJobSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.xxl-job-1.9.2"; + private static final Instrumenter INSTRUMENTER = + XxlJobInstrumenterFactory.create(INSTRUMENTATION_NAME); + private static final XxlJobHelper HELPER = + XxlJobHelper.create( + INSTRUMENTER, + object -> { + if (object != null && (object instanceof ReturnT)) { + ReturnT result = (ReturnT) object; + return result.getCode() == ReturnT.FAIL_CODE; + } + return false; + }); + + public static XxlJobHelper helper() { + return HELPER; + } + + @SuppressWarnings({"Unused", "ReturnValueIgnored"}) + private static void limitSupportedVersions() { + // GLUE_POWERSHELL was added in 1.9.2. Using this constant here ensures that muzzle will disable + // this instrumentation on earlier versions where this constant does not exist. + GlueTypeEnum.GLUE_POWERSHELL.name(); + } + + private XxlJobSingletons() {} +} diff --git a/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobTest.java b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobTest.java new file mode 100644 index 000000000000..c09b0afb5b9b --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-1.9.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v1_9_2/XxlJobTest.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v1_9_2; + +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.DEFAULT_GLUE_UPDATE_TIME; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.GLUE_JOB_GROOVY_SOURCE_OLD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.GLUE_JOB_SHELL_SCRIPT; + +import com.xxl.job.core.glue.GlueFactory; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.impl.GlueJobHandler; +import com.xxl.job.core.handler.impl.ScriptJobHandler; +import io.opentelemetry.instrumentation.xxljob.AbstractXxlJobTest; +import io.opentelemetry.instrumentation.xxljob.CustomizedFailedHandler; +import io.opentelemetry.instrumentation.xxljob.SimpleCustomizedHandler; + +class XxlJobTest extends AbstractXxlJobTest { + + private static final IJobHandler GROOVY_HANDLER; + + static { + try { + GROOVY_HANDLER = GlueFactory.getInstance().loadNewInstance(GLUE_JOB_GROOVY_SOURCE_OLD); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static final GlueJobHandler GLUE_JOB_HANDLER = + new GlueJobHandler(GROOVY_HANDLER, DEFAULT_GLUE_UPDATE_TIME); + + private static final ScriptJobHandler SCRIPT_JOB_HANDLER = + new ScriptJobHandler( + 2, DEFAULT_GLUE_UPDATE_TIME, GLUE_JOB_SHELL_SCRIPT, GlueTypeEnum.GLUE_SHELL); + + @Override + protected String getPackageName() { + return "io.opentelemetry.instrumentation.xxljob"; + } + + @Override + protected IJobHandler getGlueJobHandler() { + return GLUE_JOB_HANDLER; + } + + @Override + protected IJobHandler getScriptJobHandler() { + return SCRIPT_JOB_HANDLER; + } + + @Override + protected IJobHandler getCustomizeHandler() { + return new SimpleCustomizedHandler(); + } + + @Override + protected IJobHandler getCustomizeFailedHandler() { + return new CustomizedFailedHandler(); + } + + @Override + protected IJobHandler getMethodHandler() { + return null; + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/build.gradle.kts b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/build.gradle.kts new file mode 100644 index 000000000000..513d981448a0 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/build.gradle.kts @@ -0,0 +1,34 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("com.xuxueli") + module.set("xxl-job-core") + versions.set("[2.1.2,2.3.0)") + assertInverse.set(true) + } +} + +dependencies { + library("com.xuxueli:xxl-job-core:2.1.2") { + exclude("org.codehaus.groovy", "groovy") + } + implementation(project(":instrumentation:xxl-job:xxl-job-common:javaagent")) + + testInstrumentation(project(":instrumentation:xxl-job:xxl-job-1.9.2:javaagent")) + testInstrumentation(project(":instrumentation:xxl-job:xxl-job-2.3.0:javaagent")) + + testImplementation(project(":instrumentation:xxl-job:xxl-job-common:testing")) + latestDepTestLibrary("com.xuxueli:xxl-job-core:2.2.+") { + exclude("org.codehaus.groovy", "groovy") + } +} + +tasks.withType().configureEach { + // required on jdk17 + jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") + jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") + jvmArgs("-Dotel.instrumentation.xxl-job.experimental-span-attributes=true") +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/GlueJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/GlueJobHandlerInstrumentation.java new file mode 100644 index 000000000000..2e3ddaca3ce8 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/GlueJobHandlerInstrumentation.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.xxl.job.core.handler.IJobHandler; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class GlueJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.GlueJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()), + GlueJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("jobHandler") IJobHandler handler, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createGlueJobRequest(handler); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/MethodJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/MethodJobHandlerInstrumentation.java new file mode 100644 index 000000000000..021c3092682e --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/MethodJobHandlerInstrumentation.java @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import java.lang.reflect.Method; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class MethodJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.MethodJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()), + MethodJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("target") Object target, + @Advice.FieldValue("method") Method method, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createMethodJobRequest(target, method); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/ScriptJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/ScriptJobHandlerInstrumentation.java new file mode 100644 index 000000000000..8ab021d4e2df --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/ScriptJobHandlerInstrumentation.java @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class ScriptJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.ScriptJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()), + ScriptJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("glueType") GlueTypeEnum glueType, + @Advice.FieldValue("jobId") int jobId, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createScriptJobRequest(glueType, jobId); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/SimpleJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/SimpleJobHandlerInstrumentation.java new file mode 100644 index 000000000000..acd0cd6494c2 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/SimpleJobHandlerInstrumentation.java @@ -0,0 +1,74 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_GLUE_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_METHOD_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_SCRIPT_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import com.xxl.job.core.handler.IJobHandler; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class SimpleJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return hasSuperType(named("com.xxl.job.core.handler.IJobHandler")) + .and(not(namedOneOf(XXL_GLUE_JOB_HANDLER, XXL_SCRIPT_JOB_HANDLER, XXL_METHOD_JOB_HANDLER))); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()), + SimpleJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + public static class ScheduleAdvice { + + @SuppressWarnings("unused") + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.This IJobHandler handler, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createSimpleJobRequest(handler); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @SuppressWarnings("unused") + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(result, request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobInstrumentationModule.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobInstrumentationModule.java new file mode 100644 index 000000000000..f32251f71f3f --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobInstrumentationModule.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Arrays.asList; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class XxlJobInstrumentationModule extends InstrumentationModule { + + public XxlJobInstrumentationModule() { + super("xxl-job", "xxl-job-2.1.2"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed("com.xxl.job.core.handler.impl.MethodJobHandler") + // Class was added in 2.3.0 + .and(not(hasClassesNamed("com.xxl.job.core.context.XxlJobHelper"))); + } + + @Override + public List typeInstrumentations() { + return asList( + new MethodJobHandlerInstrumentation(), + new ScriptJobHandlerInstrumentation(), + new SimpleJobHandlerInstrumentation(), + new GlueJobHandlerInstrumentation()); + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobSingletons.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobSingletons.java new file mode 100644 index 000000000000..d88fa2733031 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobSingletons.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import com.xxl.job.core.biz.model.ReturnT; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobHelper; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobInstrumenterFactory; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; + +public final class XxlJobSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.xxl-job-2.1.2"; + private static final Instrumenter INSTRUMENTER = + XxlJobInstrumenterFactory.create(INSTRUMENTATION_NAME); + private static final XxlJobHelper HELPER = + XxlJobHelper.create( + INSTRUMENTER, + object -> { + if (object != null && (object instanceof ReturnT)) { + ReturnT result = (ReturnT) object; + return result.getCode() == ReturnT.FAIL_CODE; + } + return false; + }); + + public static XxlJobHelper helper() { + return HELPER; + } + + private XxlJobSingletons() {} +} diff --git a/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobTest.java b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobTest.java new file mode 100644 index 000000000000..27b91d2c2212 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.1.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_1_2/XxlJobTest.java @@ -0,0 +1,81 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_1_2; + +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.DEFAULT_GLUE_UPDATE_TIME; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.GLUE_JOB_GROOVY_SOURCE_OLD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.GLUE_JOB_SHELL_SCRIPT; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_DESTROY_METHOD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_INIT_METHOD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_METHOD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_OBJECT; + +import com.xxl.job.core.glue.GlueFactory; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.impl.GlueJobHandler; +import com.xxl.job.core.handler.impl.MethodJobHandler; +import com.xxl.job.core.handler.impl.ScriptJobHandler; +import io.opentelemetry.instrumentation.xxljob.AbstractXxlJobTest; +import io.opentelemetry.instrumentation.xxljob.CustomizedFailedHandler; +import io.opentelemetry.instrumentation.xxljob.SimpleCustomizedHandler; + +class XxlJobTest extends AbstractXxlJobTest { + + private static final MethodJobHandler METHOD_JOB_HANDLER = + new MethodJobHandler( + METHOD_JOB_HANDLER_OBJECT, + METHOD_JOB_HANDLER_METHOD, + METHOD_JOB_HANDLER_INIT_METHOD, + METHOD_JOB_HANDLER_DESTROY_METHOD); + + private static final IJobHandler GROOVY_HANDLER; + + static { + try { + GROOVY_HANDLER = GlueFactory.getInstance().loadNewInstance(GLUE_JOB_GROOVY_SOURCE_OLD); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static final GlueJobHandler GLUE_JOB_HANDLER = + new GlueJobHandler(GROOVY_HANDLER, DEFAULT_GLUE_UPDATE_TIME); + + private static final ScriptJobHandler SCRIPT_JOB_HANDLER = + new ScriptJobHandler( + 2, DEFAULT_GLUE_UPDATE_TIME, GLUE_JOB_SHELL_SCRIPT, GlueTypeEnum.GLUE_SHELL); + + @Override + protected String getPackageName() { + return "io.opentelemetry.instrumentation.xxljob"; + } + + @Override + protected IJobHandler getGlueJobHandler() { + return GLUE_JOB_HANDLER; + } + + @Override + protected IJobHandler getScriptJobHandler() { + return SCRIPT_JOB_HANDLER; + } + + @Override + protected IJobHandler getCustomizeHandler() { + return new SimpleCustomizedHandler(); + } + + @Override + protected IJobHandler getCustomizeFailedHandler() { + return new CustomizedFailedHandler(); + } + + @Override + protected IJobHandler getMethodHandler() { + return METHOD_JOB_HANDLER; + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/build.gradle.kts b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/build.gradle.kts new file mode 100644 index 000000000000..56e5c7a630bb --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/build.gradle.kts @@ -0,0 +1,31 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("com.xuxueli") + module.set("xxl-job-core") + versions.set("[2.3.0,)") + assertInverse.set(true) + } +} + +dependencies { + library("com.xuxueli:xxl-job-core:2.3.0") { + exclude("org.codehaus.groovy", "groovy") + } + implementation(project(":instrumentation:xxl-job:xxl-job-common:javaagent")) + + testInstrumentation(project(":instrumentation:xxl-job:xxl-job-2.1.2:javaagent")) + testInstrumentation(project(":instrumentation:xxl-job:xxl-job-2.3.0:javaagent")) + + testImplementation(project(":instrumentation:xxl-job:xxl-job-common:testing")) +} + +tasks.withType().configureEach { + // required on jdk17 + jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") + jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") + jvmArgs("-Dotel.instrumentation.xxl-job.experimental-span-attributes=true") +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/GlueJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/GlueJobHandlerInstrumentation.java new file mode 100644 index 000000000000..7e67cd14e066 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/GlueJobHandlerInstrumentation.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; + +import com.xxl.job.core.handler.IJobHandler; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class GlueJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.GlueJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesNoArguments()), + GlueJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("jobHandler") IJobHandler handler, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createGlueJobRequest(handler); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/MethodJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/MethodJobHandlerInstrumentation.java new file mode 100644 index 000000000000..04d39252acaa --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/MethodJobHandlerInstrumentation.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import java.lang.reflect.Method; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class MethodJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.MethodJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesNoArguments()), + MethodJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("target") Object target, + @Advice.FieldValue("method") Method method, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createMethodJobRequest(target, method); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/ScriptJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/ScriptJobHandlerInstrumentation.java new file mode 100644 index 000000000000..bf5fa3fa793a --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/ScriptJobHandlerInstrumentation.java @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; + +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class ScriptJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.xxl.job.core.handler.impl.ScriptJobHandler"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesNoArguments()), + ScriptJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + @SuppressWarnings("unused") + public static class ScheduleAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.FieldValue("glueType") GlueTypeEnum glueType, + @Advice.FieldValue("jobId") int jobId, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createScriptJobRequest(glueType, jobId); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/SimpleJobHandlerInstrumentation.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/SimpleJobHandlerInstrumentation.java new file mode 100644 index 000000000000..3e2b6a0ae882 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/SimpleJobHandlerInstrumentation.java @@ -0,0 +1,73 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_GLUE_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_METHOD_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobConstants.XXL_SCRIPT_JOB_HANDLER; +import static io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0.XxlJobSingletons.helper; +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; + +import com.xxl.job.core.handler.IJobHandler; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class SimpleJobHandlerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return hasSuperType(named("com.xxl.job.core.handler.IJobHandler")) + .and(not(namedOneOf(XXL_GLUE_JOB_HANDLER, XXL_SCRIPT_JOB_HANDLER, XXL_METHOD_JOB_HANDLER))); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("execute").and(isPublic()).and(takesNoArguments()), + SimpleJobHandlerInstrumentation.class.getName() + "$ScheduleAdvice"); + } + + public static class ScheduleAdvice { + + @SuppressWarnings("unused") + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onSchedule( + @Advice.This IJobHandler handler, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + request = XxlJobProcessRequest.createSimpleJobRequest(handler); + context = helper().startSpan(parentContext, request); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @SuppressWarnings("unused") + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRequest") XxlJobProcessRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + helper().stopSpan(request, throwable, scope, context); + } + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobInstrumentationModule.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobInstrumentationModule.java new file mode 100644 index 000000000000..3b17798a47ea --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobInstrumentationModule.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Arrays.asList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class XxlJobInstrumentationModule extends InstrumentationModule { + + public XxlJobInstrumentationModule() { + super("xxl-job", "xxl-job-2.3.0"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed( + "com.xxl.job.core.handler.impl.MethodJobHandler", "com.xxl.job.core.context.XxlJobHelper"); + } + + @Override + public List typeInstrumentations() { + return asList( + new MethodJobHandlerInstrumentation(), + new ScriptJobHandlerInstrumentation(), + new SimpleJobHandlerInstrumentation(), + new GlueJobHandlerInstrumentation()); + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobSingletons.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobSingletons.java new file mode 100644 index 000000000000..884e0cd4f37d --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobSingletons.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static com.xxl.job.core.context.XxlJobContext.HANDLE_COCE_SUCCESS; + +import com.xxl.job.core.context.XxlJobContext; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobHelper; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobInstrumenterFactory; +import io.opentelemetry.javaagent.instrumentation.xxljob.common.XxlJobProcessRequest; + +public final class XxlJobSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.xxl-job-2.3.0"; + private static final Instrumenter INSTRUMENTER = + XxlJobInstrumenterFactory.create(INSTRUMENTATION_NAME); + private static final XxlJobHelper HELPER = + XxlJobHelper.create( + INSTRUMENTER, + unused -> { + // From 2.3.0, XxlJobContext is used to store the result of the job execution. + XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext(); + if (xxlJobContext != null) { + int handleCode = xxlJobContext.getHandleCode(); + return handleCode != HANDLE_COCE_SUCCESS; + } + return false; + }); + + public static XxlJobHelper helper() { + return HELPER; + } + + private XxlJobSingletons() {} +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/CustomizedFailedHandler.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/CustomizedFailedHandler.java new file mode 100644 index 000000000000..55d083d176e8 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/CustomizedFailedHandler.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import com.xxl.job.core.context.XxlJobHelper; +import com.xxl.job.core.handler.IJobHandler; + +class CustomizedFailedHandler extends IJobHandler { + + @Override + public void execute() throws Exception { + XxlJobHelper.handleFail(); + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/SimpleCustomizedHandler.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/SimpleCustomizedHandler.java new file mode 100644 index 000000000000..861d5c23e9e1 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/SimpleCustomizedHandler.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import com.xxl.job.core.context.XxlJobHelper; +import com.xxl.job.core.handler.IJobHandler; + +class SimpleCustomizedHandler extends IJobHandler { + + @Override + public void execute() throws Exception { + XxlJobHelper.handleSuccess(); + } +} diff --git a/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobTest.java b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobTest.java new file mode 100644 index 000000000000..ec4c3b0fb4d4 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-2.3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/xxljob/v2_3_0/XxlJobTest.java @@ -0,0 +1,79 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0; + +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.DEFAULT_GLUE_UPDATE_TIME; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.GLUE_JOB_GROOVY_SOURCE; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.GLUE_JOB_SHELL_SCRIPT; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_DESTROY_METHOD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_INIT_METHOD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_METHOD; +import static io.opentelemetry.instrumentation.xxljob.XxlJobTestingConstants.METHOD_JOB_HANDLER_OBJECT; + +import com.xxl.job.core.glue.GlueFactory; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.impl.GlueJobHandler; +import com.xxl.job.core.handler.impl.MethodJobHandler; +import com.xxl.job.core.handler.impl.ScriptJobHandler; +import io.opentelemetry.instrumentation.xxljob.AbstractXxlJobTest; + +class XxlJobTest extends AbstractXxlJobTest { + + private static final MethodJobHandler METHOD_JOB_HANDLER = + new MethodJobHandler( + METHOD_JOB_HANDLER_OBJECT, + METHOD_JOB_HANDLER_METHOD, + METHOD_JOB_HANDLER_INIT_METHOD, + METHOD_JOB_HANDLER_DESTROY_METHOD); + + private static final IJobHandler GROOVY_HANDLER; + + static { + try { + GROOVY_HANDLER = GlueFactory.getInstance().loadNewInstance(GLUE_JOB_GROOVY_SOURCE); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static final GlueJobHandler GLUE_JOB_HANDLER = + new GlueJobHandler(GROOVY_HANDLER, DEFAULT_GLUE_UPDATE_TIME); + + private static final ScriptJobHandler SCRIPT_JOB_HANDLER = + new ScriptJobHandler( + 2, DEFAULT_GLUE_UPDATE_TIME, GLUE_JOB_SHELL_SCRIPT, GlueTypeEnum.GLUE_SHELL); + + @Override + protected String getPackageName() { + return "io.opentelemetry.javaagent.instrumentation.xxljob.v2_3_0"; + } + + @Override + protected IJobHandler getGlueJobHandler() { + return GLUE_JOB_HANDLER; + } + + @Override + protected IJobHandler getScriptJobHandler() { + return SCRIPT_JOB_HANDLER; + } + + @Override + protected IJobHandler getCustomizeHandler() { + return new SimpleCustomizedHandler(); + } + + @Override + protected IJobHandler getCustomizeFailedHandler() { + return new CustomizedFailedHandler(); + } + + @Override + protected IJobHandler getMethodHandler() { + return METHOD_JOB_HANDLER; + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/build.gradle.kts b/instrumentation/xxl-job/xxl-job-common/javaagent/build.gradle.kts new file mode 100644 index 000000000000..ebc87b1bd078 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/build.gradle.kts @@ -0,0 +1,6 @@ +plugins { + id("otel.javaagent-instrumentation") +} +dependencies { + compileOnly("com.xuxueli:xxl-job-core:2.1.2") +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobCodeAttributesGetter.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobCodeAttributesGetter.java new file mode 100644 index 000000000000..1db15ab916be --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobCodeAttributesGetter.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; +import javax.annotation.Nullable; + +class XxlJobCodeAttributesGetter implements CodeAttributesGetter { + + @Nullable + @Override + public Class getCodeClass(XxlJobProcessRequest xxlJobProcessRequest) { + GlueTypeEnum glueType = xxlJobProcessRequest.getGlueType(); + if (!glueType.isScript()) { + return xxlJobProcessRequest.getDeclaringClass(); + } + return null; + } + + @Nullable + @Override + public String getMethodName(XxlJobProcessRequest xxlJobProcessRequest) { + GlueTypeEnum glueType = xxlJobProcessRequest.getGlueType(); + if (!glueType.isScript()) { + return xxlJobProcessRequest.getMethodName(); + } + return null; + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobConstants.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobConstants.java new file mode 100644 index 000000000000..f31ac773303d --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobConstants.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +public final class XxlJobConstants { + + private XxlJobConstants() {} + + public static final String XXL_GLUE_JOB_HANDLER = "com.xxl.job.core.handler.impl.GlueJobHandler"; + public static final String XXL_SCRIPT_JOB_HANDLER = + "com.xxl.job.core.handler.impl.ScriptJobHandler"; + public static final String XXL_METHOD_JOB_HANDLER = + "com.xxl.job.core.handler.impl.MethodJobHandler"; +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobExperimentalAttributeExtractor.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobExperimentalAttributeExtractor.java new file mode 100644 index 000000000000..a9bceb6a2b43 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobExperimentalAttributeExtractor.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import javax.annotation.Nullable; + +class XxlJobExperimentalAttributeExtractor + implements AttributesExtractor { + + private static final AttributeKey XXL_JOB_GLUE_TYPE = + AttributeKey.stringKey("scheduling.xxl-job.glue.type"); + + private static final AttributeKey XXL_JOB_JOB_ID = + AttributeKey.longKey("scheduling.xxl-job.job.id"); + + @Override + public void onStart( + AttributesBuilder attributes, + Context parentContext, + XxlJobProcessRequest xxlJobProcessRequest) { + GlueTypeEnum glueType = xxlJobProcessRequest.getGlueType(); + attributes.put(XXL_JOB_GLUE_TYPE, glueType.getDesc()); + // store jobId in experimental attribute for script job. + if (glueType.isScript()) { + attributes.put(XXL_JOB_JOB_ID, xxlJobProcessRequest.getJobId()); + } + } + + @Override + public void onEnd( + AttributesBuilder attributes, + Context context, + XxlJobProcessRequest xxlJobProcessRequest, + @Nullable Void unused, + @Nullable Throwable error) {} +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobHelper.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobHelper.java new file mode 100644 index 000000000000..3b90e1d3ad44 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobHelper.java @@ -0,0 +1,57 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import java.util.function.Predicate; + +public final class XxlJobHelper { + private final Instrumenter instrumenter; + private final Predicate failedStatusPredicate; + + private XxlJobHelper( + Instrumenter instrumenter, + Predicate failedStatusPredicate) { + this.instrumenter = instrumenter; + this.failedStatusPredicate = failedStatusPredicate; + } + + public static XxlJobHelper create( + Instrumenter instrumenter, + Predicate failedStatusPredicate) { + return new XxlJobHelper(instrumenter, failedStatusPredicate); + } + + public Context startSpan(Context parentContext, XxlJobProcessRequest request) { + if (!instrumenter.shouldStart(parentContext, request)) { + return null; + } + return instrumenter.start(parentContext, request); + } + + public void stopSpan( + Object result, + XxlJobProcessRequest request, + Throwable throwable, + Scope scope, + Context context) { + if (scope == null) { + return; + } + if (failedStatusPredicate.test(result)) { + request.setFailed(); + } + scope.close(); + instrumenter.end(context, request, null, throwable); + } + + public void stopSpan( + XxlJobProcessRequest request, Throwable throwable, Scope scope, Context context) { + stopSpan(null, request, throwable, scope, context); + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobInstrumenterFactory.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobInstrumenterFactory.java new file mode 100644 index 000000000000..4a5f713808e2 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobInstrumenterFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; +import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig; + +public final class XxlJobInstrumenterFactory { + + private static final boolean CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES = + InstrumentationConfig.get() + .getBoolean("otel.instrumentation.xxl-job.experimental-span-attributes", false); + + public static Instrumenter create(String instrumentationName) { + XxlJobCodeAttributesGetter codeAttributesGetter = new XxlJobCodeAttributesGetter(); + XxlJobSpanNameExtractor spanNameExtractor = new XxlJobSpanNameExtractor(codeAttributesGetter); + InstrumenterBuilder builder = + Instrumenter.builder( + GlobalOpenTelemetry.get(), instrumentationName, spanNameExtractor) + .addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter)) + .setSpanStatusExtractor( + (spanStatusBuilder, xxlJobProcessRequest, response, error) -> { + if (error != null || xxlJobProcessRequest.isFailed()) { + spanStatusBuilder.setStatus(StatusCode.ERROR); + } + }); + if (CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES) { + builder.addAttributesExtractor( + AttributesExtractor.constant(AttributeKey.stringKey("job.system"), "xxl-job")); + builder.addAttributesExtractor(new XxlJobExperimentalAttributeExtractor()); + } + return builder.buildInstrumenter(); + } + + private XxlJobInstrumenterFactory() {} +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobProcessRequest.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobProcessRequest.java new file mode 100644 index 000000000000..2bd2f62c661c --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobProcessRequest.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.handler.IJobHandler; +import java.lang.reflect.Method; + +public final class XxlJobProcessRequest { + + private String methodName; + private int jobId; + private Class declaringClass; + private boolean failed; + private final GlueTypeEnum glueType; + + private XxlJobProcessRequest(GlueTypeEnum glueType) { + this.glueType = glueType; + } + + public static XxlJobProcessRequest createRequestForMethod( + GlueTypeEnum glueType, Class declaringClass, String methodName) { + XxlJobProcessRequest request = new XxlJobProcessRequest(glueType); + request.declaringClass = declaringClass; + request.methodName = methodName; + + return request; + } + + public static XxlJobProcessRequest createGlueJobRequest(IJobHandler handler) { + return createRequestForMethod(GlueTypeEnum.GLUE_GROOVY, handler.getClass(), "execute"); + } + + public static XxlJobProcessRequest createScriptJobRequest(GlueTypeEnum glueType, int jobId) { + XxlJobProcessRequest request = new XxlJobProcessRequest(glueType); + request.jobId = jobId; + + return request; + } + + public static XxlJobProcessRequest createSimpleJobRequest(IJobHandler handler) { + return createRequestForMethod(GlueTypeEnum.BEAN, handler.getClass(), "execute"); + } + + public static XxlJobProcessRequest createMethodJobRequest(Object target, Method method) { + return createRequestForMethod( + GlueTypeEnum.BEAN, target.getClass(), method != null ? method.getName() : null); + } + + public void setFailed() { + failed = true; + } + + public boolean isFailed() { + return failed; + } + + public String getMethodName() { + return methodName; + } + + public int getJobId() { + return jobId; + } + + public Class getDeclaringClass() { + return declaringClass; + } + + public GlueTypeEnum getGlueType() { + return glueType; + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobSpanNameExtractor.java b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobSpanNameExtractor.java new file mode 100644 index 000000000000..4c1e053feb00 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/xxljob/common/XxlJobSpanNameExtractor.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.xxljob.common; + +import com.xxl.job.core.glue.GlueTypeEnum; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; + +class XxlJobSpanNameExtractor implements SpanNameExtractor { + private final SpanNameExtractor codeSpanNameExtractor; + + XxlJobSpanNameExtractor(CodeAttributesGetter getter) { + codeSpanNameExtractor = CodeSpanNameExtractor.create(getter); + } + + @Override + public String extract(XxlJobProcessRequest request) { + GlueTypeEnum glueType = request.getGlueType(); + if (glueType.isScript()) { + // TODO: need to discuss a better span name for script job in the future. + // for detail can refer to + // https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/10421#discussion_r1511532584 + return glueType.getDesc(); + } + return codeSpanNameExtractor.extract(request); + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/testing/build.gradle.kts b/instrumentation/xxl-job/xxl-job-common/testing/build.gradle.kts new file mode 100644 index 000000000000..0eb69a252ddf --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/testing/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("otel.java-conventions") +} + +dependencies { + implementation(project(":testing-common")) + + compileOnly("com.xuxueli:xxl-job-core:2.1.2") { + exclude("org.codehaus.groovy", "groovy") + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/AbstractXxlJobTest.java b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/AbstractXxlJobTest.java new file mode 100644 index 000000000000..c8f7766e58e2 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/AbstractXxlJobTest.java @@ -0,0 +1,170 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.xxljob; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static java.util.Arrays.asList; + +import com.xxl.job.core.biz.model.TriggerParam; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.log.XxlJobFileAppender; +import com.xxl.job.core.thread.JobThread; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import io.opentelemetry.sdk.trace.data.StatusData; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public abstract class AbstractXxlJobTest { + + @RegisterExtension + private static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @BeforeAll + static void setUp() { + XxlJobFileAppender.initLogPath("build/xxljob/log"); + } + + @Test + void testGlueJob() { + JobThread jobThread = new JobThread(1, getGlueJobHandler()); + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setExecutorTimeout(0); + jobThread.pushTriggerQueue(triggerParam); + jobThread.start(); + checkXxlJob( + "CustomizedGroovyHandler.execute", + StatusData.unset(), + GlueTypeEnum.GLUE_GROOVY, + "CustomizedGroovyHandler", + "execute"); + jobThread.toStop("Test finish"); + } + + @Test + void testScriptJob() { + JobThread jobThread = new JobThread(2, getScriptJobHandler()); + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setExecutorParams(""); + triggerParam.setExecutorTimeout(0); + jobThread.pushTriggerQueue(triggerParam); + jobThread.start(); + checkXxlJobWithoutCodeAttributes("GLUE(Shell)", StatusData.unset(), GlueTypeEnum.GLUE_SHELL, 2); + jobThread.toStop("Test finish"); + } + + @Test + void testSimpleJob() { + JobThread jobThread = new JobThread(3, getCustomizeHandler()); + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setExecutorTimeout(0); + jobThread.pushTriggerQueue(triggerParam); + jobThread.start(); + checkXxlJob( + "SimpleCustomizedHandler.execute", + StatusData.unset(), + GlueTypeEnum.BEAN, + getPackageName() + ".SimpleCustomizedHandler", + "execute"); + jobThread.toStop("Test finish"); + } + + @Test + public void testMethodJob() { + // method handle is null if test is not supported by tested version of the library + Assumptions.assumeTrue(getMethodHandler() != null); + + JobThread jobThread = new JobThread(4, getMethodHandler()); + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setExecutorTimeout(0); + jobThread.pushTriggerQueue(triggerParam); + jobThread.start(); + checkXxlJob( + "ReflectObject.echo", + StatusData.unset(), + GlueTypeEnum.BEAN, + "io.opentelemetry.instrumentation.xxljob.ReflectiveMethodsFactory$ReflectObject", + "echo"); + jobThread.toStop("Test finish"); + } + + @Test + void testFailedJob() { + JobThread jobThread = new JobThread(5, getCustomizeFailedHandler()); + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setExecutorTimeout(0); + jobThread.pushTriggerQueue(triggerParam); + jobThread.start(); + checkXxlJob( + "CustomizedFailedHandler.execute", + StatusData.error(), + GlueTypeEnum.BEAN, + getPackageName() + ".CustomizedFailedHandler", + "execute"); + jobThread.toStop("Test finish"); + } + + protected abstract IJobHandler getGlueJobHandler(); + + protected abstract IJobHandler getScriptJobHandler(); + + protected abstract IJobHandler getCustomizeHandler(); + + protected abstract IJobHandler getCustomizeFailedHandler(); + + protected abstract IJobHandler getMethodHandler(); + + protected abstract String getPackageName(); + + private static void checkXxlJob( + String spanName, StatusData statusData, List assertions) { + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasKind(SpanKind.INTERNAL) + .hasName(spanName) + .hasStatus(statusData) + .hasAttributesSatisfyingExactly(assertions))); + } + + private static void checkXxlJob( + String spanName, + StatusData statusData, + GlueTypeEnum glueType, + String codeNamespace, + String codeFunction) { + List attributeAssertions = new ArrayList<>(); + attributeAssertions.addAll(attributeAssertions(glueType)); + attributeAssertions.add(equalTo(AttributeKey.stringKey("code.namespace"), codeNamespace)); + attributeAssertions.add(equalTo(AttributeKey.stringKey("code.function"), codeFunction)); + + checkXxlJob(spanName, statusData, attributeAssertions); + } + + private static void checkXxlJobWithoutCodeAttributes( + String spanName, StatusData statusData, GlueTypeEnum glueType, int jobId) { + List attributeAssertions = new ArrayList<>(); + attributeAssertions.addAll(attributeAssertions(glueType)); + attributeAssertions.add(equalTo(AttributeKey.longKey("scheduling.xxl-job.job.id"), jobId)); + + checkXxlJob(spanName, statusData, attributeAssertions); + } + + private static List attributeAssertions(GlueTypeEnum glueType) { + return asList( + equalTo(AttributeKey.stringKey("job.system"), "xxl-job"), + equalTo(AttributeKey.stringKey("scheduling.xxl-job.glue.type"), glueType.getDesc())); + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/CustomizedFailedHandler.java b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/CustomizedFailedHandler.java new file mode 100644 index 000000000000..a4573ecf69a1 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/CustomizedFailedHandler.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.xxljob; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; + +public class CustomizedFailedHandler extends IJobHandler { + + @Override + public ReturnT execute(String s) throws Exception { + return FAIL; + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/ReflectiveMethodsFactory.java b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/ReflectiveMethodsFactory.java new file mode 100644 index 000000000000..fd772a4611d3 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/ReflectiveMethodsFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.xxljob; + +import com.xxl.job.core.biz.model.ReturnT; +import java.lang.reflect.Method; + +class ReflectiveMethodsFactory { + + private ReflectiveMethodsFactory() {} + + public static class ReflectObject { + + private ReflectObject() {} + + public void initMethod() {} + + public void destroyMethod() {} + + public ReturnT echo(String param) { + return new ReturnT<>("echo: " + param); + } + } + + private static final Object SINGLETON_OBJECT = new ReflectObject(); + + static Object getTarget() { + return SINGLETON_OBJECT; + } + + static Method getMethod() { + try { + return SINGLETON_OBJECT.getClass().getMethod("echo", String.class); + } catch (Throwable t) { + // Ignore + } + return null; + } + + static Method getInitMethod() { + try { + return SINGLETON_OBJECT.getClass().getMethod("initMethod"); + } catch (Throwable t) { + // Ignore + } + return null; + } + + static Method getDestroyMethod() { + try { + return SINGLETON_OBJECT.getClass().getMethod("destroyMethod"); + } catch (Throwable t) { + // Ignore + } + return null; + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/SimpleCustomizedHandler.java b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/SimpleCustomizedHandler.java new file mode 100644 index 000000000000..78df288fc852 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/SimpleCustomizedHandler.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.xxljob; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; + +public class SimpleCustomizedHandler extends IJobHandler { + + @Override + public ReturnT execute(String s) throws Exception { + return new ReturnT<>("Hello World"); + } +} diff --git a/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/XxlJobTestingConstants.java b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/XxlJobTestingConstants.java new file mode 100644 index 000000000000..81b4e8faca49 --- /dev/null +++ b/instrumentation/xxl-job/xxl-job-common/testing/src/main/java/io/opentelemetry/instrumentation/xxljob/XxlJobTestingConstants.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.xxljob; + +import java.lang.reflect.Method; + +public class XxlJobTestingConstants { + + private XxlJobTestingConstants() {} + + public static final String GLUE_JOB_SHELL_SCRIPT = "echo 'hello'"; + + public static final long DEFAULT_GLUE_UPDATE_TIME = System.currentTimeMillis(); + + public static final Object METHOD_JOB_HANDLER_OBJECT = ReflectiveMethodsFactory.getTarget(); + + public static final Method METHOD_JOB_HANDLER_METHOD = ReflectiveMethodsFactory.getMethod(); + + public static final Method METHOD_JOB_HANDLER_INIT_METHOD = + ReflectiveMethodsFactory.getInitMethod(); + + public static final Method METHOD_JOB_HANDLER_DESTROY_METHOD = + ReflectiveMethodsFactory.getDestroyMethod(); + + public static final String GLUE_JOB_GROOVY_SOURCE_OLD = + "import com.xxl.job.core.handler.IJobHandler\n" + + "import com.xxl.job.core.biz.model.ReturnT\n" + + "class CustomizedGroovyHandler extends IJobHandler {\n" + + " @Override\n" + + " public ReturnT execute(String s) throws Exception {\n" + + " return new ReturnT<>(\"Hello World\")\n" + + " }\n" + + "}\n"; + + public static final String GLUE_JOB_GROOVY_SOURCE = + "import com.xxl.job.core.handler.IJobHandler\n" + + "\n" + + "class CustomizedGroovyHandler extends IJobHandler {\n" + + " @Override\n" + + " void execute() throws Exception {\n" + + " }\n" + + "}\n"; +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 582c5cd41943..5537f26eb7e3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -576,6 +576,11 @@ include(":instrumentation:wicket-8.0:common-testing") include(":instrumentation:wicket-8.0:javaagent") include(":instrumentation:wicket-8.0:wicket8-testing") include(":instrumentation:wicket-8.0:wicket10-testing") +include(":instrumentation:xxl-job:xxl-job-1.9.2:javaagent") +include(":instrumentation:xxl-job:xxl-job-2.1.2:javaagent") +include(":instrumentation:xxl-job:xxl-job-2.3.0:javaagent") +include(":instrumentation:xxl-job:xxl-job-common:javaagent") +include(":instrumentation:xxl-job:xxl-job-common:testing") include(":instrumentation:zio:zio-2.0:javaagent") // benchmark