Skip to content

Commit 6c5d01c

Browse files
Remove direct dependency to the OTel SDK
This removes the ObservationHandlers that have direct dependency on the OTel SDK. In practice, this means that those events that these handlers add to the spans will not be available after this change but since these handlers have "fallbacks" in the form of ObservationFilters, the data they added is still available as tags (instead of events) if the right properties are enabled (see the auto-configuration). The handler-filter pairs are: - ChatModelPromptContentObservationHandler -> ChatModelPromptContentObservationFilter - ChatModelCompletionObservationHandler -> ChatModelCompletionObservationFilter - VectorStoreQueryResponseObservationHandler -> VectorStoreQueryResponseObservationFilter
1 parent 52675d8 commit 6c5d01c

File tree

21 files changed

+30
-924
lines changed

21 files changed

+30
-924
lines changed

auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/pom.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@
3030
<version>${project.parent.version}</version>
3131
</dependency>
3232

33-
<dependency>
34-
<groupId>io.micrometer</groupId>
35-
<artifactId>micrometer-tracing-bridge-otel</artifactId>
36-
<optional>true</optional>
37-
</dependency>
38-
3933
<!-- Boot dependencies -->
4034
<dependency>
4135
<groupId>org.springframework.boot</groupId>

auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfiguration.java

Lines changed: 17 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,29 @@
1616

1717
package org.springframework.ai.model.chat.observation.autoconfigure;
1818

19-
import java.util.List;
20-
2119
import io.micrometer.core.instrument.MeterRegistry;
2220
import io.micrometer.tracing.Tracer;
23-
import io.micrometer.tracing.otel.bridge.OtelTracer;
2421
import org.slf4j.Logger;
2522
import org.slf4j.LoggerFactory;
26-
2723
import org.springframework.ai.chat.client.advisor.observation.AdvisorObservationContext;
2824
import org.springframework.ai.chat.client.observation.ChatClientObservationContext;
2925
import org.springframework.ai.chat.model.ChatModel;
3026
import org.springframework.ai.chat.observation.ChatModelCompletionObservationFilter;
31-
import org.springframework.ai.chat.observation.ChatModelCompletionObservationHandler;
3227
import org.springframework.ai.chat.observation.ChatModelMeterObservationHandler;
3328
import org.springframework.ai.chat.observation.ChatModelObservationContext;
3429
import org.springframework.ai.chat.observation.ChatModelPromptContentObservationFilter;
35-
import org.springframework.ai.chat.observation.ChatModelPromptContentObservationHandler;
3630
import org.springframework.ai.embedding.observation.EmbeddingModelObservationContext;
3731
import org.springframework.ai.image.observation.ImageModelObservationContext;
3832
import org.springframework.ai.model.observation.ErrorLoggingObservationHandler;
3933
import org.springframework.beans.factory.ObjectProvider;
4034
import org.springframework.boot.autoconfigure.AutoConfiguration;
41-
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
42-
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
43-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
44-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
45-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
35+
import org.springframework.boot.autoconfigure.condition.*;
4636
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4737
import org.springframework.context.annotation.Bean;
4838
import org.springframework.context.annotation.Configuration;
4939

