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 @@ -80,6 +80,9 @@ final class AggregateEntry extends Hashtable.Entry {
DDCaches.newFixedSizeCache(32);
private static final DDCache<String, UTF8BytesString> GRPC_STATUS_CODE_CACHE =
DDCaches.newFixedSizeCache(32);
// Origin is a small fixed vocabulary (synthetics, synthetics-browser, rum, ciapp-test, lambda).
private static final DDCache<String, UTF8BytesString> ORIGIN_CACHE =
DDCaches.newFixedSizeCache(8);

/**
* Outer cache keyed by peer-tag name, with an inner per-name cache keyed by value. The inner
Expand Down Expand Up @@ -107,9 +110,7 @@ final class AggregateEntry extends Hashtable.Entry {
@Nullable private final UTF8BytesString httpEndpoint;
@Nullable private final UTF8BytesString grpcStatusCode;
private final short httpStatusCode;

/** Whether the root span carried the {@code synthetics} origin tag (synthetic-monitoring run). */
private final boolean synthetic;
@Nullable private final UTF8BytesString origin;

/** Whether this span is the trace root ({@code parentId == 0}). */
private final boolean traceRoot;
Expand Down Expand Up @@ -139,7 +140,8 @@ final class AggregateEntry extends Hashtable.Entry {
private int errorCount;
private int hitCount;
private int topLevelCount;
private long duration;
private long okDuration;
private long errorDuration;

/** Hot-path constructor for the producer/consumer flow. Builds UTF8 fields via the caches. */
AggregateEntry(SpanSnapshot s, long keyHash) {
Expand All @@ -154,7 +156,7 @@ final class AggregateEntry extends Hashtable.Entry {
this.httpEndpoint = canonicalizeOptional(HTTP_ENDPOINT_CACHE, s.httpEndpoint);
this.grpcStatusCode = canonicalizeOptional(GRPC_STATUS_CODE_CACHE, s.grpcStatusCode);
this.httpStatusCode = s.httpStatusCode;
this.synthetic = s.synthetic;
this.origin = canonicalizeOptional(ORIGIN_CACHE, s.origin);
this.traceRoot = s.traceRoot;
this.peerTagNames = s.peerTagSchema == null ? null : s.peerTagSchema.names;
this.peerTagValues = s.peerTagValues;
Expand All @@ -174,11 +176,12 @@ void recordOneDuration(long tagAndDuration) {
if ((tagAndDuration & ERROR_TAG) == ERROR_TAG) {
tagAndDuration ^= ERROR_TAG;
errorLatenciesForWrite().accept(tagAndDuration);
errorDuration += tagAndDuration;
++errorCount;
} else {
okLatencies.accept(tagAndDuration);
okDuration += tagAndDuration;
}
duration += tagAndDuration;
}

int getErrorCount() {
Expand All @@ -194,7 +197,15 @@ int getTopLevelCount() {
}

long getDuration() {
return duration;
return okDuration + errorDuration;
}

long getOkDuration() {
return okDuration;
}

long getErrorDuration() {
return errorDuration;
}

Histogram getOkLatencies() {
Expand Down Expand Up @@ -232,7 +243,8 @@ void clear() {
this.errorCount = 0;
this.hitCount = 0;
this.topLevelCount = 0;
this.duration = 0;
this.okDuration = 0;
this.errorDuration = 0;
this.okLatencies.clear();
// errorLatencies stays null on entries that never errored. Only clear if it was allocated.
if (this.errorLatencies != null) {
Expand All @@ -243,7 +255,7 @@ void clear() {
boolean matches(SpanSnapshot s) {
String[] snapshotNames = s.peerTagSchema == null ? null : s.peerTagSchema.names;
return httpStatusCode == s.httpStatusCode
&& synthetic == s.synthetic
&& contentEquals(origin, s.origin)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid keying native stats by arbitrary origin

When the current/native metrics path is used, SerializingMetricWriter.add still serializes only the derived Synthetics boolean and never the full origin, so adding the full origin to the AggregateEntry match/hash makes non-synthetic origins such as rum, ciapp-test, or user-supplied _dd.origin values occupy separate aggregate slots even though they produce identical msgpack keys. A workload receiving many distinct origins can now exhaust maxAggregates and drop client stats; keep this split to the OTLP writer/table or normalize the native key back to the synthetics boolean.

Useful? React with 👍 / 👎.

&& traceRoot == s.traceRoot
&& contentEquals(resource, s.resourceName)
&& contentEquals(service, s.serviceName)
Expand Down Expand Up @@ -284,7 +296,7 @@ static long hashOf(SpanSnapshot s) {
h = LongHashingUtils.addToHash(h, s.serviceNameSource);
h = LongHashingUtils.addToHash(h, s.spanType);
h = LongHashingUtils.addToHash(h, s.httpStatusCode);
h = LongHashingUtils.addToHash(h, s.synthetic);
h = LongHashingUtils.addToHash(h, s.origin);
h = LongHashingUtils.addToHash(h, s.traceRoot);
h = LongHashingUtils.addToHash(h, s.spanKind);
// Always mix in both the schema's content hash and the values' content hash, unconditionally
Expand Down Expand Up @@ -352,8 +364,21 @@ int getHttpStatusCode() {
return httpStatusCode;
}

/**
* The full trace origin, or {@code null} when unset. Used by {@link OtlpStatsMetricWriter} to
* emit {@code datadog.origin}.
*/
@Nullable
UTF8BytesString getOrigin() {
return origin;
}

/**
* Whether the origin is {@code synthetics}. Derived from {@link #origin} for the native msgpack
* writer, which emits a synthetics boolean rather than the full origin.
*/
boolean isSynthetics() {
return synthetic;
return origin != null && "synthetics".contentEquals(origin);
}

boolean isTraceRoot() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ public final class ConflatingMetricsAggregator implements MetricsAggregator, Eve
private static final Map<String, String> DEFAULT_HEADERS =
Collections.singletonMap(DDAgentApi.DATADOG_META_TRACER_VERSION, DDTraceCoreInfo.VERSION);

private static final CharSequence SYNTHETICS_ORIGIN = "synthetics";

private static final SpanKindFilter METRICS_ELIGIBLE_KINDS =
SpanKindFilter.builder()
.includeServer()
Expand Down Expand Up @@ -346,7 +344,7 @@ private boolean publish(CoreSpan<?> span, boolean isTopLevel) {
span.getServiceNameSource(),
spanType,
span.getHttpStatusCode(),
isSynthetic(span),
span.getOrigin(),
span.getParentId() == 0,
spanKind,
peerTagSchema,
Expand Down Expand Up @@ -466,10 +464,6 @@ private static String[] capturePeerTagValues(CoreSpan<?> span, PeerTagSchema sch
return values;
}

private static boolean isSynthetic(CoreSpan<?> span) {
return span.getOrigin() != null && SYNTHETICS_ORIGIN.equals(span.getOrigin().toString());
}

public void stop() {
if (null != cancellation) {
cancellation.cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ final class SpanSnapshot implements InboxItem {
final CharSequence serviceNameSource;
final CharSequence spanType;
final short httpStatusCode;
final boolean synthetic;
final CharSequence origin;

final boolean traceRoot;
final String spanKind;

Expand Down Expand Up @@ -48,7 +49,7 @@ final class SpanSnapshot implements InboxItem {
CharSequence serviceNameSource,
CharSequence spanType,
short httpStatusCode,
boolean synthetic,
CharSequence origin,
boolean traceRoot,
String spanKind,
PeerTagSchema peerTagSchema,
Expand All @@ -63,7 +64,7 @@ final class SpanSnapshot implements InboxItem {
this.serviceNameSource = serviceNameSource;
this.spanType = spanType;
this.httpStatusCode = httpStatusCode;
this.synthetic = synthetic;
this.origin = origin;
this.traceRoot = traceRoot;
this.spanKind = spanKind;
this.peerTagSchema = peerTagSchema;
Expand Down
Loading
Loading