Instrumentation for redisson 3.17.2 (#6096)

* Instrumentation for redisson 3.17.2

* cross test instrumentation

* split at 3.17.0, assert inverse

* Apply suggestions from code review

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Lauri Tulmin 2022-05-26 19:44:34 +03:00 committed by GitHub
parent 24d3e1a5e8
commit efd40f8cdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 386 additions and 62 deletions

View File

@ -1,39 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
public final class RedissonSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.redisson-3.0";
private static final Instrumenter<RedissonRequest, Void> INSTRUMENTER;
static {
RedissonDbAttributesGetter dbAttributesGetter = new RedissonDbAttributesGetter();
RedissonNetAttributesGetter netAttributesGetter = new RedissonNetAttributesGetter();
INSTRUMENTER =
Instrumenter.<RedissonRequest, Void>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
DbClientSpanNameExtractor.create(dbAttributesGetter))
.addAttributesExtractor(DbClientAttributesExtractor.create(dbAttributesGetter))
.addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
.newInstrumenter(SpanKindExtractor.alwaysClient());
}
public static Instrumenter<RedissonRequest, Void> instrumenter() {
return INSTRUMENTER;
}
private RedissonSingletons() {}
}

View File

@ -6,18 +6,23 @@ muzzle {
pass {
group.set("org.redisson")
module.set("redisson")
versions.set("[3.0.0,3.17.2)")
versions.set("[3.0.0,3.17.0)")
}
}
dependencies {
library("org.redisson:redisson:3.0.0")
// TODO (trask) split out instrumentation into two modules and support 3.17.2+
latestDepTestLibrary("org.redisson:redisson:3.17.1")
implementation(project(":instrumentation:redisson:redisson-common:javaagent"))
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")
testInstrumentation(project(":instrumentation:redisson:redisson-3.17:javaagent"))
testImplementation(project(":instrumentation:redisson:redisson-common:testing"))
latestDepTestLibrary("org.redisson:redisson:3.16.+")
}
tasks.test {

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson;
package io.opentelemetry.javaagent.instrumentation.redisson.v3_0;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -12,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.redisson.CompletableFutureWrapper;
import java.util.concurrent.CompletableFuture;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;

View File

@ -3,10 +3,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson;
package io.opentelemetry.javaagent.instrumentation.redisson.v3_0;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.redisson.RedissonSingletons.instrumenter;
import static io.opentelemetry.javaagent.instrumentation.redisson.v3_0.RedissonSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -14,6 +14,9 @@ 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.redisson.EndOperationListener;
import io.opentelemetry.javaagent.instrumentation.redisson.PromiseWrapper;
import io.opentelemetry.javaagent.instrumentation.redisson.RedissonRequest;
import java.net.InetSocketAddress;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
@ -57,7 +60,7 @@ public class RedisConnectionInstrumentation implements TypeInstrumentation {
context = instrumenter().start(parentContext, request);
scope = context.makeCurrent();
promise.setEndOperationListener(new EndOperationListener<>(context, request));
promise.setEndOperationListener(new EndOperationListener<>(instrumenter(), context, request));
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)

View File

@ -3,14 +3,17 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson;
package io.opentelemetry.javaagent.instrumentation.redisson.v3_0;
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 RedissonInstrumentationModule extends InstrumentationModule {
@ -19,6 +22,11 @@ public class RedissonInstrumentationModule extends InstrumentationModule {
super("redisson", "redisson-3.0");
}
@Override
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
return not(hasClassesNamed("org.redisson.api.RFunction"));
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new RedisConnectionInstrumentation(), new RedisCommandDataInstrumentation());

View File

@ -3,10 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson;
package io.opentelemetry.javaagent.instrumentation.redisson.v3_0;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.redisson.EndOperationListener;
import io.opentelemetry.javaagent.instrumentation.redisson.PromiseWrapper;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;

View File

@ -0,0 +1,23 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson.v3_0;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.redisson.RedissonInstrumenterFactory;
import io.opentelemetry.javaagent.instrumentation.redisson.RedissonRequest;
public final class RedissonSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.redisson-3.0";
private static final Instrumenter<RedissonRequest, Void> INSTRUMENTER =
RedissonInstrumenterFactory.createInstrumenter(INSTRUMENTATION_NAME);
public static Instrumenter<RedissonRequest, Void> instrumenter() {
return INSTRUMENTER;
}
private RedissonSingletons() {}
}

View File

@ -0,0 +1,7 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class RedissonAsyncClientTest extends AbstractRedissonAsyncClientTest {
}

View File

@ -0,0 +1,7 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class RedissonClientTest extends AbstractRedissonClientTest {
}

View File

@ -0,0 +1,30 @@
plugins {
id("otel.javaagent-instrumentation")
}
muzzle {
pass {
group.set("org.redisson")
module.set("redisson")
versions.set("[3.17.0,)")
assertInverse.set(true)
}
}
dependencies {
library("org.redisson:redisson:3.17.0")
implementation(project(":instrumentation:redisson:redisson-common:javaagent"))
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")
testInstrumentation(project(":instrumentation:redisson:redisson-3.0:javaagent"))
testImplementation(project(":instrumentation:redisson:redisson-common:testing"))
}
tasks.test {
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].getService())
}