40+
import java.util.List;
41+
5042
/**
5143
* Auto-configuration for Spring AI chat model observations.
5244
*
@@ -78,60 +70,22 @@ ChatModelMeterObservationHandler chatModelMeterObservationHandler(ObjectProvider
7870
return new ChatModelMeterObservationHandler(meterRegistry.getObject());
7971
}
8072

81-
/**
82-
* The chat content is typically too big to be included in an observation as span
83-
* attributes. That's why the preferred way to store it is as span events, which are
84-
* supported by OpenTelemetry but not yet surfaced through the Micrometer APIs. This
85-
* primary/fallback configuration is a temporary solution until
86-
* https://github.com/micrometer-metrics/micrometer/issues/5238 is delivered.
87-
*/
88-
@Configuration(proxyBeanMethods = false)
89-
@ConditionalOnClass(OtelTracer.class)
90-
@ConditionalOnBean(OtelTracer.class)
91-
static class PrimaryChatContentObservationConfiguration {
92-
93-
@Bean
94-
@ConditionalOnMissingBean
95-
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-prompt",
96-
havingValue = "true")
97-
ChatModelPromptContentObservationHandler chatModelPromptContentObservationHandler() {
98-
logPromptContentWarning();
99-
return new ChatModelPromptContentObservationHandler();
100-
}
101-
102-
@Bean
103-
@ConditionalOnMissingBean
104-
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-completion",
105-
havingValue = "true")
106-
ChatModelCompletionObservationHandler chatModelCompletionObservationHandler() {
107-
logCompletionWarning();
108-
return new ChatModelCompletionObservationHandler();
109-
}
110-
73+
@Bean
74+
@ConditionalOnMissingBean
75+
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-prompt",
76+
havingValue = "true")
77+
ChatModelPromptContentObservationFilter chatModelPromptObservationFilter() {
78+
logPromptContentWarning();
79+
return new ChatModelPromptContentObservationFilter();
11180
}
11281

113-
@Configuration(proxyBeanMethods = false)
114-
@ConditionalOnMissingClass("io.micrometer.tracing.otel.bridge.OtelTracer")
115-
static class FallbackChatContentObservationConfiguration {
116-
117-
@Bean
118-
@ConditionalOnMissingBean
119-
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-prompt",
120-
havingValue = "true")
121-
ChatModelPromptContentObservationFilter chatModelPromptObservationFilter() {
122-
logPromptContentWarning();
123-
return new ChatModelPromptContentObservationFilter();
124-
}
125-
126-
@Bean
127-
@ConditionalOnMissingBean
128-
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-completion",
129-
havingValue = "true")
130-
ChatModelCompletionObservationFilter chatModelCompletionObservationFilter() {
131-
logCompletionWarning();
132-
return new ChatModelCompletionObservationFilter();
133-
}
134-
82+
@Bean
83+
@ConditionalOnMissingBean
84+
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-completion",
85+
havingValue = "true")
86+
ChatModelCompletionObservationFilter chatModelCompletionObservationFilter() {
87+
logCompletionWarning();
88+
return new ChatModelCompletionObservationFilter();
13589
}
13690

13791
@Configuration(proxyBeanMethods = false)

auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/test/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfigurationTests.java

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,10 @@
1717
package org.springframework.ai.model.chat.observation.autoconfigure;
1818

1919
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
20-
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
21-
import io.micrometer.tracing.otel.bridge.OtelTracer;
22-
import io.opentelemetry.api.OpenTelemetry;
2320
import org.junit.jupiter.api.Test;
24-
2521
import org.springframework.ai.chat.observation.ChatModelCompletionObservationFilter;
26-
import org.springframework.ai.chat.observation.ChatModelCompletionObservationHandler;
2722
import org.springframework.ai.chat.observation.ChatModelMeterObservationHandler;
2823
import org.springframework.ai.chat.observation.ChatModelPromptContentObservationFilter;
29-
import org.springframework.ai.chat.observation.ChatModelPromptContentObservationHandler;
3024
import org.springframework.boot.autoconfigure.AutoConfigurations;
3125
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3226

@@ -59,50 +53,10 @@ void promptFilterDefault() {
5953
.run(context -> assertThat(context).doesNotHaveBean(ChatModelPromptContentObservationFilter.class));
6054
}
6155

