diff --git a/instrumentation/spymemcached-2.12/javaagent/build.gradle.kts b/instrumentation/spymemcached-2.12/javaagent/build.gradle.kts index a5f5d6e1b3..b23f354cad 100644 --- a/instrumentation/spymemcached-2.12/javaagent/build.gradle.kts +++ b/instrumentation/spymemcached-2.12/javaagent/build.gradle.kts @@ -14,6 +14,9 @@ muzzle { dependencies { library("net.spy:spymemcached:2.12.0") + compileOnly("com.google.auto.value:auto-value-annotations") + annotationProcessor("com.google.auto.value:auto-value") + testImplementation("com.google.guava:guava") } diff --git a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/CompletionListener.java b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/CompletionListener.java index f0a2857329..cf5a75b8a4 100644 --- a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/CompletionListener.java +++ b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/CompletionListener.java @@ -5,7 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.spymemcached; -import static io.opentelemetry.javaagent.instrumentation.spymemcached.MemcacheClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.spymemcached.SpymemcachedSingletons.instrumenter; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; @@ -26,10 +26,12 @@ public abstract class CompletionListener { private static final String MISS = "miss"; private final Context context; + private final SpymemcachedRequest request; protected CompletionListener( Context parentContext, MemcachedConnection connection, String methodName) { - context = tracer().startSpan(parentContext, connection, methodName); + request = SpymemcachedRequest.create(connection, methodName); + context = instrumenter().start(parentContext, request); } protected void closeAsyncSpan(T future) { @@ -48,26 +50,22 @@ public abstract class CompletionListener { span.setAttribute(DB_COMMAND_CANCELLED, true); } } else { - tracer().endExceptionally(context, e); + instrumenter().end(context, request, null, e); } } catch (InterruptedException e) { // Avoid swallowing InterruptedException - tracer().endExceptionally(context, e); + instrumenter().end(context, request, null, e); Thread.currentThread().interrupt(); } catch (Throwable t) { // This should never happen, just in case to make sure we cover all unexpected exceptions - tracer().endExceptionally(context, t); + instrumenter().end(context, request, null, t); } finally { - tracer().end(context); + instrumenter().end(context, request, future, null); } } protected void closeSyncSpan(Throwable thrown) { - if (thrown == null) { - tracer().end(context); - } else { - tracer().endExceptionally(context, thrown); - } + instrumenter().end(context, request, null, thrown); } protected abstract void processResult(Span span, T future) diff --git a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/MemcacheClientTracer.java b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/MemcacheClientTracer.java deleted file mode 100644 index 761d2ec9c4..0000000000 --- a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/MemcacheClientTracer.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.spymemcached; - -import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer; -import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes; -import java.net.InetSocketAddress; -import net.spy.memcached.MemcachedConnection; - -public class MemcacheClientTracer - extends DatabaseClientTracer { - private static final MemcacheClientTracer TRACER = new MemcacheClientTracer(); - - private MemcacheClientTracer() { - super(NetPeerAttributes.INSTANCE); - } - - public static MemcacheClientTracer tracer() { - return TRACER; - } - - @Override - protected String sanitizeStatement(String methodName) { - char[] chars = - methodName - .replaceFirst("^async", "") - // 'CAS' name is special, we have to lowercase whole name - .replaceFirst("^CAS", "cas") - .toCharArray(); - - // Lowercase first letter - chars[0] = Character.toLowerCase(chars[0]); - - return new String(chars); - } - - @Override - protected String dbSystem(MemcachedConnection memcachedConnection) { - return "memcached"; - } - - @Override - protected InetSocketAddress peerAddress(MemcachedConnection memcachedConnection) { - return null; - } - - @Override - protected String dbOperation( - MemcachedConnection connection, String methodName, String operation) { - return operation; - } - - @Override - protected String getInstrumentationName() { - return "io.opentelemetry.spymemcached-2.12"; - } -} diff --git a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedAttributeExtractor.java b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedAttributeExtractor.java new file mode 100644 index 0000000000..f00d8d7abe --- /dev/null +++ b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedAttributeExtractor.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.spymemcached; + +import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class SpymemcachedAttributeExtractor + extends DbAttributesExtractor { + @Override + protected String system(SpymemcachedRequest spymemcachedRequest) { + return "memcached"; + } + + @Override + protected @Nullable String user(SpymemcachedRequest spymemcachedRequest) { + return null; + } + + @Override + protected @Nullable String name(SpymemcachedRequest spymemcachedRequest) { + return null; + } + + @Override + protected @Nullable String connectionString(SpymemcachedRequest spymemcachedRequest) { + return null; + } + + @Override + protected @Nullable String statement(SpymemcachedRequest spymemcachedRequest) { + return null; + } + + @Override + protected @Nullable String operation(SpymemcachedRequest spymemcachedRequest) { + return spymemcachedRequest.dbOperation(); + } +} diff --git a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedRequest.java b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedRequest.java new file mode 100644 index 0000000000..e8c45837a5 --- /dev/null +++ b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedRequest.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.spymemcached; + +import com.google.auto.value.AutoValue; +import net.spy.memcached.MemcachedConnection; + +@AutoValue +public abstract class SpymemcachedRequest { + + public static SpymemcachedRequest create(MemcachedConnection connection, String statement) { + return new AutoValue_SpymemcachedRequest(connection, statement); + } + + public abstract MemcachedConnection getConnection(); + + public abstract String getStatement(); + + public String dbOperation() { + String statement = getStatement(); + if (statement.startsWith("async")) { + statement = statement.substring("async".length()); + } + if (statement.startsWith("CAS")) { + // 'CAS' name is special, we have to lowercase whole name + return "cas" + statement.substring("CAS".length()); + } + + char[] chars = statement.toCharArray(); + // Lowercase first letter + chars[0] = Character.toLowerCase(chars[0]); + return new String(chars); + } +} diff --git a/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedSingletons.java b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedSingletons.java new file mode 100644 index 0000000000..229ddfb569 --- /dev/null +++ b/instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedSingletons.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.spymemcached; + +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.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.db.DbSpanNameExtractor; + +public final class SpymemcachedSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spymemcached-2.12"; + + private static final Instrumenter INSTRUMENTER; + + static { + DbAttributesExtractor attributesExtractor = + new SpymemcachedAttributeExtractor(); + SpanNameExtractor spanName = + DbSpanNameExtractor.create(attributesExtractor); + + INSTRUMENTER = + Instrumenter.newBuilder(GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanName) + .addAttributesExtractor(attributesExtractor) + .newInstrumenter(SpanKindExtractor.alwaysClient()); + } + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private SpymemcachedSingletons() {} +}