Skip to content

Commit df3defa

Browse files
committed
Add function calling telemetry
1 parent 7d1d85d commit df3defa

File tree

16 files changed

+805
-155
lines changed

16 files changed

+805
-155
lines changed

aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import com.microsoft.semantickernel.hooks.PreChatCompletionEvent;
5151
import com.microsoft.semantickernel.hooks.PreToolCallEvent;
5252
import com.microsoft.semantickernel.implementation.CollectionUtil;
53+
import com.microsoft.semantickernel.implementation.telemetry.ChatCompletionSpan;
5354
import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry;
5455
import com.microsoft.semantickernel.orchestration.FunctionResult;
5556
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
@@ -69,7 +70,6 @@
6970
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageContentType;
7071
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageImageContent;
7172
import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder;
72-
import io.opentelemetry.api.trace.Span;
7373
import java.io.IOException;
7474
import java.util.ArrayList;
7575
import java.util.Arrays;
@@ -419,26 +419,32 @@ private Mono<ChatMessages> internalChatMessageContentsAsync(
419419
invocationContext)))
420420
.getOptions();
421421

422-
Span span = SemanticKernelTelemetry.startChatCompletionSpan(
423-
getModelId(),
424-
SemanticKernelTelemetry.OPEN_AI_PROVIDER,
425-
options.getMaxTokens(),
426-
options.getTemperature(),
427-
options.getTopP());
428-
return getClient()
429-
.getChatCompletionsWithResponse(getDeploymentName(), options,
430-
OpenAIRequestSettings.getRequestOptions())
431-
.flatMap(completionsResult -> {
432-
if (completionsResult.getStatusCode() >= 400) {
433-
SemanticKernelTelemetry.endSpanWithError(span);
434-
return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR,
435-
"Request failed: " + completionsResult.getStatusCode()));
436-
}
437-
SemanticKernelTelemetry.endSpanWithUsage(span,
438-
completionsResult.getValue().getUsage());
422+
return Mono.deferContextual(contextView -> {
423+
ChatCompletionSpan span = ChatCompletionSpan.startChatCompletionSpan(
424+
SemanticKernelTelemetry.getTelemetry(invocationContext),
425+
contextView,
426+
getModelId(),
427+
SemanticKernelTelemetry.OPEN_AI_PROVIDER,
428+
options.getMaxTokens(),
429+
options.getTemperature(),
430+
options.getTopP());
431+
432+
return getClient()
433+
.getChatCompletionsWithResponse(getDeploymentName(), options,
434+
OpenAIRequestSettings.getRequestOptions())
435+
.contextWrite(span.getReactorContextModifier())
436+
.flatMap(completionsResult -> {
437+
if (completionsResult.getStatusCode() >= 400) {
438+
return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR,
439+
"Request failed: " + completionsResult.getStatusCode()));
440+
}
439441

440-
return Mono.just(completionsResult.getValue());
441-
})
442+
return Mono.just(completionsResult.getValue());
443+
})
444+
.doOnError(span::endSpanWithError)
445+
.doOnSuccess(span::endSpanWithUsage)
446+
.doOnTerminate(span::close);
447+
})
442448
.flatMap(completions -> {
443449

444450
List<ChatResponseMessage> responseMessages = completions

aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAITextGenerationService.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
import com.microsoft.semantickernel.services.StreamingTextContent;
1515
import com.microsoft.semantickernel.services.textcompletion.TextContent;
1616
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
17-
import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry;
18-
import io.opentelemetry.api.trace.Span;
1917
import java.util.Collections;
2018
import java.util.HashMap;
2119
import java.util.List;
@@ -84,23 +82,14 @@ protected Mono<List<TextContent>> internalCompleteTextAsync(
8482

8583
CompletionsOptions completionsOptions = getCompletionsOptions(text, requestSettings);
8684

87-
Span span = SemanticKernelTelemetry.startTextCompletionSpan(
88-
getModelId(),
89-
SemanticKernelTelemetry.OPEN_AI_PROVIDER,
90-
completionsOptions.getMaxTokens(),
91-
completionsOptions.getTemperature(),
92-
completionsOptions.getTopP());
9385
return getClient()
9486
.getCompletionsWithResponse(getDeploymentName(), completionsOptions,
9587
OpenAIRequestSettings.getRequestOptions())
9688
.flatMap(completionsResult -> {
9789
if (completionsResult.getStatusCode() >= 400) {
98-
SemanticKernelTelemetry.endSpanWithError(span);
9990
return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR,
10091
"Request failed: " + completionsResult.getStatusCode()));
10192
}
102-
SemanticKernelTelemetry.endSpanWithUsage(span,
103-
completionsResult.getValue().getUsage());
10493
return Mono.just(completionsResult.getValue());
10594
})
10695
.map(completions -> {

aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/OtelCaptureTest.java

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -75,57 +75,6 @@ public static void shutdown() {
7575
otel.shutdown();
7676
}
7777

78-
@Test
79-
public void otelTextCaptureTest() {
80-
81-
OpenAIAsyncClient openAIAsyncClient = Mockito.mock(OpenAIAsyncClient.class);
82-
83-
CompletionsUsage completionsUsage = Mockito.mock(CompletionsUsage.class);
84-
Mockito.when(completionsUsage.getCompletionTokens()).thenReturn(22);
85-
Mockito.when(completionsUsage.getPromptTokens()).thenReturn(55);
86-
87-
Completions completions = Mockito.mock(Completions.class);
88-
Mockito.when(completions.getUsage()).thenReturn(completionsUsage);
89-
90-
Response<Completions> response = Mockito.mock(Response.class);
91-
Mockito.when(response.getStatusCode()).thenReturn(200);
92-
Mockito.when(response.getValue()).thenReturn(completions);
93-
94-
Mockito.when(openAIAsyncClient.getCompletionsWithResponse(
95-
Mockito.any(),
96-
Mockito.<CompletionsOptions>any(),
97-
Mockito.any())).thenAnswer(invocation -> Mono.just(response));
98-
99-
TextGenerationService client = OpenAITextGenerationService.builder()
100-
.withOpenAIAsyncClient(openAIAsyncClient)
101-
.withModelId("a-model")
102-
.build();
103-
104-
try {
105-
client.getTextContentsAsync(
106-
"foo",
107-
null,
108-
null).block();
109-
} catch (Exception e) {
110-
// Expect to fail
111-
}
112-
113-
Assertions.assertFalse(spans.isEmpty());
114-
Assertions.assertEquals("a-model",
115-
spans.get(0).getAttributes().get(AttributeKey.stringKey("gen_ai.request.model")));
116-
Assertions.assertEquals("text.completions",
117-
spans.get(0).getAttributes().get(AttributeKey.stringKey("gen_ai.operation.name")));
118-
Assertions.assertEquals("openai",
119-
spans.get(0).getAttributes().get(AttributeKey.stringKey("gen_ai.system")));
120-
Assertions.assertEquals(22,
121-
spans.get(0).getAttributes()
122-
.get(AttributeKey.longKey("gen_ai.response.completion_tokens")));
123-
Assertions.assertEquals(55,
124-
spans.get(0).getAttributes()
125-
.get(AttributeKey.longKey("gen_ai.response.prompt_tokens")));
126-
127-
}
128-
12978
@Test
13079
public void otelChatCaptureTest() {
13180
OpenAIAsyncClient openAIAsyncClient = Mockito.mock(OpenAIAsyncClient.class);

samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
</dependencyManagement>
2727

2828
<dependencies>
29+
<dependency>
30+
<groupId>io.opentelemetry.instrumentation</groupId>
31+
<artifactId>opentelemetry-reactor-3.1</artifactId>
32+
<version>2.9.0-alpha</version>
33+
</dependency>
2934
<dependency>
3035
<groupId>com.microsoft.semantic-kernel</groupId>
3136
<artifactId>semantickernel-api</artifactId>
@@ -165,6 +170,7 @@
165170
</executions>
166171
<configuration>
167172
<mainClass>com.microsoft.semantickernel.samples.syntaxexamples.${sample}</mainClass>
173+
<cleanupDaemonThreads>false</cleanupDaemonThreads>
168174
</configuration>
169175
</plugin>
170176
</plugins>

0 commit comments

Comments
 (0)