Skip to content

Commit af8b844

Browse files
authored
Add telemetry for LLMObs manual api span finish calls (#10616)
llmobs: add telemetry for manual api span finish calls Add a test for a non-root span Add has_session_id tag to the llmobs "span.finished" metric Co-authored-by: yury.gribkov <yury.gribkov@datadoghq.com>
1 parent 5c6554f commit af8b844

7 files changed

Lines changed: 180 additions & 75 deletions

File tree

dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import datadog.trace.api.llmobs.LLMObsContext;
99
import datadog.trace.api.llmobs.LLMObsSpan;
1010
import datadog.trace.api.llmobs.LLMObsTags;
11+
import datadog.trace.api.telemetry.LLMObsMetricCollector;
1112
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
1213
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
1314
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
@@ -47,6 +48,7 @@ public class DDLLMObsSpan implements LLMObsSpan {
4748
private final AgentSpan span;
4849
private final String spanKind;
4950
private final ContextScope scope;
51+
private final boolean hasSessionId;
5052

5153
private boolean finished = false;
5254

@@ -68,51 +70,52 @@ public DDLLMObsSpan(
6870
.withServiceName(serviceName)
6971
.withSpanType(DDSpanTypes.LLMOBS);
7072

71-
this.span = spanBuilder.start();
73+
span = spanBuilder.start();
7274

7375
// set UST (unified service tags, env, service, version)
74-
this.span.setTag(ENV, wellKnownTags.getEnv());
75-
this.span.setTag(SERVICE, wellKnownTags.getService());
76-
this.span.setTag(VERSION, wellKnownTags.getVersion());
77-
78-
this.span.setTag(SPAN_KIND, kind);
79-
this.spanKind = kind;
80-
this.span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.ML_APP, mlApp);
81-
if (sessionId != null && !sessionId.isEmpty()) {
82-
this.span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.SESSION_ID, sessionId);
76+
span.setTag(ENV, wellKnownTags.getEnv());
77+
span.setTag(SERVICE, wellKnownTags.getService());
78+
span.setTag(VERSION, wellKnownTags.getVersion());
79+
80+
span.setTag(SPAN_KIND, kind);
81+
spanKind = kind;
82+
span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.ML_APP, mlApp);
83+
this.hasSessionId = sessionId != null && !sessionId.isEmpty();
84+
if (this.hasSessionId) {
85+
span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.SESSION_ID, sessionId);
8386
}
8487

8588
AgentSpanContext parent = LLMObsContext.current();
8689
String parentSpanID = LLMObsContext.ROOT_SPAN_ID;
8790
if (null != parent) {
88-
if (parent.getTraceId() != this.span.getTraceId()) {
91+
if (parent.getTraceId() != span.getTraceId()) {
8992
LOGGER.error(
9093
"trace ID mismatch, retrieved parent from context trace_id={}, span_id={}, started span trace_id={}, span_id={}",
9194
parent.getTraceId(),
9295
parent.getSpanId(),
93-
this.span.getTraceId(),
94-
this.span.getSpanId());
96+
span.getTraceId(),
97+
span.getSpanId());
9598
} else {
9699
parentSpanID = String.valueOf(parent.getSpanId());
97100
}
98101
}
99-
this.span.setTag(LLMOBS_TAG_PREFIX + PARENT_ID_TAG_INTERNAL, parentSpanID);
100-
this.scope = LLMObsContext.attach(this.span.context());
102+
span.setTag(LLMOBS_TAG_PREFIX + PARENT_ID_TAG_INTERNAL, parentSpanID);
103+
scope = LLMObsContext.attach(span.context());
101104
}
102105

103106
@Override
104107
public String toString() {
105108
return super.toString()
106109
+ ", trace_id="
107-
+ this.span.context().getTraceId()
110+
+ span.context().getTraceId()
108111
+ ", span_id="
109-
+ this.span.context().getSpanId()
112+
+ span.context().getSpanId()
110113
+ ", ml_app="
111-
+ this.span.getTag(LLMObsTags.ML_APP)
114+
+ span.getTag(LLMObsTags.ML_APP)
112115
+ ", service="
113-
+ this.span.getServiceName()
116+
+ span.getServiceName()
114117
+ ", span_kind="
115-
+ this.span.getTag(SPAN_KIND);
118+
+ span.getTag(SPAN_KIND);
116119
}
117120

