|
5 | 5 |
|
6 | 6 | package io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties; |
7 | 7 |
|
| 8 | +import static java.util.Collections.emptyMap; |
8 | 9 | import static org.assertj.core.api.Assertions.assertThat; |
9 | 10 | import static org.assertj.core.api.Assertions.entry; |
| 11 | +import static org.mockito.ArgumentMatchers.eq; |
| 12 | +import static org.mockito.Mockito.spy; |
| 13 | +import static org.mockito.Mockito.times; |
| 14 | +import static org.mockito.Mockito.verify; |
10 | 15 |
|
11 | 16 | import io.opentelemetry.api.OpenTelemetry; |
12 | 17 | import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; |
|
17 | 22 | import java.util.HashMap; |
18 | 23 | import java.util.List; |
19 | 24 | import java.util.Map; |
| 25 | +import java.util.function.Consumer; |
20 | 26 | import java.util.stream.Stream; |
21 | 27 | import org.junit.jupiter.api.DisplayName; |
22 | 28 | import org.junit.jupiter.api.Test; |
@@ -162,8 +168,120 @@ void shouldInitializeAttributesByMap() { |
162 | 168 | }); |
163 | 169 | } |
164 | 170 |
|
| 171 | + public static Stream<Arguments> propertyCachingTestCases() { |
| 172 | + return Stream.of( |
| 173 | + // property, typeClass, assertion |
| 174 | + Arguments.of( |
| 175 | + "otel.service.name=test-service", |
| 176 | + String.class, |
| 177 | + (Consumer<SpringConfigProperties>) |
| 178 | + config -> |
| 179 | + assertThat(config.getString("otel.service.name")).isEqualTo("test-service")), |
| 180 | + Arguments.of( |
| 181 | + "otel.exporter.otlp.enabled=true", |
| 182 | + Boolean.class, |
| 183 | + (Consumer<SpringConfigProperties>) |
| 184 | + config -> assertThat(config.getBoolean("otel.exporter.otlp.enabled")).isTrue()), |
| 185 | + Arguments.of( |
| 186 | + "otel.metric.export.interval=10", |
| 187 | + Integer.class, |
| 188 | + (Consumer<SpringConfigProperties>) |
| 189 | + config -> assertThat(config.getInt("otel.metric.export.interval")).isEqualTo(10)), |
| 190 | + Arguments.of( |
| 191 | + "otel.bsp.schedule.delay=5000", |
| 192 | + Long.class, |
| 193 | + (Consumer<SpringConfigProperties>) |
| 194 | + config -> assertThat(config.getLong("otel.bsp.schedule.delay")).isEqualTo(5000L)), |
| 195 | + Arguments.of( |
| 196 | + "otel.traces.sampler.arg=0.5", |
| 197 | + Double.class, |
| 198 | + (Consumer<SpringConfigProperties>) |
| 199 | + config -> assertThat(config.getDouble("otel.traces.sampler.arg")).isEqualTo(0.5)), |
| 200 | + Arguments.of( |
| 201 | + "otel.bsp.export.timeout=30s", |
| 202 | + String.class, |
| 203 | + (Consumer<SpringConfigProperties>) |
| 204 | + config -> |
| 205 | + assertThat(config.getDuration("otel.bsp.export.timeout")) |
| 206 | + .isEqualByComparingTo(java.time.Duration.ofSeconds(30))), |
| 207 | + Arguments.of( |
| 208 | + "otel.attribute.value.length.limit=256", |
| 209 | + List.class, |
| 210 | + (Consumer<SpringConfigProperties>) |
| 211 | + config -> |
| 212 | + assertThat(config.getList("otel.attribute.value.length.limit")) |
| 213 | + .containsExactly("256"))); |
| 214 | + } |
| 215 | + |
| 216 | + @ParameterizedTest |
| 217 | + @MethodSource("propertyCachingTestCases") |
| 218 | + @DisplayName("should cache property lookups and call Environment.getProperty() only once") |
| 219 | + void propertyCaching( |
| 220 | + String property, Class<?> typeClass, Consumer<SpringConfigProperties> assertion) { |
| 221 | + String propertyName = property.split("=")[0]; |
| 222 | + |
| 223 | + this.contextRunner |
| 224 | + .withPropertyValues(property) |
| 225 | + .run( |
| 226 | + context -> { |
| 227 | + Environment realEnvironment = context.getBean("environment", Environment.class); |
| 228 | + Environment spyEnvironment = spy(realEnvironment); |
| 229 | + |
| 230 | + SpringConfigProperties config = |
| 231 | + new SpringConfigProperties( |
| 232 | + spyEnvironment, |
| 233 | + new SpelExpressionParser(), |
| 234 | + context.getBean(OtlpExporterProperties.class), |
| 235 | + context.getBean(OtelResourceProperties.class), |
| 236 | + context.getBean(OtelSpringProperties.class), |
| 237 | + DefaultConfigProperties.createFromMap(emptyMap())); |
| 238 | + |
| 239 | + for (int i = 0; i < 100; i++) { |
| 240 | + assertion.accept(config); |
| 241 | + } |
| 242 | + |
| 243 | + verify(spyEnvironment, times(1)).getProperty(eq(propertyName), eq(typeClass)); |
| 244 | + }); |
| 245 | + } |
| 246 | + |
| 247 | + @Test |
| 248 | + @DisplayName("should cache map property lookups and call Environment.getProperty() only once") |
| 249 | + void mapPropertyCaching() { |
| 250 | + this.contextRunner |
| 251 | + .withSystemProperties( |
| 252 | + "otel.instrumentation.common.peer-service-mapping={'host1':'serviceA','host2':'serviceB'}") |
| 253 | + .run( |
| 254 | + context -> { |
| 255 | + Environment realEnvironment = context.getBean("environment", Environment.class); |
| 256 | + Environment spyEnvironment = spy(realEnvironment); |
| 257 | + |
| 258 | + SpringConfigProperties config = |
| 259 | + new SpringConfigProperties( |
| 260 | + spyEnvironment, |
| 261 | + new SpelExpressionParser(), |
| 262 | + context.getBean(OtlpExporterProperties.class), |
| 263 | + context.getBean(OtelResourceProperties.class), |
| 264 | + context.getBean(OtelSpringProperties.class), |
| 265 | + DefaultConfigProperties.createFromMap(emptyMap())); |
| 266 | + |
| 267 | + for (int i = 0; i < 100; i++) { |
| 268 | + Map<String, String> mapping = |
| 269 | + config.getMap("otel.instrumentation.common.peer-service-mapping"); |
| 270 | + assertThat(mapping) |
| 271 | + .containsEntry("host1", "serviceA") |
| 272 | + .containsEntry("host2", "serviceB"); |
| 273 | + } |
| 274 | + |
| 275 | + // Map properties call getProperty(name) which delegates to getProperty(name, |
| 276 | + // String.class) |
| 277 | + verify(spyEnvironment, times(1)) |
| 278 | + .getProperty( |
| 279 | + eq("otel.instrumentation.common.peer-service-mapping"), eq(String.class)); |
| 280 | + }); |
| 281 | + } |
| 282 | + |
165 | 283 | private static ConfigProperties getConfig(AssertableApplicationContext context) { |
166 | | - return getConfig(context, Collections.emptyMap()); |
| 284 | + return getConfig(context, emptyMap()); |
167 | 285 | } |
168 | 286 |
|
169 | 287 | private static SpringConfigProperties getConfig( |
|
0 commit comments