Skip to content

Commit f6ed413

Browse files
gary-huangNayeem Kamalnayeem-kamal
authored
LLM Obs SDK use context API for parent children span linkage (#8711)
* add APIs for llm obs * add llm message class to support llm spans * add llm message class to support llm spans * impl llmobs agent and llmobs apis * support llm messages with tool calls * handle default model name and provider * rm unneeded file * impl llmobs agent and llmobs apis * impl llmobs agent * working writer * add support for llm message and tool calls * impl llmobs agent and llmobs apis * use new ctx api to track parent span * cleaned up whitespace * resolve merge conflicts * remaining merge conflicts * fix bad method call * fixed llmobs intake creation if llmobs not enabled * removed print statements * ran spotless * added tests for llmobsspanmapper * fixed coverage for tags --------- Co-authored-by: Nayeem Kamal <[email protected]> Co-authored-by: Nayeem Kamal <[email protected]>
1 parent f877866 commit f6ed413

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package datadog.trace.llmobs.domain;
22

3+
import datadog.context.ContextScope;
34
import datadog.trace.api.DDSpanTypes;
45
import datadog.trace.api.llmobs.LLMObs;
56
import datadog.trace.api.llmobs.LLMObsSpan;
67
import datadog.trace.api.llmobs.LLMObsTags;
78
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
9+
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
810
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
911
import datadog.trace.bootstrap.instrumentation.api.Tags;
1012
import java.util.Collections;
@@ -29,13 +31,15 @@ public class DDLLMObsSpan implements LLMObsSpan {
2931
private static final String OUTPUT = LLMOBS_TAG_PREFIX + "output";
3032
private static final String SPAN_KIND = LLMOBS_TAG_PREFIX + Tags.SPAN_KIND;
3133
private static final String METADATA = LLMOBS_TAG_PREFIX + LLMObsTags.METADATA;
34+
private static final String PARENT_ID_TAG_INTERNAL = "parent_id";
3235

3336
private static final String LLM_OBS_INSTRUMENTATION_NAME = "llmobs";
3437

3538
private static final Logger LOGGER = LoggerFactory.getLogger(DDLLMObsSpan.class);
3639

3740
private final AgentSpan span;
3841
private final String spanKind;
42+
private final ContextScope scope;
3943

4044
private boolean finished = false;
4145

@@ -63,6 +67,24 @@ public DDLLMObsSpan(
6367
if (sessionId != null && !sessionId.isEmpty()) {
6468
this.span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.SESSION_ID, sessionId);
6569
}
70+
71+
AgentSpanContext parent = LLMObsState.getLLMObsParentContext();
72+
String parentSpanID = LLMObsState.ROOT_SPAN_ID;
73+
if (null != parent) {
74+
if (parent.getTraceId() != this.span.getTraceId()) {
75+
LOGGER.error(
76+
"trace ID mismatch, retrieved parent from context trace_id={}, span_id={}, started span trace_id={}, span_id={}",
77+
parent.getTraceId(),
78+
parent.getSpanId(),
79+
this.span.getTraceId(),
80+
this.span.getSpanId());
81+
} else {
82+
parentSpanID = String.valueOf(parent.getSpanId());
83+
}
84+
}
85+
this.span.setTag(LLMOBS_TAG_PREFIX + PARENT_ID_TAG_INTERNAL, parentSpanID);
86+
this.scope = LLMObsState.attach();
87+
LLMObsState.setLLMObsParentContext(this.span.context());
6688
}
6789

6890
@Override
@@ -271,6 +293,7 @@ public void finish() {
271293
return;
272294
}
273295
this.span.finish();
296+
this.scope.close();
274297
this.finished = true;
275298
}
276299
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package datadog.trace.llmobs.domain;
2+
3+
import datadog.context.Context;
4+
import datadog.context.ContextKey;
5+
import datadog.context.ContextScope;
6+
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
7+
8+
public class LLMObsState {
9+
public static final String ROOT_SPAN_ID = "undefined";
10+
11+
private static final ContextKey<LLMObsState> CONTEXT_KEY = ContextKey.named("llmobs_span");
12+
13+
private AgentSpanContext parentSpanID;
14+
15+
public static ContextScope attach() {
16+
return Context.current().with(CONTEXT_KEY, new LLMObsState()).attach();
17+
}
18+
19+
private static LLMObsState fromContext() {
20+
return Context.current().get(CONTEXT_KEY);
21+
}
22+
23+
public static AgentSpanContext getLLMObsParentContext() {
24+
LLMObsState state = fromContext();
25+
if (state != null) {
26+
return state.parentSpanID;
27+
}
28+
return null;
29+
}
30+
31+
public static void setLLMObsParentContext(AgentSpanContext llmObsParentContext) {
32+
LLMObsState state = fromContext();
33+
if (state != null) {
34+
state.parentSpanID = llmObsParentContext;
35+
}
36+
}
37+
}

dd-trace-core/src/main/java/datadog/trace/llmobs/writer/ddintake/LLMObsSpanMapper.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public class LLMObsSpanMapper implements RemoteMapper {
7575
private static final byte[] LLM_TOOL_CALL_ARGUMENTS =
7676
"arguments".getBytes(StandardCharsets.UTF_8);
7777

78+
private static final String PARENT_ID_TAG_INTERNAL_FULL = LLMOBS_TAG_PREFIX + "parent_id";
79+
7880
private final LLMObsSpanMapper.MetaWriter metaWriter = new MetaWriter();
7981
private final int size;
8082

@@ -113,8 +115,8 @@ public void map(List<? extends CoreSpan<?>> trace, Writable writable) {
113115

114116
// 3
115117
writable.writeUTF8(PARENT_ID);
116-
// TODO fix after parent ID tracking is in place
117-
writable.writeString("undefined", null);
118+
writable.writeString(span.getTag(PARENT_ID_TAG_INTERNAL_FULL), null);
119+
span.removeTag(PARENT_ID_TAG_INTERNAL_FULL);
118120

119121
// 4
120122
writable.writeUTF8(NAME);

0 commit comments

Comments
 (0)