From 35e6e1e3f7a3f6607d85e68e1f30a978f0d44d8d Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Wed, 3 Dec 2025 11:35:39 +0100 Subject: [PATCH] Avoid getTag overhead in ConflatingMetricsAggregator --- .../metrics/ConflatingMetricsAggregator.java | 27 ++++++++++--------- .../java/datadog/trace/core/CoreSpan.java | 8 ++++++ .../main/java/datadog/trace/core/DDSpan.java | 13 +++++++++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java b/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java index 9ca468c24b4..3fbac80e9e4 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java @@ -46,6 +46,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import javax.annotation.Nonnull; import org.jctools.queues.MpscCompoundQueue; import org.jctools.queues.SpmcArrayQueue; import org.slf4j.Logger; @@ -276,7 +277,8 @@ public boolean publish(List> trace) { if (features.supportsMetrics()) { for (CoreSpan span : trace) { boolean isTopLevel = span.isTopLevel(); - if (shouldComputeMetric(span)) { + final CharSequence spanKind = span.unsafeGetTag(SPAN_KIND, ""); + if (shouldComputeMetric(span, spanKind)) { final CharSequence resourceName = span.getResourceName(); if (resourceName != null && ignoredResources.contains(resourceName.toString())) { // skip publishing all children @@ -284,7 +286,7 @@ public boolean publish(List> trace) { break; } counted++; - forceKeep |= publish(span, isTopLevel); + forceKeep |= publish(span, isTopLevel, spanKind); } } healthMetrics.onClientStatTraceComputed( @@ -293,21 +295,19 @@ public boolean publish(List> trace) { return forceKeep; } - private boolean shouldComputeMetric(CoreSpan span) { - return (span.isMeasured() || span.isTopLevel() || spanKindEligible(span)) + private boolean shouldComputeMetric(CoreSpan span, @Nonnull CharSequence spanKind) { + return (span.isMeasured() || span.isTopLevel() || spanKindEligible(spanKind)) && span.getLongRunningVersion() <= 0 // either not long-running or unpublished long-running span && span.getDurationNano() > 0; } - private boolean spanKindEligible(CoreSpan span) { - final Object spanKind = span.getTag(SPAN_KIND); + private boolean spanKindEligible(@Nonnull CharSequence spanKind) { // use toString since it could be a CharSequence... - return spanKind != null && ELIGIBLE_SPAN_KINDS_FOR_METRICS.contains(spanKind.toString()); + return ELIGIBLE_SPAN_KINDS_FOR_METRICS.contains(spanKind.toString()); } - private boolean publish(CoreSpan span, boolean isTopLevel) { - final CharSequence spanKind = span.getTag(SPAN_KIND, ""); + private boolean publish(CoreSpan span, boolean isTopLevel, CharSequence spanKind) { MetricKey newKey = new MetricKey( span.getResourceName(), @@ -353,9 +353,10 @@ private boolean publish(CoreSpan span, boolean isTopLevel) { private List getPeerTags(CoreSpan span, String spanKind) { if (ELIGIBLE_SPAN_KINDS_FOR_PEER_AGGREGATION.contains(spanKind)) { - List peerTags = new ArrayList<>(); - for (String peerTag : features.peerTags()) { - Object value = span.getTag(peerTag); + final Set eligiblePeerTags = features.peerTags(); + List peerTags = new ArrayList<>(eligiblePeerTags.size()); + for (String peerTag : eligiblePeerTags) { + Object value = span.unsafeGetTag(peerTag); if (value != null) { final Pair, Function> cacheAndCreator = PEER_TAGS_CACHE.computeIfAbsent(peerTag, PEER_TAGS_CACHE_ADDER); @@ -368,7 +369,7 @@ private List getPeerTags(CoreSpan span, String spanKind) { return peerTags; } else if (SPAN_KIND_INTERNAL.equals(spanKind)) { // in this case only the base service should be aggregated if present - final Object baseService = span.getTag(BASE_SERVICE); + final Object baseService = span.unsafeGetTag(BASE_SERVICE); if (baseService != null) { final Pair, Function> cacheAndCreator = PEER_TAGS_CACHE.computeIfAbsent(BASE_SERVICE, PEER_TAGS_CACHE_ADDER); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreSpan.java index 7c3e65e0d41..df0516c7159 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreSpan.java @@ -57,6 +57,14 @@ public interface CoreSpan> { U getTag(CharSequence name); + default U unsafeGetTag(CharSequence name, U defaultValue) { + return getTag(name, defaultValue); + } + + default U unsafeGetTag(CharSequence name) { + return getTag(name); + } + boolean hasSamplingPriority(); boolean isMeasured(); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java index 106eb57e474..a17f6eb1298 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java @@ -505,6 +505,19 @@ public Object getTag(final String tag) { return context.getTag(tag); } + @Override + @SuppressWarnings("unchecked") + public U unsafeGetTag(CharSequence name, U defaultValue) { + Object tag = unsafeGetTag(name); + return null == tag ? defaultValue : (U) tag; + } + + @Override + @SuppressWarnings("unchecked") + public U unsafeGetTag(CharSequence name) { + return (U) context.unsafeGetTag(String.valueOf(name)); + } + @Override @Nonnull public final DDSpanContext context() {