118121
@Override
@@ -121,10 +124,10 @@ public void annotateIO(List<LLMObs.LLMMessage> inputData, List<LLMObs.LLMMessage
121124
return;
122125
}
123126
if (inputData != null && !inputData.isEmpty()) {
124-
this.span.setTag(INPUT, inputData);
127+
span.setTag(INPUT, inputData);
125128
}
126129
if (outputData != null && !outputData.isEmpty()) {
127-
this.span.setTag(OUTPUT, outputData);
130+
span.setTag(OUTPUT, outputData);
128131
}
129132
}
130133

@@ -135,24 +138,24 @@ public void annotateIO(String inputData, String outputData) {
135138
}
136139
boolean wrongSpanKind = false;
137140
if (inputData != null && !inputData.isEmpty()) {
138-
if (Tags.LLMOBS_LLM_SPAN_KIND.equals(this.spanKind)) {
141+
if (Tags.LLMOBS_LLM_SPAN_KIND.equals(spanKind)) {
139142
wrongSpanKind = true;
140143
annotateIO(
141144
Collections.singletonList(LLMObs.LLMMessage.from(LLM_MESSAGE_UNKNOWN_ROLE, inputData)),
142145
null);
143146
} else {
144-
this.span.setTag(INPUT, inputData);
147+
span.setTag(INPUT, inputData);
145148
}
146149
}
147150
if (outputData != null && !outputData.isEmpty()) {
148-
if (Tags.LLMOBS_LLM_SPAN_KIND.equals(this.spanKind)) {
151+
if (Tags.LLMOBS_LLM_SPAN_KIND.equals(spanKind)) {
149152
wrongSpanKind = true;
150153
annotateIO(
151154
null,
152155
Collections.singletonList(
153156
LLMObs.LLMMessage.from(LLM_MESSAGE_UNKNOWN_ROLE, outputData)));
154157
} else {
155-
this.span.setTag(OUTPUT, outputData);
158+
span.setTag(OUTPUT, outputData);
156159
}
157160
}
158161
if (wrongSpanKind) {
@@ -168,7 +171,7 @@ public void setMetadata(Map<String, Object> metadata) {
168171
}
169172
Object value = span.getTag(METADATA);
170173
if (value == null) {
171-
this.span.setTag(METADATA, new HashMap<>(metadata));
174+
span.setTag(METADATA, new HashMap<>(metadata));
172175
return;
173176
}
174177

@@ -178,7 +181,7 @@ public void setMetadata(Map<String, Object> metadata) {
178181
LOGGER.debug(
179182
"unexpected instance type for metadata {}, overwriting for now",
180183
value.getClass().getName());
181-
this.span.setTag(METADATA, new HashMap<>(metadata));
184+
span.setTag(METADATA, new HashMap<>(metadata));
182185
}
183186
}
184187

@@ -188,7 +191,7 @@ public void setMetrics(Map<String, Number> metrics) {
188191
return;
189192
}
190193
for (Map.Entry<String, Number> entry : metrics.entrySet()) {
191-
this.span.setMetric(LLMOBS_METRIC_PREFIX + entry.getKey(), entry.getValue().doubleValue());
194+
span.setMetric(LLMOBS_METRIC_PREFIX + entry.getKey(), entry.getValue().doubleValue());
192195
}
193196
}
194197

@@ -197,23 +200,23 @@ public void setMetric(CharSequence key, int value) {
197200
if (finished) {
198201
return;
199202
}
200-
this.span.setMetric(LLMOBS_METRIC_PREFIX + key, value);
203+
span.setMetric(LLMOBS_METRIC_PREFIX + key, value);
201204
}
202205

203206
@Override
204207
public void setMetric(CharSequence key, long value) {
205208
if (finished) {
206209
return;
207210
}
208-
this.span.setMetric(LLMOBS_METRIC_PREFIX + key, value);
211+
span.setMetric(LLMOBS_METRIC_PREFIX + key, value);
209212
}
210213

211214
@Override
212215
public void setMetric(CharSequence key, double value) {
213216
if (finished) {
214217
return;
215218
}
216-
this.span.setMetric(LLMOBS_METRIC_PREFIX + key, value);
219+
span.setMetric(LLMOBS_METRIC_PREFIX + key, value);
217220
}
218221

219222
@Override
@@ -223,7 +226,7 @@ public void setTags(Map<String, Object> tags) {
223226
}
224227
if (tags != null && !tags.isEmpty()) {
225228
for (Map.Entry<String, Object> entry : tags.entrySet()) {
226-
this.span.setTag(LLMOBS_TAG_PREFIX + entry.getKey(), entry.getValue());
229+
span.setTag(LLMOBS_TAG_PREFIX + entry.getKey(), entry.getValue());
227230
}
228231
}
229232
}
@@ -233,47 +236,47 @@ public void setTag(String key, String value) {
233236
if (finished) {
234237
return;
235238
}
236-
this.span.setTag(LLMOBS_TAG_PREFIX + key, value);
239+
span.setTag(LLMOBS_TAG_PREFIX + key, value);
237240
}
238241

