Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
30c758d
Configure required settings for OpenTelemetry HTTP semantics:
zacharycmontoya Sep 23, 2026
46e94e7
Add the following tags:
zacharycmontoya Sep 24, 2026
ea6f1be
Implement OpenTelemetry HTTP client semantic conventions
zacharycmontoya Oct 6, 2026
61d0240
Implement OpenTelemetry HTTP server semantic conventions
zacharycmontoya Oct 6, 2026
099041c
Test end-to-end OpenTelemetry HTTP client semantics
zacharycmontoya Oct 1, 2026
36f08f9
Test end-to-end OpenTelemetry HTTP server semantics
zacharycmontoya Oct 1, 2026
4fe3e78
PR feedback on logic/processing, avoiding tags definitions:
zacharycmontoya Oct 16, 2026
01377cc
PR feedback on tag-conventions: Restore network.client.ip so it is no…
zacharycmontoya Oct 16, 2026
2ac5dd2
PR feedback on tag-conventions: Fix the tag definitions of OTel serve…
zacharycmontoya Oct 16, 2026
f0f092d
Polish: Update the obfuscator tag name for OpenTelemetry semantics to…
zacharycmontoya Oct 16, 2026
4e1404e
Polish: Update setters to use IDs rather than tag names
zacharycmontoya Oct 16, 2026
5f48fc9
Fix: Add regression tests for identified errors when enabling the opt…
zacharycmontoya Oct 19, 2026
70be501
Fix: Implement fixes for the noted regressions
zacharycmontoya Oct 19, 2026
866cff2
Fix: Address two issues identified by automated code review.
zacharycmontoya Oct 19, 2026
5eee031
fix linting issue
zacharycmontoya Oct 19, 2026
1d4d8a0
Apply spotless formatting
zacharycmontoya Oct 19, 2026
fd65cad
Fix: Address issues identified by automated code review:
zacharycmontoya Oct 20, 2026
abc1c63
PR feedback: Address the following issues:
zacharycmontoya Oct 21, 2026
18c7ce9
PR Feedback: Remove DDTags.HTTP_QUERY_OTEL_NAME (public API) and use …
zacharycmontoya Oct 21, 2026
d27a8f1
PR Feedback: Use the TagExtractor infrastructure to simplify setting …
zacharycmontoya Oct 21, 2026
ba672e9
Preserve default HTTP behavior with OTel semantics disabled
mcculls Oct 21, 2026
53b4e2c
Simplify HTTP URL string assembly
mcculls Oct 21, 2026
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
/dd-trace-api/src/*/*/datadog/trace/api/TracePropagation* @DataDog/apm-sdk-capabilities
/dd-trace-api/src/*/*/datadog/trace/api/sampling @DataDog/apm-sdk-capabilities
/internal-api/src/*/*/datadog/trace/bootstrap @DataDog/apm-sdk-capabilities
/internal-api/src/*/*/datadog/trace/bootstrap/instrumentation/api/http/ @DataDog/apm-sdk-capabilities
/internal-api/src/*/*/datadog/trace/api/propagation/ @DataDog/apm-sdk-capabilities
/internal-api/src/*/*/datadog/trace/api/sampling @DataDog/apm-sdk-capabilities
/internal-api/src/*/*/datadog/trace/api/scopemanager/ @DataDog/apm-sdk-capabilities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.ErrorPriorities;
import datadog.trace.bootstrap.instrumentation.api.SpanPrototype;
import datadog.trace.bootstrap.instrumentation.api.Tags;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.Inet6Address;
Expand Down Expand Up @@ -224,12 +223,12 @@ public final void onPeerConnection(
}

public void setPeerPort(AgentSpan span, String port) {
span.setTag(Tags.PEER_PORT, port);
span.setTag(KnownTags.PEER_PORT_ID, port);
}