62-
@Test
63-
void promptHandlerDefault() {
64-
this.contextRunner
65-
.run(context -> assertThat(context).doesNotHaveBean(ChatModelPromptContentObservationHandler.class));
66-
}
67-
68-
@Test
69-
void promptHandlerEnabled() {
70-
this.contextRunner
71-
.withBean(OtelTracer.class, OpenTelemetry.noop().getTracer("test"), new OtelCurrentTraceContext(), null)
72-
.withPropertyValues("spring.ai.chat.observations.include-prompt=true")
73-
.run(context -> assertThat(context).hasSingleBean(ChatModelPromptContentObservationHandler.class));
74-
}
75-
76-
@Test
77-
void promptHandlerDisabled() {
78-
this.contextRunner.withPropertyValues("spring.ai.chat.observations.include-prompt=true")
79-
.run(context -> assertThat(context).doesNotHaveBean(ChatModelPromptContentObservationHandler.class));
80-
}
81-
8256
@Test
8357
void completionFilterDefault() {
8458
this.contextRunner
8559
.run(context -> assertThat(context).doesNotHaveBean(ChatModelCompletionObservationFilter.class));
8660
}
8761

88-
@Test
89-
void completionHandlerDefault() {
90-
this.contextRunner
91-
.run(context -> assertThat(context).doesNotHaveBean(ChatModelCompletionObservationHandler.class));
92-
}
93-
94-
@Test
95-
void completionHandlerEnabled() {
96-
this.contextRunner
97-
.withBean(OtelTracer.class, OpenTelemetry.noop().getTracer("test"), new OtelCurrentTraceContext(), null)
98-
.withPropertyValues("spring.ai.chat.observations.include-completion=true")
99-
.run(context -> assertThat(context).hasSingleBean(ChatModelCompletionObservationHandler.class));
100-
}
101-
102-
@Test
103-
void completionHandlerDisabled() {
104-
this.contextRunner.withPropertyValues("spring.ai.chat.observations.include-completion=true")
105-
.run(context -> assertThat(context).doesNotHaveBean(ChatModelCompletionObservationHandler.class));
106-
}
107-
10862
}

auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/pom.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@
4343
<artifactId>spring-ai-vector-store</artifactId>
4444
<version>${project.parent.version}</version>
4545
</dependency>
46-
<dependency>
47-
<groupId>io.micrometer</groupId>
48-
<artifactId>micrometer-tracing-bridge-otel</artifactId>
49-
<optional>true</optional>
50-
</dependency>
5146
<dependency>
5247
<groupId>org.springframework.boot</groupId>
5348
<artifactId>spring-boot-starter</artifactId>

auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/main/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfiguration.java

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,16 @@
1616

1717
package org.springframework.ai.vectorstore.observation.autoconfigure;
1818

19-
import io.micrometer.tracing.otel.bridge.OtelTracer;
2019
import org.slf4j.Logger;
2120
import org.slf4j.LoggerFactory;
22-
2321
import org.springframework.ai.vectorstore.VectorStore;
2422
import org.springframework.ai.vectorstore.observation.VectorStoreQueryResponseObservationFilter;
25-
import org.springframework.ai.vectorstore.observation.VectorStoreQueryResponseObservationHandler;
2623
import org.springframework.boot.autoconfigure.AutoConfiguration;
27-
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2824
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2925
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
30-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
3126
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3227
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3328
import org.springframework.context.annotation.Bean;
34-
import org.springframework.context.annotation.Configuration;
3529

