Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import datadog.trace.api.Config;
import datadog.trace.api.DDTags;
import datadog.trace.api.Functions;
import datadog.trace.api.KnownTags;
import datadog.trace.api.TagMap;
import datadog.trace.api.cache.QualifiedClassNameCache;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
Expand Down Expand Up @@ -194,12 +195,12 @@ public final void onPeerConnection(
if (remoteAddress != null) {
String ip = remoteAddress.getHostAddress();
if (resolved && Config.get().isPeerHostNameEnabled()) {
span.setTag(Tags.PEER_HOSTNAME, hostName(remoteAddress, ip));
span.setTag(KnownTags.PEER_HOSTNAME_ID, hostName(remoteAddress, ip));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are included because eventually we'll need to use ID to disambiguate some of these concepts for OTLP, and I wanted to illustrate usage.

That said, I'm happy to leave these to another PR if others prefer.

}
if (remoteAddress instanceof Inet4Address) {
span.setTag(Tags.PEER_HOST_IPV4, ip);
span.setTag(KnownTags.PEER_IPV4_ID, ip);
} else if (remoteAddress instanceof Inet6Address) {
span.setTag(Tags.PEER_HOST_IPV6, ip);
span.setTag(KnownTags.PEER_IPV6_ID, ip);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ class BaseDecoratorTest extends DDSpecification {
@Shared
def errorPriority = null as Byte

def span = Mock(AgentSpan)
def span = mockSpan()

/**
* Mocks an {@link AgentSpan} that reports every id-keyed {@code setTag} as the name-keyed call,
* so expectations are written by tag name however the code under test sets the tag. See
* {@link NameKeyedAgentSpan}.
*/
AgentSpan mockSpan() {
return Mock(NameKeyedAgentSpan)
}
def spanContext = Mock(AgentSpanContext)

def "test afterStart"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import datadog.trace.bootstrap.instrumentation.api.Tags

class ClientDecoratorTest extends BaseDecoratorTest {

def span = Mock(AgentSpan)
def span = mockSpan()

def "test afterStart"() {
setup:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ package datadog.trace.bootstrap.instrumentation.decorator

import datadog.trace.api.DDTags
import datadog.trace.api.TagMap
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
import datadog.trace.bootstrap.instrumentation.api.Tags
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString
import spock.lang.Ignore

class DBTypeProcessingDatabaseClientDecoratorTest extends ClientDecoratorTest {

def span = Mock(AgentSpan)
def span = mockSpan()

@Ignore("https://github.com/DataDog/dd-trace-java/pull/5213")
def "test afterStart"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST

class DatabaseClientDecoratorTest extends ClientDecoratorTest {

def span = Mock(AgentSpan)
def span = mockSpan()

def "test afterStart"() {
setup:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class HttpClientDecoratorTest extends ClientDecoratorTest {
AgentTracer.forceRegister(ORIGINAL_TRACER)
}

def span = Mock(AgentSpan)
def span = mockSpan()

def "test onRequest"() {
setup:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import static datadog.trace.api.gateway.Events.EVENTS

class HttpServerDecoratorTest extends ServerDecoratorTest {

def span = Mock(AgentSpan)
def span = mockSpan()

static class MapCarrierVisitor
implements AgentPropagation.ContextVisitor<Map> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import static datadog.trace.bootstrap.instrumentation.api.Tags.SPAN_KIND

class ServerDecoratorTest extends BaseDecoratorTest {

def span = Mock(AgentSpan)
def span = mockSpan()

def "test afterStart"() {
def decorator = newDecorator()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package datadog.trace.bootstrap.instrumentation.decorator;

import datadog.trace.api.KnownTagCodec;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;

/**
* An {@link AgentSpan} to mock in tests whose id-keyed {@code setTag} overloads are {@code final}
* and delegate to the name-keyed ones. A mock cannot override a final method, so it never sees the
* id-keyed call: tests keep expecting {@code setTag(name, value)} whether the code under test sets
* a tag by name or by {@code KnownTags} id.
*/
public abstract class NameKeyedAgentSpan implements AgentSpan {
@Override
public final AgentSpan setTag(long tagId, boolean value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, int value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, long value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, float value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, double value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, String value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, CharSequence value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}

@Override
public final AgentSpan setTag(long tagId, Object value) {
return setTag(KnownTagCodec.nameOf(tagId), value);
}
}
62 changes: 62 additions & 0 deletions dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import datadog.trace.api.DDTags;
import datadog.trace.api.DDTraceId;
import datadog.trace.api.EndpointTracker;
import datadog.trace.api.KnownTags;
import datadog.trace.api.TagMap;
import datadog.trace.api.TraceConfig;
import datadog.trace.api.debugger.DebuggerConfigBridge;
Expand Down Expand Up @@ -514,6 +515,67 @@ public DDSpan setTag(final String tag, final Object value) {
return this;
}

// Id-keyed overrides: same behavior as the String family above, including interception and the
// http.status_code quirk, but the tag is stored by id with no name lookup.
@Override
public DDSpan setTag(final long tagId, final String value) {
if (value == null || value.isEmpty()) {
context.removeTag(tagId);
Comment thread
dougqh marked this conversation as resolved.
} else {
context.setTag(tagId, value);
}
return this;
}

@Override
public DDSpan setTag(final long tagId, final boolean value) {
context.setTag(tagId, value);
return this;
}

@Override
public DDSpan setTag(final long tagId, final int value) {
if (tagId == KnownTags.HTTP_STATUS_CODE_ID) {
context.setHttpStatusCode((short) value);
}
context.setTag(tagId, value);
return this;
}

@Override
public DDSpan setTag(final long tagId, final long value) {
context.setTag(tagId, value);
return this;
}

@Override
public DDSpan setTag(final long tagId, final float value) {
context.setTag(tagId, value);
return this;
}

@Override
public DDSpan setTag(final long tagId, final double value) {
context.setTag(tagId, value);
return this;
}

@Override
public DDSpan setTag(final long tagId, final CharSequence value) {
if (value == null || value.length() == 0) {
context.setTag(tagId, (Object) null);
} else {
context.setTag(tagId, value);
}
return this;
}

@Override
public DDSpan setTag(final long tagId, final Object value) {
context.setTag(tagId, value);
return this;
}

@Override
public AgentSpan setAllTags(Map<String, ?> map) {
context.setAllTags(map);
Expand Down
127 changes: 123 additions & 4 deletions dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import datadog.trace.api.DDTags;
import datadog.trace.api.DDTraceId;
import datadog.trace.api.Functions;
import datadog.trace.api.KnownTagCodec;
import datadog.trace.api.KnownTags;
import datadog.trace.api.ProcessTags;
import datadog.trace.api.TagMap;
Expand Down Expand Up @@ -995,6 +996,22 @@ public void removeTag(String tag) {
}
}

/**
* Removes a known tag by id, rather than by its name, which need not resolve back to the id. An
* id that names no known tag is ignored, like the id-keyed setters do.
*/
public void removeTag(long tagId) {
if (KnownTagCodec.nameOf(tagId) == null) {
return;
}
if (tagId == KnownTags.SPAN_KIND_ID) {
spanKindOrdinal = SPAN_KIND_UNSET;
}
synchronized (unsafeTags) {
unsafeTags.getAndRemove(tagId);
}
}

/**
* Sets a tag to the span. Tags are not propagated to the children.
*
Expand Down Expand Up @@ -1030,6 +1047,109 @@ public void setTag(final String tag, final String value) {
}
}

/*
* Id-keyed setters, mirroring the String setters above: interception still runs on the tag's
* name (TagInterceptor is name-keyed), but a stored tag is set by id, skipping the name lookup.
* An id that names no known tag is ignored, like a null tag.
*/
public void setTag(final long tagId, final Object value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (null == value) {
removeTag(tagId);
} else if (!tagInterceptor.interceptTag(this, tag, value)) {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(final long tagId, final CharSequence value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (null == value) {
removeTag(tagId);
} else if (!tagInterceptor.interceptTag(this, tag, value)) {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(final long tagId, final boolean value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (precheckIntercept(tag)) {
this.setBox(tag, value);
} else {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(final long tagId, final int value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (precheckIntercept(tag)) {
this.setBox(tag, value);
} else {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(final long tagId, final long value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (precheckIntercept(tag)) {
this.setBox(tag, value);
} else {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(final long tagId, final float value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (precheckIntercept(tag)) {
this.setBox(tag, value);
} else {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(final long tagId, final double value) {
final String tag = KnownTagCodec.nameOf(tagId);
if (null == tag) {
return;
}
if (precheckIntercept(tag)) {
this.setBox(tag, value);
} else {
synchronized (unsafeTags) {
unsafeTags.set(tagId, value);
}
}
}

public void setTag(TagMap.EntryReader entry) {
if (entry == null) {
return;
Expand Down Expand Up @@ -1105,10 +1225,9 @@ public void setTag(final String tag, final long value) {
if (null == tag) {
return;
}
// check needsIntercept first to avoid unnecessary boxing
boolean intercepted =
tagInterceptor.needsIntercept(tag) && tagInterceptor.interceptTag(this, tag, value);
if (!intercepted) {
if (precheckIntercept(tag)) {
this.setBox(tag, value);
} else {
synchronized (unsafeTags) {
unsafeTags.set(tag, value);
}
Expand Down
Loading
Loading