This commit is contained in:
Tyler Benson 2018-07-26 16:03:02 +10:00
parent 2e7899b405
commit 094552cad3
2 changed files with 19 additions and 24 deletions

View File

@ -2,6 +2,7 @@ package datadog.trace.instrumentation.spymemcached;
import static io.opentracing.log.Fields.ERROR_OBJECT; import static io.opentracing.log.Fields.ERROR_OBJECT;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags; import datadog.trace.api.DDTags;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.Span; import io.opentracing.Span;
@ -19,12 +20,6 @@ public abstract class CompletionListener<T> {
static final String OPERATION_NAME = "memcached.query"; static final String OPERATION_NAME = "memcached.query";
static final String SERVICE_NAME = "memcached"; static final String SERVICE_NAME = "memcached";
/*
Ideally this should be "spymemcached" or something along those lines.
Unfortunately nondeterministic interaction between SpanTypeDecorator and DBTypeDecorator
pretty much forces this to be "sql".
*/
static final String SPAN_TYPE = "cache";
static final String COMPONENT_NAME = "java-spymemcached"; static final String COMPONENT_NAME = "java-spymemcached";
static final String DB_TYPE = "memcached"; static final String DB_TYPE = "memcached";
static final String DB_COMMAND_CANCELLED = "db.command.cancelled"; static final String DB_COMMAND_CANCELLED = "db.command.cancelled";
@ -35,36 +30,36 @@ public abstract class CompletionListener<T> {
private final Tracer tracer; private final Tracer tracer;
private final Scope scope; private final Scope scope;
public CompletionListener(final Tracer tracer, String methodName, boolean async) { public CompletionListener(final Tracer tracer, final String methodName, final boolean async) {
this.tracer = tracer; this.tracer = tracer;
scope = buildSpan(getOperationName(methodName), async); scope = buildSpan(getOperationName(methodName), async);
} }
private Scope buildSpan(String operation, boolean async) { private Scope buildSpan(final String operation, final boolean async) {
final Tracer.SpanBuilder spanBuilder = final Tracer.SpanBuilder spanBuilder =
tracer tracer
.buildSpan(OPERATION_NAME) .buildSpan(OPERATION_NAME)
.withTag(DDTags.SERVICE_NAME, SERVICE_NAME) .withTag(DDTags.SERVICE_NAME, SERVICE_NAME)
.withTag(DDTags.RESOURCE_NAME, operation) .withTag(DDTags.RESOURCE_NAME, operation)
.withTag(DDTags.SPAN_TYPE, SPAN_TYPE) .withTag(DDTags.SPAN_TYPE, DDSpanTypes.MEMCACHED)
.withTag(Tags.COMPONENT.getKey(), COMPONENT_NAME) .withTag(Tags.COMPONENT.getKey(), COMPONENT_NAME)
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
.withTag(Tags.DB_TYPE.getKey(), DB_TYPE); .withTag(Tags.DB_TYPE.getKey(), DB_TYPE);
Scope scope = spanBuilder.startActive(false); final Scope scope = spanBuilder.startActive(false);
if (async) { if (async) {
scope.close(); scope.close();
} }
return scope; return scope;
} }
protected void closeAsyncSpan(T future) { protected void closeAsyncSpan(final T future) {
Span span = scope.span(); final Span span = scope.span();
try { try {
processResult(span, future); processResult(span, future);
} catch (CancellationException e) { } catch (final CancellationException e) {
span.setTag(DB_COMMAND_CANCELLED, true); span.setTag(DB_COMMAND_CANCELLED, true);
} catch (ExecutionException e) { } catch (final ExecutionException e) {
if (e.getCause() instanceof CancellationException) { if (e.getCause() instanceof CancellationException) {
// Looks like underlying OperationFuture wraps CancellationException into ExecutionException // Looks like underlying OperationFuture wraps CancellationException into ExecutionException
span.setTag(DB_COMMAND_CANCELLED, true); span.setTag(DB_COMMAND_CANCELLED, true);
@ -72,12 +67,12 @@ public abstract class CompletionListener<T> {
Tags.ERROR.set(span, Boolean.TRUE); Tags.ERROR.set(span, Boolean.TRUE);
span.log(Collections.singletonMap(ERROR_OBJECT, e.getCause())); span.log(Collections.singletonMap(ERROR_OBJECT, e.getCause()));
} }
} catch (InterruptedException e) { } catch (final InterruptedException e) {
// Avoid swallowing InterruptedException // Avoid swallowing InterruptedException
Tags.ERROR.set(span, Boolean.TRUE); Tags.ERROR.set(span, Boolean.TRUE);
span.log(Collections.singletonMap(ERROR_OBJECT, e)); span.log(Collections.singletonMap(ERROR_OBJECT, e));
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (Exception e) { } catch (final Exception e) {
// 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
Tags.ERROR.set(span, Boolean.TRUE); Tags.ERROR.set(span, Boolean.TRUE);
span.log(Collections.singletonMap(ERROR_OBJECT, e)); span.log(Collections.singletonMap(ERROR_OBJECT, e));
@ -86,8 +81,8 @@ public abstract class CompletionListener<T> {
} }
} }
protected void closeSyncSpan(Throwable thrown) { protected void closeSyncSpan(final Throwable thrown) {
Span span = scope.span(); final Span span = scope.span();
if (thrown != null) { if (thrown != null) {
Tags.ERROR.set(span, Boolean.TRUE); Tags.ERROR.set(span, Boolean.TRUE);
@ -101,12 +96,12 @@ public abstract class CompletionListener<T> {
protected abstract void processResult(Span span, T future) protected abstract void processResult(Span span, T future)
throws ExecutionException, InterruptedException; throws ExecutionException, InterruptedException;
protected void setResultTag(Span span, boolean hit) { protected void setResultTag(final Span span, final boolean hit) {
span.setTag(MEMCACHED_RESULT, hit ? HIT : MISS); span.setTag(MEMCACHED_RESULT, hit ? HIT : MISS);
} }
private static String getOperationName(String methodName) { private static String getOperationName(final String methodName) {
char chars[] = final char[] chars =
methodName methodName
.replaceFirst("^async", "") .replaceFirst("^async", "")
// 'CAS' name is special, we have to lowercase whole name // 'CAS' name is special, we have to lowercase whole name

View File

@ -3,6 +3,7 @@ package datadog.trace.instrumentation.spymemcached
import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.MoreExecutors
import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.AgentTestRunner
import datadog.trace.agent.test.TraceAssert import datadog.trace.agent.test.TraceAssert
import datadog.trace.api.DDSpanTypes
import datadog.trace.api.DDTags import datadog.trace.api.DDTags
import io.opentracing.tag.Tags import io.opentracing.tag.Tags
import net.spy.memcached.CASResponse import net.spy.memcached.CASResponse
@ -25,7 +26,6 @@ import java.util.concurrent.locks.ReentrantLock
import static CompletionListener.COMPONENT_NAME import static CompletionListener.COMPONENT_NAME
import static CompletionListener.OPERATION_NAME import static CompletionListener.OPERATION_NAME
import static CompletionListener.SERVICE_NAME import static CompletionListener.SERVICE_NAME
import static CompletionListener.SPAN_TYPE
import static datadog.trace.agent.test.ListWriterAssert.assertTraces import static datadog.trace.agent.test.ListWriterAssert.assertTraces
import static datadog.trace.agent.test.TestUtils.runUnderTrace import static datadog.trace.agent.test.TestUtils.runUnderTrace
import static net.spy.memcached.ConnectionFactoryBuilder.Protocol.BINARY import static net.spy.memcached.ConnectionFactoryBuilder.Protocol.BINARY
@ -631,12 +631,12 @@ class SpymemcachedTest extends AgentTestRunner {
serviceName SERVICE_NAME serviceName SERVICE_NAME
operationName OPERATION_NAME operationName OPERATION_NAME
resourceName operation resourceName operation
spanType SPAN_TYPE spanType DDSpanTypes.MEMCACHED
errored(error != null && error != "canceled") errored(error != null && error != "canceled")
tags { tags {
defaultTags() defaultTags()
"${DDTags.SPAN_TYPE}" SPAN_TYPE "${DDTags.SPAN_TYPE}" DDSpanTypes.MEMCACHED
"${Tags.COMPONENT.key}" COMPONENT_NAME "${Tags.COMPONENT.key}" COMPONENT_NAME
"${Tags.SPAN_KIND.key}" Tags.SPAN_KIND_CLIENT "${Tags.SPAN_KIND.key}" Tags.SPAN_KIND_CLIENT
"${Tags.DB_TYPE.key}" CompletionListener.DB_TYPE "${Tags.DB_TYPE.key}" CompletionListener.DB_TYPE