239242
@Override
240243
public void setTag(String key, boolean value) {
241244
if (finished) {
242245
return;
243246
}
244-
this.span.setTag(LLMOBS_TAG_PREFIX + key, value);
247+
span.setTag(LLMOBS_TAG_PREFIX + key, value);
245248
}
246249

247250
@Override
248251
public void setTag(String key, int value) {
249252
if (finished) {
250253
return;
251254
}
252-
this.span.setTag(LLMOBS_TAG_PREFIX + key, value);
255+
span.setTag(LLMOBS_TAG_PREFIX + key, value);
253256
}
254257

255258
@Override
256259
public void setTag(String key, long value) {
257260
if (finished) {
258261
return;
259262
}
260-
this.span.setTag(LLMOBS_TAG_PREFIX + key, value);
263+
span.setTag(LLMOBS_TAG_PREFIX + key, value);
261264
}
262265

263266
@Override
264267
public void setTag(String key, double value) {
265268
if (finished) {
266269
return;
267270
}
268-
this.span.setTag(LLMOBS_TAG_PREFIX + key, value);
271+
span.setTag(LLMOBS_TAG_PREFIX + key, value);
269272
}
270273

271274
@Override
272275
public void setError(boolean error) {
273276
if (finished) {
274277
return;
275278
}
276-
this.span.setError(error);
279+
span.setError(error);
277280
}
278281

279282
@Override
@@ -284,8 +287,8 @@ public void setErrorMessage(String errorMessage) {
284287
if (errorMessage == null || errorMessage.isEmpty()) {
285288
return;
286289
}
287-
this.span.setError(true);
288-
this.span.setErrorMessage(errorMessage);
290+
span.setError(true);
291+
span.setErrorMessage(errorMessage);
289292
}
290293

291294
@Override
@@ -296,27 +299,36 @@ public void addThrowable(Throwable throwable) {
296299
if (throwable == null) {
297300
return;
298301
}
299-
this.span.setError(true);
300-
this.span.addThrowable(throwable);
302+
span.setError(true);
303+
span.addThrowable(throwable);
301304
}
302305

303306
@Override
304307
public void finish() {
305308
if (finished) {
306309
return;
307310
}
308-
this.span.finish();
309-
this.scope.close();
310-
this.finished = true;
311+
span.finish();
312+
scope.close();
313+
finished = true;
314+
boolean isRootSpan = span.getLocalRootSpan() == span;
315+
LLMObsMetricCollector.get()
316+
.recordSpanFinished(
317+
LLM_OBS_INSTRUMENTATION_NAME,
318+
spanKind,
319+
isRootSpan,
320+
false,
321+
span.isError(),
322+
hasSessionId);
311323
}
312324

313325
@Override
314326
public DDTraceId getTraceId() {
315-
return this.span.getTraceId();
327+
return span.getTraceId();
316328
}
317329

318330
@Override
319331
public long getSpanId() {
320-
return this.span.getSpanId();
332+
return span.getSpanId();
321333
}
322334
}

0 commit comments

Comments
 (0)