View File

@ -0,0 +1,44 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson.v3_17;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.redisson.CompletableFutureWrapper;
import java.util.concurrent.CompletableFuture;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
public class RedisCommandDataInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return namedOneOf(
"org.redisson.client.protocol.CommandData", "org.redisson.client.protocol.CommandsData");
}
@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isConstructor().and(takesArgument(0, CompletableFuture.class)),
this.getClass().getName() + "$WrapCompletableFutureAdvice");
}
@SuppressWarnings("unused")
public static class WrapCompletableFutureAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.Argument(value = 0, readOnly = false) CompletableFuture<?> completableFuture) {
completableFuture = CompletableFutureWrapper.wrap(completableFuture);
}
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson.v3_17;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.redisson.v3_17.RedissonSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
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.redisson.EndOperationListener;
import io.opentelemetry.javaagent.instrumentation.redisson.PromiseWrapper;
import io.opentelemetry.javaagent.instrumentation.redisson.RedissonRequest;
import java.net.InetSocketAddress;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.redisson.client.RedisConnection;
public class RedisConnectionInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.redisson.client.RedisConnection");
}
@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod().and(named("send")), this.getClass().getName() + "$SendAdvice");
}
@SuppressWarnings("unused")
public static class SendAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.This RedisConnection connection,
@Advice.Argument(0) Object arg,
@Advice.Local("otelRequest") RedissonRequest request,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();
InetSocketAddress remoteAddress = (InetSocketAddress) connection.getChannel().remoteAddress();
request = RedissonRequest.create(remoteAddress, arg);
PromiseWrapper<?> promise = request.getPromiseWrapper();
if (promise == null) {
return;
}
if (!instrumenter().shouldStart(parentContext, request)) {
return;
}
context = instrumenter().start(parentContext, request);
scope = context.makeCurrent();
promise.setEndOperationListener(new EndOperationListener<>(instrumenter(), context, request));
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Thrown Throwable throwable,
@Advice.Local("otelRequest") RedissonRequest request,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
scope.close();
if (throwable != null) {
instrumenter().end(context, request, null, throwable);
}
// span ended in EndOperationListener
}
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson.v3_17;
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 RedissonInstrumentationModule extends InstrumentationModule {
public RedissonInstrumentationModule() {
super("redisson", "redisson-3.17");
}
@Override
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
return hasClassesNamed("org.redisson.api.RFunction");
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new RedisConnectionInstrumentation(), new RedisCommandDataInstrumentation());
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson.v3_17;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.redisson.RedissonInstrumenterFactory;
import io.opentelemetry.javaagent.instrumentation.redisson.RedissonRequest;
public final class RedissonSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.redisson-3.17";
private static final Instrumenter<RedissonRequest, Void> INSTRUMENTER =
RedissonInstrumenterFactory.createInstrumenter(INSTRUMENTATION_NAME);
public static Instrumenter<RedissonRequest, Void> instrumenter() {
return INSTRUMENTER;
}
private RedissonSingletons() {}
}

View File

@ -0,0 +1,12 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class RedissonAsyncClientTest extends AbstractRedissonAsyncClientTest {
@Override
boolean useRedisProtocol() {
true
}
}

View File

@ -0,0 +1,12 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class RedissonClientTest extends AbstractRedissonClientTest {
@Override
boolean useRedisProtocol() {
true
}
}

View File

@ -0,0 +1,10 @@
plugins {
id("otel.javaagent-instrumentation")
}
dependencies {
compileOnly("org.redisson:redisson:3.0.0")
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")
}

View File

