diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/thread/ThreadDetailsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/thread/ThreadDetailsAutoConfiguration.java new file mode 100644 index 000000000000..24ffc73a970a --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/thread/ThreadDetailsAutoConfiguration.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.thread; + +import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation; +import io.opentelemetry.instrumentation.thread.AddThreadDetailsSpanProcessor; +import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +@ConditionalOnEnabledInstrumentation(module = "thread-details") +@Configuration +@SuppressWarnings("OtelPrivateConstructorForUtilityClass") +public class ThreadDetailsAutoConfiguration { + + @Bean + public AutoConfigurationCustomizerProvider threadDetailOtelCustomizer() { + return p -> + p.addTracerProviderCustomizer( + (builder, config) -> { + builder.addSpanProcessor(new AddThreadDetailsSpanProcessor()); + return builder; + }); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index cb026785d354..aa3f1300ec31 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -13,7 +13,8 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java8RuntimeMetricsProvider,\ -io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider,\ +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.thread.ThreadDetailsAutoConfiguration org.springframework.context.ApplicationListener=\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.LogbackAppenderApplicationListener diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 2392e0c35592..e8c5e8a83d7a 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -14,3 +14,4 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.s io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java8RuntimeMetricsProvider io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.thread.ThreadDetailsAutoConfiguration diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentTracerProviderConfigurer.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentTracerProviderConfigurer.java index 71223c79573c..a77b4e585863 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentTracerProviderConfigurer.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentTracerProviderConfigurer.java @@ -11,6 +11,7 @@ import com.google.auto.service.AutoService; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.exporter.logging.LoggingSpanExporter; +import io.opentelemetry.instrumentation.thread.AddThreadDetailsSpanProcessor; import io.opentelemetry.javaagent.tooling.config.AgentConfig; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/AddThreadDetailsSpanProcessorTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/AddThreadDetailsSpanProcessorTest.groovy deleted file mode 100644 index d3a8a8c933db..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/AddThreadDetailsSpanProcessorTest.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling - -import io.opentelemetry.context.Context -import io.opentelemetry.sdk.trace.ReadWriteSpan -import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes -import spock.lang.Specification - -class AddThreadDetailsSpanProcessorTest extends Specification { - def span = Mock(ReadWriteSpan) - - def processor = new AddThreadDetailsSpanProcessor() - - def "should require onStart call"() { - expect: - processor.isStartRequired() - } - - def "should set thread attributes on span start"() { - given: - def currentThreadName = Thread.currentThread().name - def currentThreadId = Thread.currentThread().id - - when: - processor.onStart(Context.root(), span) - - then: - 1 * span.setAttribute(ThreadIncubatingAttributes.THREAD_ID, currentThreadId) - 1 * span.setAttribute(ThreadIncubatingAttributes.THREAD_NAME, currentThreadName) - } -} diff --git a/sdk-autoconfigure-support/build.gradle.kts b/sdk-autoconfigure-support/build.gradle.kts index 7a2e5e185912..cf9be9f90a7d 100644 --- a/sdk-autoconfigure-support/build.gradle.kts +++ b/sdk-autoconfigure-support/build.gradle.kts @@ -7,7 +7,9 @@ group = "io.opentelemetry.instrumentation" dependencies { api("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + api("io.opentelemetry:opentelemetry-sdk-extension-incubator") compileOnly("com.google.code.findbugs:annotations") testCompileOnly("com.google.code.findbugs:annotations") + testImplementation(project(":testing-common")) } diff --git a/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/sdk/LoggingSpanExporterCustomizerProvider.java b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/sdk/LoggingSpanExporterCustomizerProvider.java new file mode 100644 index 000000000000..368f0ec17e3c --- /dev/null +++ b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/sdk/LoggingSpanExporterCustomizerProvider.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.sdk; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; + +public class LoggingSpanExporterCustomizerProvider + implements DeclarativeConfigurationCustomizerProvider { + @Override + public void customize(DeclarativeConfigurationCustomizer customizer) { + customizer.addModelCustomizer( + model -> { + DeclarativeConfigProperties properties = + SdkConfigProvider.create(model).getInstrumentationConfig(); + if (properties == null) { + properties = DeclarativeConfigProperties.empty(); + } + DeclarativeConfigProperties java = + properties.getStructured("java", DeclarativeConfigProperties.empty()); + if (!java.getBoolean("enabled", true)) { + // todo extract this logic to a common place + // todo should this be pulled out or to be reusable by spring? + return model; + } + + if (java.getStructured("thread_details", DeclarativeConfigProperties.empty()) + .getBoolean("enabled", true)) { + TracerProviderModel tracerProvider = model.getTracerProvider(); + if (tracerProvider != null) { + tracerProvider + .getProcessors() + .add(new SpanProcessorModel().withAdditionalProperty("thread_details", null)); + } + } + + // todo also add logging like in AgentTracerProviderConfigurer + + return model; + }); + } +} diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AddThreadDetailsSpanProcessor.java b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/AddThreadDetailsSpanProcessor.java similarity index 63% rename from javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AddThreadDetailsSpanProcessor.java rename to sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/AddThreadDetailsSpanProcessor.java index 496d8580ff79..33f033edf4f5 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AddThreadDetailsSpanProcessor.java +++ b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/AddThreadDetailsSpanProcessor.java @@ -3,22 +3,29 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.tooling; +package io.opentelemetry.instrumentation.thread; +import static io.opentelemetry.api.common.AttributeKey.longKey; +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.trace.ReadWriteSpan; import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.SpanProcessor; -import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; public class AddThreadDetailsSpanProcessor implements SpanProcessor { + // attributes are not stable yet + public static final AttributeKey THREAD_ID = longKey("thread.id"); + public static final AttributeKey THREAD_NAME = stringKey("thread.name"); + @Override public void onStart(Context context, ReadWriteSpan span) { Thread currentThread = Thread.currentThread(); - span.setAttribute(ThreadIncubatingAttributes.THREAD_ID, currentThread.getId()); - span.setAttribute(ThreadIncubatingAttributes.THREAD_NAME, currentThread.getName()); + span.setAttribute(THREAD_ID, currentThread.getId()); + span.setAttribute(THREAD_NAME, currentThread.getName()); } @Override diff --git a/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/ThreadDetailsComponentProvider.java b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/ThreadDetailsComponentProvider.java new file mode 100644 index 000000000000..684f2ba6acab --- /dev/null +++ b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/ThreadDetailsComponentProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thread; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.trace.SpanProcessor; + +public class ThreadDetailsComponentProvider implements ComponentProvider { + @Override + public String getName() { + return "thread_details"; + } + + @Override + public SpanProcessor create(DeclarativeConfigProperties config) { + return new AddThreadDetailsSpanProcessor(); + } + + @Override + public Class getType() { + return SpanProcessor.class; + } +} diff --git a/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/ThreadDetailsCustomizerProvider.java b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/ThreadDetailsCustomizerProvider.java new file mode 100644 index 000000000000..a498c8e90b3b --- /dev/null +++ b/sdk-autoconfigure-support/src/main/java/io/opentelemetry/instrumentation/thread/ThreadDetailsCustomizerProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thread; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; + +public class ThreadDetailsCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { + @Override + public void customize(DeclarativeConfigurationCustomizer customizer) { + customizer.addModelCustomizer( + model -> { + DeclarativeConfigProperties properties = + SdkConfigProvider.create(model).getInstrumentationConfig(); + if (properties == null) { + properties = DeclarativeConfigProperties.empty(); + } + DeclarativeConfigProperties java = + properties.getStructured("java", DeclarativeConfigProperties.empty()); + if (!java.getBoolean("enabled", true)) { + // todo extract this logic to a common place + // todo should this be pulled out or to be reusable by spring? + return model; + } + + if (java.getStructured("thread_details", DeclarativeConfigProperties.empty()) + .getBoolean("enabled", true)) { + TracerProviderModel tracerProvider = model.getTracerProvider(); + if (tracerProvider != null) { + tracerProvider + .getProcessors() + .add(new SpanProcessorModel().withAdditionalProperty("thread_details", null)); + } + } + + // todo also add logging like in AgentTracerProviderConfigurer + + return model; + }); + } +} diff --git a/sdk-autoconfigure-support/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/sdk-autoconfigure-support/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider new file mode 100644 index 000000000000..4c301010489b --- /dev/null +++ b/sdk-autoconfigure-support/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider @@ -0,0 +1 @@ +io.opentelemetry.instrumentation.thread.ThreadDetailsComponentProvider diff --git a/sdk-autoconfigure-support/src/main/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider b/sdk-autoconfigure-support/src/main/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider new file mode 100644 index 000000000000..2b0e55824d87 --- /dev/null +++ b/sdk-autoconfigure-support/src/main/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider @@ -0,0 +1,2 @@ +io.opentelemetry.instrumentation.thread.ThreadDetailsCustomizerProvider +io.opentelemetry.instrumentation.sdk.LoggingSpanExporterCustomizerProvider diff --git a/sdk-autoconfigure-support/src/test/java/io/opentelemetry/instrumentation/thread/AddThreadDetailsSpanProcessorTest.java b/sdk-autoconfigure-support/src/test/java/io/opentelemetry/instrumentation/thread/AddThreadDetailsSpanProcessorTest.java new file mode 100644 index 000000000000..a0bcea8daf9d --- /dev/null +++ b/sdk-autoconfigure-support/src/test/java/io/opentelemetry/instrumentation/thread/AddThreadDetailsSpanProcessorTest.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thread; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; +import org.junit.jupiter.api.Test; + +class AddThreadDetailsSpanProcessorTest { + + private final ReadWriteSpan span = mock(ReadWriteSpan.class); + + private final SpanProcessor spanProcessor = new AddThreadDetailsSpanProcessor(); + + @Test + void onStart() { + assertThat(spanProcessor.isStartRequired()).isTrue(); + } + + @Test + void setThreadAttributes() { + Thread thread = Thread.currentThread(); + spanProcessor.onStart(Context.root(), span); + + verify(span).setAttribute(ThreadIncubatingAttributes.THREAD_ID, thread.getId()); + verify(span).setAttribute(ThreadIncubatingAttributes.THREAD_NAME, thread.getName()); + verifyNoMoreInteractions(span); + } +} diff --git a/sdk-autoconfigure-support/src/test/java/io/opentelemetry/instrumentation/thread/ThreadDetailsConfigurationCustomizerProviderTest.java b/sdk-autoconfigure-support/src/test/java/io/opentelemetry/instrumentation/thread/ThreadDetailsConfigurationCustomizerProviderTest.java new file mode 100644 index 000000000000..b415a29e0217 --- /dev/null +++ b/sdk-autoconfigure-support/src/test/java/io/opentelemetry/instrumentation/thread/ThreadDetailsConfigurationCustomizerProviderTest.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thread; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationBuilder; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; +import org.junit.jupiter.api.Test; + +class ThreadDetailsConfigurationCustomizerProviderTest { + + @Test + void addSpanProcessor() { + OpenTelemetryConfigurationModel model = + new DeclarativeConfigurationBuilder() + .customizeModel( + new OpenTelemetryConfigurationModel() + .withFileFormat("0.4") + .withTracerProvider(new TracerProviderModel())); + + try (OpenTelemetrySdk sdk = DeclarativeConfiguration.create(model)) { + assertThat(sdk.toString()).containsOnlyOnce("AddThreadDetailsSpanProcessor"); + } + } +} diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index 6b277a222ea6..3ef2bd5f0215 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -30,6 +30,7 @@ import io.opentelemetry.semconv.incubating.CodeIncubatingAttributes; import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes; +import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -37,6 +38,7 @@ import java.util.List; import org.assertj.core.api.AbstractCharSequenceAssert; import org.assertj.core.api.AbstractIterableAssert; +import org.assertj.core.api.AbstractLongAssert; import org.assertj.core.api.MapAssert; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; @@ -180,9 +182,7 @@ void shouldSendTelemetry() { UrlAttributes.URL_FULL, stringAssert -> stringAssert.endsWith("/ping")), equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"), - satisfies( - ServerAttributes.SERVER_PORT, - integerAssert -> integerAssert.isNotZero())), + satisfies(ServerAttributes.SERVER_PORT, AbstractLongAssert::isNotZero)), serverSpan -> HttpSpanDataAssert.create(serverSpan) .assertServerGetRequest("/ping") @@ -205,10 +205,14 @@ void shouldSendTelemetry() { equalTo( AttributeKey.stringArrayKey("http.request.header.key"), Collections.singletonList("value")), + satisfies(ServerAttributes.SERVER_PORT, AbstractLongAssert::isNotZero), + satisfies( + ThreadIncubatingAttributes.THREAD_ID, + AbstractLongAssert::isNotZero), satisfies( - ServerAttributes.SERVER_PORT, - integerAssert -> integerAssert.isNotZero())), - span -> withSpanAssert(span))); + ThreadIncubatingAttributes.THREAD_NAME, + AbstractCharSequenceAssert::isNotBlank)), + AbstractSpringStarterSmokeTest::withSpanAssert)); // Metric testing.waitAndAssertMetrics( @@ -307,7 +311,7 @@ void restTemplate() { span -> HttpSpanDataAssert.create(span).assertClientGetRequest("/ping"), span -> span.hasKind(SpanKind.SERVER).hasAttribute(HttpAttributes.HTTP_ROUTE, "/ping"), - span -> withSpanAssert(span))); + AbstractSpringStarterSmokeTest::withSpanAssert)); } @Test