3630
/**
3731
* Auto-configuration for Spring AI vector store observations.
@@ -53,42 +47,13 @@ private static void logQueryResponseContentWarning() {
5347
"You have enabled the inclusion of the query response content in the observations, with the risk of exposing sensitive or private information. Please, be careful!");
5448
}
5549

56-
/**
57-
* The query response content is typically too big to be included in an observation as
58-
* span attributes. That's why the preferred way to store it is as span events, which
59-
* are supported by OpenTelemetry but not yet surfaced through the Micrometer APIs.
60-
* This primary/fallback configuration is a temporary solution until
61-
* https://github.com/micrometer-metrics/micrometer/issues/5238 is delivered.
62-
*/
63-
@Configuration(proxyBeanMethods = false)
64-
@ConditionalOnClass(OtelTracer.class)
65-
@ConditionalOnBean(OtelTracer.class)
66-
static class PrimaryVectorStoreQueryResponseContentObservationConfiguration {
67-
68-
@Bean
69-
@ConditionalOnMissingBean
70-
@ConditionalOnProperty(prefix = VectorStoreObservationProperties.CONFIG_PREFIX, name = "include-query-response",
71-
havingValue = "true")
72-
VectorStoreQueryResponseObservationHandler vectorStoreQueryResponseObservationHandler() {
73-
logQueryResponseContentWarning();
74-
return new VectorStoreQueryResponseObservationHandler();
75-
}
76-
77-
}
78-
79-
@Configuration(proxyBeanMethods = false)
80-
@ConditionalOnMissingClass("io.micrometer.tracing.otel.bridge.OtelTracer")
81-
static class FallbackVectorStoreQueryResponseContentObservationConfiguration {
82-
83-
@Bean
84-
@ConditionalOnMissingBean
85-
@ConditionalOnProperty(prefix = VectorStoreObservationProperties.CONFIG_PREFIX, name = "include-query-response",
86-
havingValue = "true")
87-
VectorStoreQueryResponseObservationFilter vectorStoreQueryResponseContentObservationFilter() {
88-
logQueryResponseContentWarning();
89-
return new VectorStoreQueryResponseObservationFilter();
90-
}
91-
50+
@Bean
51+
@ConditionalOnMissingBean
52+
@ConditionalOnProperty(prefix = VectorStoreObservationProperties.CONFIG_PREFIX, name = "include-query-response",
53+
havingValue = "true")
54+
VectorStoreQueryResponseObservationFilter vectorStoreQueryResponseContentObservationFilter() {
55+
logQueryResponseContentWarning();
56+
return new VectorStoreQueryResponseObservationFilter();
9257
}
9358

9459
}

auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/test/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfigurationTests.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,8 @@
1616

1717
package org.springframework.ai.vectorstore.observation.autoconfigure;
1818

19-
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
20-
import io.micrometer.tracing.otel.bridge.OtelTracer;
21-
import io.opentelemetry.api.OpenTelemetry;
2219
import org.junit.jupiter.api.Test;
23-
2420
import org.springframework.ai.vectorstore.observation.VectorStoreQueryResponseObservationFilter;
25-
import org.springframework.ai.vectorstore.observation.VectorStoreQueryResponseObservationHandler;
2621
import org.springframework.boot.autoconfigure.AutoConfigurations;
2722
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2823

@@ -45,17 +40,9 @@ void queryResponseFilterDefault() {
4540
}
4641

4742
@Test
48-
void queryResponseHandlerDefault() {
49-
this.contextRunner
50-
.run(context -> assertThat(context).doesNotHaveBean(VectorStoreQueryResponseObservationHandler.class));
51-
}
52-
53-
@Test
54-
void queryResponseHandlerEnabled() {
55-
this.contextRunner
56-
.withBean(OtelTracer.class, OpenTelemetry.noop().getTracer("test"), new OtelCurrentTraceContext(), null)
57-
.withPropertyValues("spring.ai.vectorstore.observations.include-query-response=true")
58-
.run(context -> assertThat(context).hasSingleBean(VectorStoreQueryResponseObservationHandler.class));
43+
void queryResponseFilterDefaultEnabled() {
44+
this.contextRunner.withPropertyValues("spring.ai.vectorstore.observations.include-query-response=true")
45+
.run(context -> assertThat(context).hasSingleBean(VectorStoreQueryResponseObservationFilter.class));
5946
}
6047

6148
}

spring-ai-commons/pom.xml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@
5454
</dependency>
5555

5656
<dependency>
57-
<groupId>io.micrometer</groupId>
58-
<artifactId>micrometer-tracing-bridge-otel</artifactId>
59-
<optional>true</optional>
57+
<groupId>org.slf4j</groupId>
58+
<artifactId>slf4j-api</artifactId>
6059
</dependency>
6160

6261
<dependency>

spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)