@ -5,22 +5,24 @@
package io.opentelemetry.javaagent.instrumentation.redisson;
import static io.opentelemetry.javaagent.instrumentation.redisson.RedissonSingletons.instrumenter;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import java.util.function.BiConsumer;
public final class EndOperationListener<T> implements BiConsumer<T, Throwable> {
private final Instrumenter<RedissonRequest, Void> instrumenter;
private final Context context;
private final RedissonRequest request;
public EndOperationListener(Context context, RedissonRequest request) {
public EndOperationListener(
Instrumenter<RedissonRequest, Void> instrumenter, Context context, RedissonRequest request) {
this.instrumenter = instrumenter;
this.context = context;
this.request = request;
}
@Override
public void accept(T t, Throwable error) {
instrumenter().end(context, request, null, error);
instrumenter.end(context, request, null, error);
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.redisson;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
public final class RedissonInstrumenterFactory {
public static Instrumenter<RedissonRequest, Void> createInstrumenter(String instrumentationName) {
RedissonDbAttributesGetter dbAttributesGetter = new RedissonDbAttributesGetter();
RedissonNetAttributesGetter netAttributesGetter = new RedissonNetAttributesGetter();
return Instrumenter.<RedissonRequest, Void>builder(
GlobalOpenTelemetry.get(),
instrumentationName,
DbClientSpanNameExtractor.create(dbAttributesGetter))
.addAttributesExtractor(DbClientAttributesExtractor.create(dbAttributesGetter))
.addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
.newInstrumenter(SpanKindExtractor.alwaysClient());
}
private RedissonInstrumenterFactory() {}
}

View File

@ -23,7 +23,6 @@ import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.redisson.client.protocol.CommandData;
import org.redisson.client.protocol.CommandsData;
import org.redisson.misc.RPromise;
@AutoValue
public abstract class RedissonRequest {
@ -138,9 +137,12 @@ public abstract class RedissonRequest {
private static MethodHandle findGetPromiseMethod(Class<?> commandClass) {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
try {
Class<?> promiseClass =
Class.forName(
"org.redisson.misc.RPromise", false, RedissonRequest.class.getClassLoader());
// try versions older than 3.16.8
return lookup.findVirtual(commandClass, "getPromise", MethodType.methodType(RPromise.class));
} catch (NoSuchMethodException e) {
return lookup.findVirtual(commandClass, "getPromise", MethodType.methodType(promiseClass));
} catch (NoSuchMethodException | ClassNotFoundException e) {
// in 3.16.8 CommandsData#getPromise() and CommandData#getPromise() return type was changed in
// a backwards-incompatible way from RPromise to CompletableFuture
try {

View File

@ -0,0 +1,14 @@
plugins {
id("otel.java-conventions")
}
dependencies {
api(project(":testing-common"))
implementation("org.apache.groovy:groovy")
implementation("io.opentelemetry:opentelemetry-api")
implementation("org.spockframework:spock-core")
implementation("org.testcontainers:testcontainers")
compileOnly("org.redisson:redisson:3.0.0")
}

View File

@ -8,6 +8,7 @@ import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.Callable
import java.util.concurrent.CompletionStage
import java.util.concurrent.TimeUnit
import org.redisson.Redisson
import org.redisson.api.RBucket
import org.redisson.api.RFuture
@ -19,12 +20,10 @@ import org.redisson.config.SingleServerConfig
import org.testcontainers.containers.GenericContainer
import spock.lang.Shared
import java.util.concurrent.TimeUnit
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
class RedissonAsyncClientTest extends AgentInstrumentationSpecification {
abstract class AbstractRedissonAsyncClientTest extends AgentInstrumentationSpecification {
private static GenericContainer redisServer = new GenericContainer<>("redis:6.2.3-alpine").withExposedPorts(6379)
@Shared
@ -39,7 +38,7 @@ class RedissonAsyncClientTest extends AgentInstrumentationSpecification {
redisServer.start()
port = redisServer.getMappedPort(6379)
address = "localhost:" + port
if (Boolean.getBoolean("testLatestDeps")) {
if (useRedisProtocol()) {
// Newer versions of redisson require scheme, older versions forbid it
address = "redis://" + address
}
@ -61,6 +60,10 @@ class RedissonAsyncClientTest extends AgentInstrumentationSpecification {
clearExportedData()
}
boolean useRedisProtocol() {
return Boolean.getBoolean("testLatestDeps")
}
def "test future set"() {
when:
RBucket<String> keyObject = redisson.getBucket("foo")

View File

@ -24,7 +24,7 @@ import static io.opentelemetry.api.trace.SpanKind.CLIENT
import static java.util.regex.Pattern.compile
import static java.util.regex.Pattern.quote
class RedissonClientTest extends AgentInstrumentationSpecification {
abstract class AbstractRedissonClientTest extends AgentInstrumentationSpecification {
private static GenericContainer redisServer = new GenericContainer<>("redis:6.2.3-alpine").withExposedPorts(6379)
@Shared
@ -39,7 +39,7 @@ class RedissonClientTest extends AgentInstrumentationSpecification {
redisServer.start()
port = redisServer.getMappedPort(6379)
address = "localhost:" + port
if (Boolean.getBoolean("testLatestDeps")) {
if (useRedisProtocol()) {
// Newer versions of redisson require scheme, older versions forbid it
address = "redis://" + address
}
@ -60,6 +60,10 @@ class RedissonClientTest extends AgentInstrumentationSpecification {
clearExportedData()
}
boolean useRedisProtocol() {
return Boolean.getBoolean("testLatestDeps")
}
def "test string command"() {
when:
RBucket<String> keyObject = redisson.getBucket("foo")

View File

@ -365,7 +365,10 @@ include(":instrumentation:reactor:reactor-3.1:testing")
include(":instrumentation:reactor:reactor-netty:reactor-netty-0.9:javaagent")
include(":instrumentation:reactor:reactor-netty:reactor-netty-1.0:javaagent")
include(":instrumentation:rediscala-1.8:javaagent")
include(":instrumentation:redisson-3.0:javaagent")
include(":instrumentation:redisson:redisson-3.0:javaagent")
include(":instrumentation:redisson:redisson-3.17:javaagent")
include(":instrumentation:redisson:redisson-common:javaagent")
include(":instrumentation:redisson:redisson-common:testing")
include(":instrumentation:restlet:restlet-1.0:javaagent")
include(":instrumentation:restlet:restlet-1.0:library")
include(":instrumentation:restlet:restlet-1.0:testing")