From 8772feceac799424ccfec403500b593aae970fa6 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Tue, 17 Feb 2026 13:32:09 -0800 Subject: [PATCH 1/3] llmobs: add telemetry for manual api span finish calls --- .../trace/llmobs/domain/DDLLMObsSpan.java | 97 ++++++++++--------- .../llmobs/domain/DDLLMObsSpanTest.groovy | 25 +++++ .../datadog/metrics/api/NoOpHistogram.java | 2 +- 3 files changed, 77 insertions(+), 47 deletions(-) diff --git a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java index 56bc1f69c88..47af43eeb1b 100644 --- a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java +++ b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java @@ -8,6 +8,7 @@ import datadog.trace.api.llmobs.LLMObsContext; import datadog.trace.api.llmobs.LLMObsSpan; import datadog.trace.api.llmobs.LLMObsTags; +import datadog.trace.api.telemetry.LLMObsMetricCollector; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; @@ -68,51 +69,51 @@ public DDLLMObsSpan( .withServiceName(serviceName) .withSpanType(DDSpanTypes.LLMOBS); - this.span = spanBuilder.start(); + span = spanBuilder.start(); // set UST (unified service tags, env, service, version) - this.span.setTag(ENV, wellKnownTags.getEnv()); - this.span.setTag(SERVICE, wellKnownTags.getService()); - this.span.setTag(VERSION, wellKnownTags.getVersion()); + span.setTag(ENV, wellKnownTags.getEnv()); + span.setTag(SERVICE, wellKnownTags.getService()); + span.setTag(VERSION, wellKnownTags.getVersion()); - this.span.setTag(SPAN_KIND, kind); - this.spanKind = kind; - this.span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.ML_APP, mlApp); + span.setTag(SPAN_KIND, kind); + spanKind = kind; + span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.ML_APP, mlApp); if (sessionId != null && !sessionId.isEmpty()) { - this.span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.SESSION_ID, sessionId); + span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.SESSION_ID, sessionId); } AgentSpanContext parent = LLMObsContext.current(); String parentSpanID = LLMObsContext.ROOT_SPAN_ID; if (null != parent) { - if (parent.getTraceId() != this.span.getTraceId()) { + if (parent.getTraceId() != span.getTraceId()) { LOGGER.error( "trace ID mismatch, retrieved parent from context trace_id={}, span_id={}, started span trace_id={}, span_id={}", parent.getTraceId(), parent.getSpanId(), - this.span.getTraceId(), - this.span.getSpanId()); + span.getTraceId(), + span.getSpanId()); } else { parentSpanID = String.valueOf(parent.getSpanId()); } } - this.span.setTag(LLMOBS_TAG_PREFIX + PARENT_ID_TAG_INTERNAL, parentSpanID); - this.scope = LLMObsContext.attach(this.span.context()); + span.setTag(LLMOBS_TAG_PREFIX + PARENT_ID_TAG_INTERNAL, parentSpanID); + scope = LLMObsContext.attach(span.context()); } @Override public String toString() { return super.toString() + ", trace_id=" - + this.span.context().getTraceId() + + span.context().getTraceId() + ", span_id=" - + this.span.context().getSpanId() + + span.context().getSpanId() + ", ml_app=" - + this.span.getTag(LLMObsTags.ML_APP) + + span.getTag(LLMObsTags.ML_APP) + ", service=" - + this.span.getServiceName() + + span.getServiceName() + ", span_kind=" - + this.span.getTag(SPAN_KIND); + + span.getTag(SPAN_KIND); } @Override @@ -121,10 +122,10 @@ public void annotateIO(List inputData, List metadata) { } Object value = span.getTag(METADATA); if (value == null) { - this.span.setTag(METADATA, new HashMap<>(metadata)); + span.setTag(METADATA, new HashMap<>(metadata)); return; } @@ -178,7 +179,7 @@ public void setMetadata(Map metadata) { LOGGER.debug( "unexpected instance type for metadata {}, overwriting for now", value.getClass().getName()); - this.span.setTag(METADATA, new HashMap<>(metadata)); + span.setTag(METADATA, new HashMap<>(metadata)); } } @@ -188,7 +189,7 @@ public void setMetrics(Map metrics) { return; } for (Map.Entry entry : metrics.entrySet()) { - this.span.setMetric(LLMOBS_METRIC_PREFIX + entry.getKey(), entry.getValue().doubleValue()); + span.setMetric(LLMOBS_METRIC_PREFIX + entry.getKey(), entry.getValue().doubleValue()); } } @@ -197,7 +198,7 @@ public void setMetric(CharSequence key, int value) { if (finished) { return; } - this.span.setMetric(LLMOBS_METRIC_PREFIX + key, value); + span.setMetric(LLMOBS_METRIC_PREFIX + key, value); } @Override @@ -205,7 +206,7 @@ public void setMetric(CharSequence key, long value) { if (finished) { return; } - this.span.setMetric(LLMOBS_METRIC_PREFIX + key, value); + span.setMetric(LLMOBS_METRIC_PREFIX + key, value); } @Override @@ -213,7 +214,7 @@ public void setMetric(CharSequence key, double value) { if (finished) { return; } - this.span.setMetric(LLMOBS_METRIC_PREFIX + key, value); + span.setMetric(LLMOBS_METRIC_PREFIX + key, value); } @Override @@ -223,7 +224,7 @@ public void setTags(Map tags) { } if (tags != null && !tags.isEmpty()) { for (Map.Entry entry : tags.entrySet()) { - this.span.setTag(LLMOBS_TAG_PREFIX + entry.getKey(), entry.getValue()); + span.setTag(LLMOBS_TAG_PREFIX + entry.getKey(), entry.getValue()); } } } @@ -233,7 +234,7 @@ public void setTag(String key, String value) { if (finished) { return; } - this.span.setTag(LLMOBS_TAG_PREFIX + key, value); + span.setTag(LLMOBS_TAG_PREFIX + key, value); } @Override @@ -241,7 +242,7 @@ public void setTag(String key, boolean value) { if (finished) { return; } - this.span.setTag(LLMOBS_TAG_PREFIX + key, value); + span.setTag(LLMOBS_TAG_PREFIX + key, value); } @Override @@ -249,7 +250,7 @@ public void setTag(String key, int value) { if (finished) { return; } - this.span.setTag(LLMOBS_TAG_PREFIX + key, value); + span.setTag(LLMOBS_TAG_PREFIX + key, value); } @Override @@ -257,7 +258,7 @@ public void setTag(String key, long value) { if (finished) { return; } - this.span.setTag(LLMOBS_TAG_PREFIX + key, value); + span.setTag(LLMOBS_TAG_PREFIX + key, value); } @Override @@ -265,7 +266,7 @@ public void setTag(String key, double value) { if (finished) { return; } - this.span.setTag(LLMOBS_TAG_PREFIX + key, value); + span.setTag(LLMOBS_TAG_PREFIX + key, value); } @Override @@ -273,7 +274,7 @@ public void setError(boolean error) { if (finished) { return; } - this.span.setError(error); + span.setError(error); } @Override @@ -284,8 +285,8 @@ public void setErrorMessage(String errorMessage) { if (errorMessage == null || errorMessage.isEmpty()) { return; } - this.span.setError(true); - this.span.setErrorMessage(errorMessage); + span.setError(true); + span.setErrorMessage(errorMessage); } @Override @@ -296,8 +297,8 @@ public void addThrowable(Throwable throwable) { if (throwable == null) { return; } - this.span.setError(true); - this.span.addThrowable(throwable); + span.setError(true); + span.addThrowable(throwable); } @Override @@ -305,18 +306,22 @@ public void finish() { if (finished) { return; } - this.span.finish(); - this.scope.close(); - this.finished = true; + span.finish(); + scope.close(); + finished = true; + boolean isRootSpan = span.getLocalRootSpan() == span; + LLMObsMetricCollector.get() + .recordSpanFinished( + LLM_OBS_INSTRUMENTATION_NAME, spanKind, isRootSpan, false, span.isError()); } @Override public DDTraceId getTraceId() { - return this.span.getTraceId(); + return span.getTraceId(); } @Override public long getSpanId() { - return this.span.getSpanId(); + return span.getSpanId(); } } diff --git a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy index 7595b51e82a..57fcc2ffde5 100644 --- a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy +++ b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy @@ -4,6 +4,7 @@ import datadog.trace.agent.tooling.TracerInstaller import datadog.trace.api.DDTags import datadog.trace.api.IdGenerationStrategy import datadog.trace.api.WellKnownTags +import datadog.trace.api.telemetry.LLMObsMetricCollector import datadog.trace.api.llmobs.LLMObs import datadog.trace.api.llmobs.LLMObsSpan import datadog.trace.api.llmobs.LLMObsTags @@ -325,6 +326,30 @@ class DDLLMObsSpanTest extends DDSpecification{ "v1" == tagVersion.toString() } + def "finish records span.finished telemetry when LLMObs enabled"() { + setup: + LLMObsMetricCollector collector = LLMObsMetricCollector.get() + collector.drain() + def span = givenALLMObsSpan(Tags.LLMOBS_WORKFLOW_SPAN_KIND, "workflow-span") + + when: + span.finish() + def metrics = collector.drain() + + then: + metrics.size() == 1 + + and: + def m = metrics[0] + m.namespace == 'mlobs' + m.metricName == 'span.finished' + m.type == 'count' + m.value == 1 + m.tags.contains('integration:llmobs') + m.tags.contains('span_kind:workflow') + m.tags.contains('autoinstrumented:0') + } + private LLMObsSpan givenALLMObsSpan(String kind, name){ new DDLLMObsSpan(kind, name, "test-ml-app", null, "test-svc", new WellKnownTags("test-runtime-1", "host-1", "test-env", "test-svc", "v1", "java")) } diff --git a/products/metrics/metrics-api/src/main/java/datadog/metrics/api/NoOpHistogram.java b/products/metrics/metrics-api/src/main/java/datadog/metrics/api/NoOpHistogram.java index 14e6625457c..6645e3bc402 100644 --- a/products/metrics/metrics-api/src/main/java/datadog/metrics/api/NoOpHistogram.java +++ b/products/metrics/metrics-api/src/main/java/datadog/metrics/api/NoOpHistogram.java @@ -53,6 +53,6 @@ public void clear() {} @Override public ByteBuffer serialize() { - return null; + return ByteBuffer.allocate(0); } } From 0535a727f08cd833b80d7cc2ec6ba05593b95cec Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 18 Feb 2026 10:29:36 -0800 Subject: [PATCH 2/3] Add a test for a non-root span --- .../llmobs/domain/DDLLMObsSpanTest.groovy | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy index 57fcc2ffde5..d7caf1030a0 100644 --- a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy +++ b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy @@ -1,5 +1,7 @@ package datadog.trace.llmobs.domain +import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace + import datadog.trace.agent.tooling.TracerInstaller import datadog.trace.api.DDTags import datadog.trace.api.IdGenerationStrategy @@ -62,7 +64,7 @@ class DDLLMObsSpanTest extends DDSpecification{ def "test span simple"() { setup: - def test = givenALLMObsSpan(Tags.LLMOBS_WORKFLOW_SPAN_KIND, "test-span") + def test = llmObsSpan(Tags.LLMOBS_WORKFLOW_SPAN_KIND, "test-span") when: def input = "test input" @@ -136,7 +138,7 @@ class DDLLMObsSpanTest extends DDSpecification{ def "test span with overwrites"() { setup: - def test = givenALLMObsSpan(Tags.LLMOBS_AGENT_SPAN_KIND, "test-span") + def test = llmObsSpan(Tags.LLMOBS_AGENT_SPAN_KIND, "test-span") when: def input = "test input" @@ -221,7 +223,7 @@ class DDLLMObsSpanTest extends DDSpecification{ def "test llm span string input formatted to messages"() { setup: - def test = givenALLMObsSpan(Tags.LLMOBS_LLM_SPAN_KIND, "test-span") + def test = llmObsSpan(Tags.LLMOBS_LLM_SPAN_KIND, "test-span") when: def input = "test input" @@ -272,7 +274,7 @@ class DDLLMObsSpanTest extends DDSpecification{ def "test llm span with messages"() { setup: - def test = givenALLMObsSpan(Tags.LLMOBS_LLM_SPAN_KIND, "test-span") + def test = llmObsSpan(Tags.LLMOBS_LLM_SPAN_KIND, "test-span") when: def inputMsg = LLMObs.LLMMessage.from("user", "input") @@ -330,13 +332,12 @@ class DDLLMObsSpanTest extends DDSpecification{ setup: LLMObsMetricCollector collector = LLMObsMetricCollector.get() collector.drain() - def span = givenALLMObsSpan(Tags.LLMOBS_WORKFLOW_SPAN_KIND, "workflow-span") when: - span.finish() - def metrics = collector.drain() + llmObsSpan(Tags.LLMOBS_WORKFLOW_SPAN_KIND, "workflow-span").finish() then: + def metrics = collector.drain() metrics.size() == 1 and: @@ -348,9 +349,37 @@ class DDLLMObsSpanTest extends DDSpecification{ m.tags.contains('integration:llmobs') m.tags.contains('span_kind:workflow') m.tags.contains('autoinstrumented:0') + m.tags.contains('is_root_span:1') + } + + def "finish records span.finished telemetry for non-root span when LLMObs enabled"() { + setup: + LLMObsMetricCollector collector = LLMObsMetricCollector.get() + collector.drain() + + when: + runUnderTrace("parent") { + llmObsSpan(Tags.LLMOBS_LLM_SPAN_KIND, "child-llm").finish() + } + + then: + def metrics = collector.drain() + metrics.size() == 1 + + and: + def m = metrics[0] + m.namespace == 'mlobs' + m.metricName == 'span.finished' + m.type == 'count' + m.value == 1 + m.tags.contains('integration:llmobs') + m.tags.contains('span_kind:llm') + m.tags.contains('autoinstrumented:0') + m.tags.contains('is_root_span:0') } - private LLMObsSpan givenALLMObsSpan(String kind, name){ - new DDLLMObsSpan(kind, name, "test-ml-app", null, "test-svc", new WellKnownTags("test-runtime-1", "host-1", "test-env", "test-svc", "v1", "java")) + private LLMObsSpan llmObsSpan(String kind, name) { + def tags = new WellKnownTags("test-runtime-1", "host-1", "test-env", "test-svc", "v1", "java") + new DDLLMObsSpan(kind, name, "test-ml-app", null, "test-svc", tags) } } From e566c2e7fd1e617c95b88e5a7fa5683b4db71faf Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 18 Feb 2026 10:47:07 -0800 Subject: [PATCH 3/3] Add has_session_id tag to the llmobs "span.finished" metric --- .../trace/llmobs/domain/DDLLMObsSpan.java | 11 +++++-- .../llmobs/domain/DDLLMObsSpanTest.groovy | 30 ++++++++++++++++++- .../openai_java/OpenAiDecorator.java | 2 +- .../api/telemetry/LLMObsMetricCollector.java | 10 +++++-- .../LLMObsMetricCollectorTest.groovy | 15 ++++++---- .../LLMObsMetricPeriodicActionTest.groovy | 24 ++++++++------- 6 files changed, 69 insertions(+), 23 deletions(-) diff --git a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java index 47af43eeb1b..ab337bd6923 100644 --- a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java +++ b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java @@ -48,6 +48,7 @@ public class DDLLMObsSpan implements LLMObsSpan { private final AgentSpan span; private final String spanKind; private final ContextScope scope; + private final boolean hasSessionId; private boolean finished = false; @@ -79,7 +80,8 @@ public DDLLMObsSpan( span.setTag(SPAN_KIND, kind); spanKind = kind; span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.ML_APP, mlApp); - if (sessionId != null && !sessionId.isEmpty()) { + this.hasSessionId = sessionId != null && !sessionId.isEmpty(); + if (this.hasSessionId) { span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.SESSION_ID, sessionId); } @@ -312,7 +314,12 @@ public void finish() { boolean isRootSpan = span.getLocalRootSpan() == span; LLMObsMetricCollector.get() .recordSpanFinished( - LLM_OBS_INSTRUMENTATION_NAME, spanKind, isRootSpan, false, span.isError()); + LLM_OBS_INSTRUMENTATION_NAME, + spanKind, + isRootSpan, + false, + span.isError(), + hasSessionId); } @Override diff --git a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy index d7caf1030a0..e667e3599d6 100644 --- a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy +++ b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy @@ -378,8 +378,36 @@ class DDLLMObsSpanTest extends DDSpecification{ m.tags.contains('is_root_span:0') } + def "span has expected session tag and telemetry has #expectedHasSessionIdTag"() { + setup: + LLMObsMetricCollector collector = LLMObsMetricCollector.get() + collector.drain() + + when: + llmObsSpan(Tags.LLMOBS_WORKFLOW_SPAN_KIND, "workflow-span", sessionId).finish() + + then: + def metrics = collector.drain() + metrics.size() == 1 + + and: + def m = metrics[0] + m.namespace == 'mlobs' + m.metricName == 'span.finished' + m.tags.contains(expectedHasSessionIdTag) + + where: + sessionId | expectedHasSessionIdTag + "session-123" | "has_session_id:1" + null | "has_session_id:0" + } + private LLMObsSpan llmObsSpan(String kind, name) { + llmObsSpan(kind, name, null) + } + + private LLMObsSpan llmObsSpan(String kind, name, String sessionId) { def tags = new WellKnownTags("test-runtime-1", "host-1", "test-env", "test-svc", "v1", "java") - new DDLLMObsSpan(kind, name, "test-ml-app", null, "test-svc", tags) + new DDLLMObsSpan(kind, name, "test-ml-app", sessionId, "test-svc", tags) } } diff --git a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java index 331269bad83..e6fca7e8979 100644 --- a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java +++ b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java @@ -116,7 +116,7 @@ public AgentSpan beforeFinish(AgentSpan span) { String spanKind = spanKindTag.toString(); boolean isRootSpan = span.getLocalRootSpan() == span; LLMObsMetricCollector.get() - .recordSpanFinished(INTEGRATION, spanKind, isRootSpan, true, span.isError()); + .recordSpanFinished(INTEGRATION, spanKind, isRootSpan, true, span.isError(), false); } } return super.beforeFinish(span); diff --git a/internal-api/src/main/java/datadog/trace/api/telemetry/LLMObsMetricCollector.java b/internal-api/src/main/java/datadog/trace/api/telemetry/LLMObsMetricCollector.java index 4325c2ef197..f43d92cb741 100644 --- a/internal-api/src/main/java/datadog/trace/api/telemetry/LLMObsMetricCollector.java +++ b/internal-api/src/main/java/datadog/trace/api/telemetry/LLMObsMetricCollector.java @@ -32,6 +32,8 @@ public static LLMObsMetricCollector get() { private static final String AUTOINSTRUMENTED_FALSE = "autoinstrumented:0"; private static final String ERROR_TRUE = "error:1"; private static final String ERROR_FALSE = "error:0"; + private static final String HAS_SESSION_ID_TRUE = "has_session_id:1"; + private static final String HAS_SESSION_ID_FALSE = "has_session_id:0"; private final BlockingQueue metricsQueue; private final DDCache integrationTagCache; @@ -51,13 +53,15 @@ private LLMObsMetricCollector() { * @param isRootSpan whether this is a root span * @param isAutoInstrumented whether this span was auto-instrumented * @param hasError whether the span had an error + * @param hasSessionId whether a session id was provided for this span */ public void recordSpanFinished( String integration, String spanKind, boolean isRootSpan, boolean isAutoInstrumented, - boolean hasError) { + boolean hasError, + boolean hasSessionId) { String integrationTag = integrationTagCache.computeIfAbsent(integration, key -> "integration:" + key); String spanKindTag = spanKindTagCache.computeIfAbsent(spanKind, key -> "span_kind:" + key); @@ -68,8 +72,8 @@ public void recordSpanFinished( spanKindTag, isRootSpan ? IS_ROOT_SPAN_TRUE : IS_ROOT_SPAN_FALSE, isAutoInstrumented ? AUTOINSTRUMENTED_TRUE : AUTOINSTRUMENTED_FALSE, - hasError ? ERROR_TRUE : ERROR_FALSE); - + hasError ? ERROR_TRUE : ERROR_FALSE, + hasSessionId ? HAS_SESSION_ID_TRUE : HAS_SESSION_ID_FALSE); LLMObsMetric metric = new LLMObsMetric(METRIC_NAMESPACE, true, SPAN_FINISHED_METRIC, COUNT_METRIC_TYPE, 1L, tags); if (!metricsQueue.offer(metric)) { diff --git a/internal-api/src/test/groovy/datadog/trace/api/telemetry/LLMObsMetricCollectorTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/telemetry/LLMObsMetricCollectorTest.groovy index 16264e84e32..e3927c03900 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/telemetry/LLMObsMetricCollectorTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/telemetry/LLMObsMetricCollectorTest.groovy @@ -20,9 +20,9 @@ class LLMObsMetricCollectorTest extends DDSpecification { def "record and drain span finished metrics"() { when: - collector.recordSpanFinished("openai", "llm", true, true, false) - collector.recordSpanFinished("openai", "llm", false, true, false) - collector.recordSpanFinished("anthropic", "embedding", true, false, true) + collector.recordSpanFinished("openai", "llm", true, true, false, false) + collector.recordSpanFinished("openai", "llm", false, true, false, true) + collector.recordSpanFinished("anthropic", "embedding", true, false, true, false) collector.prepareMetrics() def metrics = collector.drain() @@ -39,7 +39,8 @@ class LLMObsMetricCollectorTest extends DDSpecification { 'span_kind:llm', 'is_root_span:1', 'autoinstrumented:1', - 'error:0' + 'error:0', + 'has_session_id:0' ].sort() def metric2 = metrics[1] @@ -52,7 +53,8 @@ class LLMObsMetricCollectorTest extends DDSpecification { 'span_kind:llm', 'is_root_span:0', 'autoinstrumented:1', - 'error:0' + 'error:0', + 'has_session_id:1' ].toSet() def metric3 = metrics[2] @@ -65,7 +67,8 @@ class LLMObsMetricCollectorTest extends DDSpecification { 'span_kind:embedding', 'is_root_span:1', 'autoinstrumented:0', - 'error:1' + 'error:1', + 'has_session_id:0' ].toSet() } } diff --git a/telemetry/src/test/groovy/datadog/telemetry/metric/LLMObsMetricPeriodicActionTest.groovy b/telemetry/src/test/groovy/datadog/telemetry/metric/LLMObsMetricPeriodicActionTest.groovy index 4eb5567491b..887cf766280 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/metric/LLMObsMetricPeriodicActionTest.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/metric/LLMObsMetricPeriodicActionTest.groovy @@ -17,9 +17,9 @@ class LLMObsMetricPeriodicActionTest extends DDSpecification { void 'test multiple span finished metrics with different tags'() { when: - collector.recordSpanFinished('openai', 'llm', true, true, false) - collector.recordSpanFinished('openai', 'llm', false, true, false) - collector.recordSpanFinished('anthropic', 'embedding', true, false, true) + collector.recordSpanFinished('openai', 'llm', true, true, false, true) + collector.recordSpanFinished('openai', 'llm', false, true, false, false) + collector.recordSpanFinished('anthropic', 'embedding', true, false, true, false) periodicAction.doIteration(telemetryService) then: @@ -31,7 +31,8 @@ class LLMObsMetricPeriodicActionTest extends DDSpecification { 'span_kind:llm', 'is_root_span:1', 'autoinstrumented:1', - 'error:0' + 'error:0', + 'has_session_id:1' ].toSet() }) 1 * telemetryService.addMetric({ Metric metric -> @@ -42,7 +43,8 @@ class LLMObsMetricPeriodicActionTest extends DDSpecification { 'span_kind:llm', 'is_root_span:0', 'autoinstrumented:1', - 'error:0' + 'error:0', + 'has_session_id:0' ].toSet() }) 1 * telemetryService.addMetric({ Metric metric -> @@ -53,7 +55,8 @@ class LLMObsMetricPeriodicActionTest extends DDSpecification { 'span_kind:embedding', 'is_root_span:1', 'autoinstrumented:0', - 'error:1' + 'error:1', + 'has_session_id:0' ].toSet() }) 0 * _ @@ -61,9 +64,9 @@ class LLMObsMetricPeriodicActionTest extends DDSpecification { void 'test aggregation of identical metrics'() { when: - collector.recordSpanFinished('openai', 'llm', true, true, false) - collector.recordSpanFinished('openai', 'llm', true, true, false) - collector.recordSpanFinished('openai', 'llm', true, true, false) + collector.recordSpanFinished('openai', 'llm', true, true, false, false) + collector.recordSpanFinished('openai', 'llm', true, true, false, false) + collector.recordSpanFinished('openai', 'llm', true, true, false, false) periodicAction.doIteration(telemetryService) then: @@ -77,7 +80,8 @@ class LLMObsMetricPeriodicActionTest extends DDSpecification { 'span_kind:llm', 'is_root_span:1', 'autoinstrumented:1', - 'error:0' + 'error:0', + 'has_session_id:0' ].toSet() }) 0 * _