diff --git a/instrumentation/jedis-5.0.0/build.gradle b/instrumentation/jedis-5.0.0/build.gradle new file mode 100644 index 0000000000..0efd5985bf --- /dev/null +++ b/instrumentation/jedis-5.0.0/build.gradle @@ -0,0 +1,24 @@ +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.jedis-5.0.0' } +} + +dependencies { + implementation(project(":agent-bridge")) + implementation(project(":agent-bridge-datastore")) + implementation(project(":newrelic-api")) + implementation(project(":newrelic-weaver-api")) + implementation("redis.clients:jedis:5.0.0") +} + +verifyInstrumentation { + passesOnly 'redis.clients:jedis:[5.0.0,)' + fails 'redis.clients:jedis:[1.4.0,3.8.0]' + excludeRegex 'redis.clients:jedis:.*-(m|rc|RC|alpha|beta)[0-9]*' + exclude 'redis.clients:jedis:3.6.2' + +} + +site { + title 'Jedis' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation/jedis-5.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java b/instrumentation/jedis-5.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java new file mode 100644 index 0000000000..cbd9290f2b --- /dev/null +++ b/instrumentation/jedis-5.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java @@ -0,0 +1,90 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package redis.clients.jedis; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.agent.bridge.datastore.DatastoreVendor; +import com.newrelic.api.agent.DatastoreParameters; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import redis.clients.jedis.commands.ProtocolCommand; + +import java.nio.charset.StandardCharsets; +import java.util.logging.Level; + +@SuppressWarnings({ "ResultOfMethodCallIgnored", "WeakerAccess", "unused" }) // Weaver.callOriginal(), matching signatures +@Weave(type = MatchType.BaseClass, originalName = "redis.clients.jedis.Connection") +public abstract class Connection_Instrumentation { + + @NewField + private long db = 0; + + abstract HostAndPort getHostAndPort(); + + public void disconnect() { + db = 0; + Weaver.callOriginal(); + } + + @Trace + public void sendCommand(final ProtocolCommand cmd, final byte[]... args) { + Weaver.callOriginal(); + if (args != null && args.length > 0) { + updateDbIndex(cmd, new String(args[0], StandardCharsets.UTF_8)); + } + } + + @Trace + public void sendCommand(final ProtocolCommand cmd, final String... args) { + Weaver.callOriginal(); + if (args != null && args.length > 0) { + updateDbIndex(cmd, args[0]); + } + } + + @Trace(leaf = true) + public void sendCommand(final CommandArguments args) { + Weaver.callOriginal(); + + ProtocolCommand cmd = args.getCommand(); + reportMethodAsExternal(cmd); + + } + + private void updateDbIndex(ProtocolCommand cmd, String arg0) { + try { + if (cmd == Protocol.Command.SELECT) { + db = Long.parseLong(arg0); + } + } catch (Throwable t) { + AgentBridge.getAgent().getLogger().log(Level.FINER, t, "Unable to set DB index"); + } + } + + private void reportMethodAsExternal(ProtocolCommand command) { + String operation = "unknown"; + try { + + operation = new String(command.getRaw(), Protocol.CHARSET).toLowerCase(); + } catch (Exception ignored) { + } + + NewRelic.getAgent().getTracedMethod().reportAsExternal(DatastoreParameters + .product(DatastoreVendor.Redis.name()) + .collection(null) + .operation(operation) + .instance(getHostAndPort().getHost(), getHostAndPort().getPort()) + .databaseName(String.valueOf(db)) + .build()); + } + +} diff --git a/instrumentation/jedis-5.0.0/src/main/java/redis/clients/jedis/JedisPubSubBase_Instrumentation.java b/instrumentation/jedis-5.0.0/src/main/java/redis/clients/jedis/JedisPubSubBase_Instrumentation.java new file mode 100644 index 0000000000..ea19f8affc --- /dev/null +++ b/instrumentation/jedis-5.0.0/src/main/java/redis/clients/jedis/JedisPubSubBase_Instrumentation.java @@ -0,0 +1,83 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package redis.clients.jedis; + +import com.newrelic.agent.bridge.datastore.DatastoreVendor; +import com.newrelic.api.agent.DatastoreParameters; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@SuppressWarnings({ "ResultOfMethodCallIgnored", "unused" }) +@Weave(type = MatchType.ExactClass, originalName = "redis.clients.jedis.JedisPubSubBase") +public class JedisPubSubBase_Instrumentation { + + private volatile Connection client; + + public final void proceed(Connection client, Object... channels) { + Weaver.callOriginal(); + } + + public void proceedWithPatterns(Connection client, Object... channels) { + Weaver.callOriginal(); + } + + @Trace + public void onMessage(Object channel, Object message) { + Weaver.callOriginal(); + + reportMethodAsExternal("message"); + } + + @Trace + public void onPMessage(Object pattern, Object channel, Object message) { + Weaver.callOriginal(); + + reportMethodAsExternal("message"); + } + + @Trace + public void onSubscribe(Object channel, int subscribedChannels) { + Weaver.callOriginal(); + + reportMethodAsExternal("subscribe"); + } + + @Trace + public void onUnsubscribe(Object channel, int subscribedChannels) { + Weaver.callOriginal(); + + reportMethodAsExternal("unsubscribe"); + } + + @Trace + public void onPUnsubscribe(Object pattern, int subscribedChannels) { + Weaver.callOriginal(); + + reportMethodAsExternal("unsubscribe"); + } + + @Trace + public void onPSubscribe(Object pattern, int subscribedChannels) { + Weaver.callOriginal(); + + reportMethodAsExternal("subscribe"); + } + + private void reportMethodAsExternal(String commandName) { + NewRelic.getAgent().getTracedMethod().reportAsExternal(DatastoreParameters + .product(DatastoreVendor.Redis.name()) + .collection(null) + .operation(commandName) + .instance(client.getHostAndPort().getHost(), client.getHostAndPort().getPort()) + .build()); + + } +} diff --git a/settings.gradle b/settings.gradle index b3838b6793..66c617cb31 100644 --- a/settings.gradle +++ b/settings.gradle @@ -203,6 +203,7 @@ include 'instrumentation:jedis-2.7.1' include 'instrumentation:jedis-2.7.2' include 'instrumentation:jedis-3.0.0' include 'instrumentation:jedis-4.0.0' +include 'instrumentation:jedis-5.0.0' include 'instrumentation:jersey-1' include 'instrumentation:jersey-2' include 'instrumentation:jersey-3'