Convert Spymemcached integration to Instrumenter (#4273)
* Convert Spymemcached integration to Instrumenter * Update instrumentation/spymemcached-2.12/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spymemcached/SpymemcachedAttributeExtractor.java Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com> * Spotless * Optimise Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
parent
fbb5f8f5c6
commit
11b2f16820
|
@ -14,6 +14,9 @@ muzzle {
|
||||||
dependencies {
|
dependencies {
|
||||||
library("net.spy:spymemcached:2.12.0")
|
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")
|
testImplementation("com.google.guava:guava")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spymemcached;
|
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.api.trace.Span;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
|
@ -26,10 +26,12 @@ public abstract class CompletionListener<T> {
|
||||||
private static final String MISS = "miss";
|
private static final String MISS = "miss";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private final SpymemcachedRequest request;
|
||||||
|
|
||||||
protected CompletionListener(
|
protected CompletionListener(
|
||||||
Context parentContext, MemcachedConnection connection, String methodName) {
|
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) {
|
protected void closeAsyncSpan(T future) {
|
||||||
|
@ -48,26 +50,22 @@ public abstract class CompletionListener<T> {
|
||||||
span.setAttribute(DB_COMMAND_CANCELLED, true);
|
span.setAttribute(DB_COMMAND_CANCELLED, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tracer().endExceptionally(context, e);
|
instrumenter().end(context, request, null, e);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// Avoid swallowing InterruptedException
|
// Avoid swallowing InterruptedException
|
||||||
tracer().endExceptionally(context, e);
|
instrumenter().end(context, request, null, e);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
// This should never happen, just in case to make sure we cover all unexpected exceptions
|
// 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 {
|
} finally {
|
||||||
tracer().end(context);
|
instrumenter().end(context, request, future, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void closeSyncSpan(Throwable thrown) {
|
protected void closeSyncSpan(Throwable thrown) {
|
||||||
if (thrown == null) {
|
instrumenter().end(context, request, null, thrown);
|
||||||
tracer().end(context);
|
|
||||||
} else {
|
|
||||||
tracer().endExceptionally(context, thrown);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void processResult(Span span, T future)
|
protected abstract void processResult(Span span, T future)
|
||||||
|
|
|
@ -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<MemcachedConnection, String, String> {
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<SpymemcachedRequest, Object> {
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<SpymemcachedRequest, Object> INSTRUMENTER;
|
||||||
|
|
||||||
|
static {
|
||||||
|
DbAttributesExtractor<SpymemcachedRequest, Object> attributesExtractor =
|
||||||
|
new SpymemcachedAttributeExtractor();
|
||||||
|
SpanNameExtractor<SpymemcachedRequest> spanName =
|
||||||
|
DbSpanNameExtractor.create(attributesExtractor);
|
||||||
|
|
||||||
|
INSTRUMENTER =
|
||||||
|
Instrumenter.newBuilder(GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanName)
|
||||||
|
.addAttributesExtractor(attributesExtractor)
|
||||||
|
.newInstrumenter(SpanKindExtractor.alwaysClient());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Instrumenter<SpymemcachedRequest, Object> instrumenter() {
|
||||||
|
return INSTRUMENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpymemcachedSingletons() {}
|
||||||
|
}
|
Loading…
Reference in New Issue