public void setPeerPort(AgentSpan span, int port) {
if (port > UNSET_PORT) {
span.setTag(Tags.PEER_PORT, port);
span.setTag(KnownTags.PEER_PORT_ID, port);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import datadog.appsec.api.blocking.BlockingException;
import datadog.trace.api.Config;
import datadog.trace.api.DDTags;
import datadog.trace.api.InstrumenterConfig;
import datadog.trace.api.KnownTags;
import datadog.trace.api.ProductActivation;
import datadog.trace.api.appsec.HttpClientRequest;
import datadog.trace.api.datastreams.DataStreamsTransactionExtractor;
Expand All @@ -23,9 +23,11 @@
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
import datadog.trace.bootstrap.instrumentation.api.Tags;
import datadog.trace.bootstrap.instrumentation.api.URIUtils;
import datadog.trace.bootstrap.instrumentation.api.OtelHttpSemantics;
import datadog.trace.bootstrap.instrumentation.api.TagExtractor;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.instrumentation.api.http.DatadogClientUrl;
import datadog.trace.bootstrap.instrumentation.api.http.OtelClientUrl;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.BitSet;
Expand All @@ -42,6 +44,9 @@ public abstract class HttpClientDecorator<REQUEST, RESPONSE> extends UriBasedCli
private static final String DD_CLIENT_LIBRARY_LANGUAGE_HEADER_NAME = "DD-Client-Library-Language";

private static final BitSet CLIENT_ERROR_STATUSES = Config.get().getHttpClientErrorStatuses();
private static final boolean OTEL_SEMANTICS = Config.get().isTraceOtelSemanticsEnabled();
private static final TagExtractor<URI> URL_TAGS =
OTEL_SEMANTICS ? OtelClientUrl.INSTANCE : DatadogClientUrl.INSTANCE;

private static final UTF8BytesString DEFAULT_RESOURCE_NAME = UTF8BytesString.create("/");

Expand Down Expand Up @@ -118,7 +123,14 @@ protected void doOnRequest(final AgentSpan span, final REQUEST request) {
DSM_TRANSACTION_SOURCE_READER);

String method = method(request);
span.setTag(Tags.HTTP_METHOD, method);
if (OTEL_SEMANTICS) {
OtelHttpSemantics.setRequestMethod(span, method);
if (shouldSetResourceName()) {
OtelHttpSemantics.setMethodResourceName(span, method);
}
} else {
span.setTag(KnownTags.HTTP_METHOD_ID, method);
}

if (CLIENT_TAG_HEADERS) {
for (Map.Entry<String, String> headerTag :
Expand All @@ -130,24 +142,18 @@ protected void doOnRequest(final AgentSpan span, final REQUEST request) {
}
}

// Copy of HttpServerDecorator url handling
try {
final URI url = url(request);
if (url != null) {
onURI(span, url);
span.setTag(
Tags.HTTP_URL,
URIUtils.lazyValidURL(url.getScheme(), url.getHost(), url.getPort(), url.getPath()));
if (Config.get().isHttpClientTagQueryString()) {
span.setTag(DDTags.HTTP_QUERY, url.getQuery());
span.setTag(DDTags.HTTP_FRAGMENT, url.getFragment());
}
span.setTagsFrom(url, URL_TAGS);
// Explicit path mappings take precedence over the default name in either semantic mode.
if (shouldSetResourceName()) {
HTTP_RESOURCE_DECORATOR.withClientPath(span, method, url.getPath());
}
// SSRF exploit prevention check
onHttpClientRequest(span, url.toString());
} else if (shouldSetResourceName()) {
} else if (!OTEL_SEMANTICS && shouldSetResourceName()) {
span.setResourceName(DEFAULT_RESOURCE_NAME);
}
} catch (final BlockingException e) {
Expand Down Expand Up @@ -177,6 +183,9 @@ protected void doOnResponse(final AgentSpan span, final RESPONSE response) {
span.setHttpStatusCode(status);
if (CLIENT_ERROR_STATUSES.get(status)) {
span.setError(true);
if (OTEL_SEMANTICS) {
OtelHttpSemantics.setErrorType(span, status);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import datadog.context.Context;
import datadog.context.propagation.Propagators;
import datadog.trace.api.Config;
import datadog.trace.api.DDTags;
import datadog.trace.api.KnownTags;
import datadog.trace.api.datastreams.DataStreamsTransactionExtractor;
import datadog.trace.api.datastreams.DataStreamsTransactionTracker;
import datadog.trace.api.function.TriConsumer;
Expand All @@ -34,12 +34,16 @@
import datadog.trace.bootstrap.instrumentation.api.ClientIpAddressData;
import datadog.trace.bootstrap.instrumentation.api.ErrorPriorities;
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
import datadog.trace.bootstrap.instrumentation.api.OtelHttpSemantics;
import datadog.trace.bootstrap.instrumentation.api.ResourceNamePriorities;
import datadog.trace.bootstrap.instrumentation.api.TagContext;
import datadog.trace.bootstrap.instrumentation.api.TagExtractor;
import datadog.trace.bootstrap.instrumentation.api.Tags;
import datadog.trace.bootstrap.instrumentation.api.URIDataAdapter;
import datadog.trace.bootstrap.instrumentation.api.URIUtils;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.instrumentation.api.http.DatadogServerUrl;
import datadog.trace.bootstrap.instrumentation.api.http.HttpServerUrl;
import datadog.trace.bootstrap.instrumentation.api.http.OtelServerUrl;
import datadog.trace.bootstrap.instrumentation.decorator.http.ClientIpAddressResolver;
import java.net.InetAddress;
import java.util.BitSet;
Expand Down Expand Up @@ -68,13 +72,17 @@ public abstract class HttpServerDecorator<REQUEST, CONNECTION, RESPONSE, REQUEST
public static final String DD_IGNORE_COMMIT_ATTRIBUTE = "datadog.commit.ignore";

private static final UTF8BytesString DEFAULT_RESOURCE_NAME = UTF8BytesString.create("/");
private static final boolean OTEL_SEMANTICS = Config.get().isTraceOtelSemanticsEnabled();
private static final TagExtractor<HttpServerUrl> URL_TAGS =
OTEL_SEMANTICS ? OtelServerUrl.INSTANCE : DatadogServerUrl.INSTANCE;
protected static final UTF8BytesString NOT_FOUND_RESOURCE_NAME = UTF8BytesString.create("404");
protected static final boolean SHOULD_SET_404_RESOURCE_NAME =
Config.get().isRuleEnabled("URLAsResourceNameRule")
!OTEL_SEMANTICS
&& Config.get().isRuleEnabled("URLAsResourceNameRule")
&& Config.get().isRuleEnabled("Status404Rule")
&& Config.get().isRuleEnabled("Status404Decorator");
private static final boolean SHOULD_SET_URL_RESOURCE_NAME =
Config.get().isRuleEnabled("URLAsResourceNameRule");
!OTEL_SEMANTICS && Config.get().isRuleEnabled("URLAsResourceNameRule");

private static final BitSet SERVER_ERROR_STATUSES = Config.get().getHttpServerErrorStatuses();
private static final String DEFAULT_INSTRUMENTATION_NAME = "http-server";
Expand Down Expand Up @@ -323,40 +331,36 @@ protected void doOnRequest(
}
String userAgent = extracted.getUserAgent();
if (userAgent != null) {
span.setTag(Tags.HTTP_USER_AGENT, userAgent);
span.setTag(KnownTags.HTTP_USERAGENT_ID, userAgent);
}
}

if (request != null) {
String method = method(request);
span.setTag(Tags.HTTP_METHOD, method);
if (OTEL_SEMANTICS) {
OtelHttpSemantics.setRequestMethod(span, method);
OtelHttpSemantics.setMethodResourceName(span, method);
} else {
span.setTag(KnownTags.HTTP_METHOD_ID, method);
}

// Copy of HttpClientDecorator url handling
try {
final URIDataAdapter url = url(request);
if (url != null) {
boolean supportsRaw = url.supportsRaw();
boolean encoded = supportsRaw && config.isHttpServerRawResource();
boolean valid = url.isValid();
String path = encoded ? url.rawPath() : url.path();
if (valid) {
span.setTag(
Tags.HTTP_URL, URIUtils.lazyValidURL(url.scheme(), url.host(), url.port(), path));
} else if (supportsRaw) {
span.setTag(Tags.HTTP_URL, URIUtils.lazyInvalidUrl(url.raw()));
}
if (extracted != null && extracted.getXForwardedHost() != null) {
span.setTag(Tags.HTTP_HOSTNAME, extracted.getXForwardedHost());
} else if (url.host() != null) {
span.setTag(Tags.HTTP_HOSTNAME, url.host());
}

if (valid && config.isHttpServerTagQueryString()) {
String query =
supportsRaw && config.isHttpServerRawQueryString() ? url.rawQuery() : url.query();
span.setTag(DDTags.HTTP_QUERY, query);
span.setTag(DDTags.HTTP_FRAGMENT, url.fragment());
}
span.setTagsFrom(
HttpServerUrl.fromRequest(
url,
path,
extracted,
// Only OTel origin resolution uses Host to resolve ports after a scheme change.
OTEL_SEMANTICS && extracted != null && extracted.getXForwardedProto() != null
? getRequestHeader(request, "Host")
: null),
URL_TAGS);
Flow<Void> flow = callIGCallbackURI(span, url, method);
if (flow.getAction() instanceof RequestBlockingAction) {
span.setRequestBlockingAction((RequestBlockingAction) flow.getAction());
Expand Down Expand Up @@ -398,7 +402,7 @@ protected void doOnRequest(
if (inferredAddress != null) {
inferredAddressStr = inferredAddress.getHostAddress();
if (shouldTagIps) {
span.setTag(Tags.HTTP_CLIENT_IP, inferredAddressStr);
span.setTag(KnownTags.HTTP_CLIENT_IP_ID, inferredAddressStr);
}
}
} else if (shouldTagIps && span.getLocalRootSpan() != span) {
Expand All @@ -410,18 +414,21 @@ protected void doOnRequest(
AgentSpan localRootSpan = span.getLocalRootSpan();
Object clientIp = localRootSpan.getTag(Tags.HTTP_CLIENT_IP);
if (clientIp != null) {
span.setTag(Tags.HTTP_CLIENT_IP, clientIp);
span.setTag(KnownTags.HTTP_CLIENT_IP_ID, clientIp);
}
}

if (peerIp != null) {
if (peerIp.indexOf(':') > 0) {
span.setTag(Tags.PEER_HOST_IPV6, peerIp);
span.setTag(KnownTags.PEER_IPV6_ID, peerIp);
} else {
span.setTag(Tags.PEER_HOST_IPV4, peerIp);
span.setTag(KnownTags.PEER_IPV4_ID, peerIp);
}
if (shouldTagIps) {
span.setTag(Tags.NETWORK_CLIENT_IP, peerIp);
span.setTag(KnownTags.NETWORK_CLIENT_IP_ID, peerIp);
if (OTEL_SEMANTICS && span.getTag(KnownTags.HTTP_CLIENT_IP_OTEL_NAME) == null) {
span.setTag(KnownTags.HTTP_CLIENT_IP_ID, peerIp);
}
}
}
if (shouldStashIps && (peerIp != null || inferredAddressStr != null)) {
Expand Down Expand Up @@ -484,6 +491,9 @@ protected void doOnResponseStatus(final AgentSpan span, final int status) {
if (!BlockingException.class.getName().equals(span.getTag("error.type"))) {
span.setError(SERVER_ERROR_STATUSES.get(status), ErrorPriorities.HTTP_SERVER_DECORATOR);
}
if (OTEL_SEMANTICS && SERVER_ERROR_STATUSES.get(status)) {
OtelHttpSemantics.setErrorType(span, status);
}
}

if (SHOULD_SET_404_RESOURCE_NAME && status == 404) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@
import datadog.trace.api.Config;
import datadog.trace.api.datastreams.DataStreamsContext;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.OtelHttpSemantics;
import datadog.trace.bootstrap.instrumentation.api.Tags;
import java.net.URI;
import javax.annotation.Nonnull;

public abstract class UriBasedClientDecorator extends ClientDecorator {
private static final boolean OTEL_SEMANTICS = Config.get().isTraceOtelSemanticsEnabled();

public void onURI(@Nonnull final AgentSpan span, @Nonnull final URI uri) {
String host = uri.getHost();
int port = uri.getPort();
if (null != host && !host.isEmpty()) {
span.setTag(Tags.PEER_HOSTNAME, host);
if (Config.get().isHttpClientSplitByDomain() && host.charAt(0) >= 'A') {
span.setServiceName(host, component());
}
// Port tagging must follow domain splitting so split-by-tags keeps its precedence.
int port = OTEL_SEMANTICS ? OtelHttpSemantics.serverPort(uri) : uri.getPort();
if (port > 0) {
setPeerPort(span, port);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package datadog.trace.bootstrap.instrumentation.decorator;

import datadog.trace.api.Config;
import datadog.trace.api.cache.DDCache;
import datadog.trace.api.cache.DDCaches;
import datadog.trace.api.naming.SpanNaming;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
import datadog.trace.bootstrap.instrumentation.api.Tags;
import datadog.trace.bootstrap.instrumentation.api.TagExtractor;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.instrumentation.api.http.DatadogClientUrl;
import datadog.trace.bootstrap.instrumentation.api.http.OtelClientUrl;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
Expand All @@ -16,6 +19,10 @@
import org.slf4j.LoggerFactory;

public class UrlConnectionDecorator extends UriBasedClientDecorator {
private static final TagExtractor<URI> URL_TAGS =
Config.get().isTraceOtelSemanticsEnabled()
? OtelClientUrl.INSTANCE
: DatadogClientUrl.FULL_URL;
private static final DDCache<String, CharSequence> CACHE = DDCaches.newFixedSizeCache(16);

private static final Function<String, CharSequence> ADDER =
Expand Down Expand Up @@ -51,7 +58,7 @@ protected String service() {
@Override
public void onURI(@Nonnull AgentSpan span, @Nonnull URI uri) {
super.onURI(span, uri);
span.setTag(Tags.HTTP_URL, uri.toString());
span.setTagsFrom(uri, URL_TAGS);
}

public void onURL(@Nonnull final AgentSpan span, @Nonnull final URL url) {
Expand Down
Loading
Loading