Add HTTP server tests for non standard methods (#9446)
This commit is contained in:
parent
2b2c4ca2d2
commit
3136916749
|
|
@ -31,13 +31,16 @@ public final class HttpServerRoute {
|
||||||
*/
|
*/
|
||||||
public static <REQUEST> ContextCustomizer<REQUEST> create(
|
public static <REQUEST> ContextCustomizer<REQUEST> create(
|
||||||
HttpServerAttributesGetter<REQUEST, ?> getter) {
|
HttpServerAttributesGetter<REQUEST, ?> getter) {
|
||||||
return (context, request, startAttributes) -> {
|
return builder(getter).build();
|
||||||
if (HttpRouteState.fromContextOrNull(context) != null) {
|
|
||||||
return context;
|
|
||||||
}
|
}
|
||||||
String method = getter.getHttpRequestMethod(request);
|
|
||||||
return context.with(HttpRouteState.create(method, null, 0));
|
/**
|
||||||
};
|
* Returns a new {@link HttpServerRouteBuilder} that can be used to configure the {@link
|
||||||
|
* HttpServerRoute}.
|
||||||
|
*/
|
||||||
|
public static <REQUEST> HttpServerRouteBuilder<REQUEST> builder(
|
||||||
|
HttpServerAttributesGetter<REQUEST, ?> getter) {
|
||||||
|
return new HttpServerRouteBuilder<>(getter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpServerRoute() {}
|
private HttpServerRoute() {}
|
||||||
|
|
@ -147,12 +150,9 @@ public final class HttpServerRoute {
|
||||||
|
|
||||||
private static void updateSpanName(Span serverSpan, HttpRouteState httpRouteState, String route) {
|
private static void updateSpanName(Span serverSpan, HttpRouteState httpRouteState, String route) {
|
||||||
String method = httpRouteState.getMethod();
|
String method = httpRouteState.getMethod();
|
||||||
// method should never really be null - but in case it for some reason is, we'll rely on the
|
// method should never really be null
|
||||||
// span name extractor behavior
|
|
||||||
if (method != null) {
|
|
||||||
serverSpan.updateName(method + " " + route);
|
serverSpan.updateName(method + " " + route);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code http.route} attribute value that's stored in the {@code context}, or null if
|
* Returns the {@code http.route} attribute value that's stored in the {@code context}, or null if
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.api.instrumenter.http;
|
||||||
|
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
|
import io.opentelemetry.context.Context;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpRouteState;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/** A builder of {@link HttpSpanNameExtractor}. */
|
||||||
|
public final class HttpServerRouteBuilder<REQUEST> {
|
||||||
|
|
||||||
|
final HttpServerAttributesGetter<REQUEST, ?> getter;
|
||||||
|
Set<String> knownMethods = HttpConstants.KNOWN_METHODS;
|
||||||
|
|
||||||
|
HttpServerRouteBuilder(HttpServerAttributesGetter<REQUEST, ?> getter) {
|
||||||
|
this.getter = getter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the customizer to recognize an alternative set of HTTP request methods.
|
||||||
|
*
|
||||||
|
* <p>By default, this customizer defines "known" methods as the ones listed in <a
|
||||||
|
* href="https://www.rfc-editor.org/rfc/rfc9110.html#name-methods">RFC9110</a> and the PATCH
|
||||||
|
* method defined in <a href="https://www.rfc-editor.org/rfc/rfc5789.html">RFC5789</a>. If an
|
||||||
|
* unknown method is encountered, the customizer will use the value {@value HttpConstants#_OTHER}
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* <p>Note: calling this method <b>overrides</b> the default known method sets completely; it does
|
||||||
|
* not supplement it.
|
||||||
|
*
|
||||||
|
* @param knownMethods A set of recognized HTTP request methods.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public HttpServerRouteBuilder<REQUEST> setKnownMethods(Set<String> knownMethods) {
|
||||||
|
this.knownMethods = new HashSet<>(knownMethods);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link ContextCustomizer} that initializes an {@link HttpServerRoute} in the {@link
|
||||||
|
* Context} returned from {@link Instrumenter#start(Context, Object)}. The returned customizer is
|
||||||
|
* configured with the settings of this {@link HttpServerRouteBuilder}.
|
||||||
|
*/
|
||||||
|
public ContextCustomizer<REQUEST> build() {
|
||||||
|
Set<String> knownMethods = new HashSet<>(this.knownMethods);
|
||||||
|
return (context, request, startAttributes) -> {
|
||||||
|
if (HttpRouteState.fromContextOrNull(context) != null) {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
String method = getter.getHttpRequestMethod(request);
|
||||||
|
if (method == null || !knownMethods.contains(method)) {
|
||||||
|
method = "HTTP";
|
||||||
|
}
|
||||||
|
return context.with(HttpRouteState.create(method, null, 0));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
package io.opentelemetry.instrumentation.api.instrumenter.http;
|
package io.opentelemetry.instrumentation.api.instrumenter.http;
|
||||||
|
|
||||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
@ -14,6 +15,7 @@ import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension;
|
import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension;
|
||||||
|
import java.util.HashSet;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
@ -33,7 +35,10 @@ class HttpServerRouteTest {
|
||||||
void setUp() {
|
void setUp() {
|
||||||
instrumenter =
|
instrumenter =
|
||||||
Instrumenter.<String, Void>builder(testing.getOpenTelemetry(), "test", s -> s)
|
Instrumenter.<String, Void>builder(testing.getOpenTelemetry(), "test", s -> s)
|
||||||
.addContextCustomizer(HttpServerRoute.create(getter))
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(getter)
|
||||||
|
.setKnownMethods(new HashSet<>(singletonList("GET")))
|
||||||
|
.build())
|
||||||
.buildInstrumenter();
|
.buildInstrumenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,7 +163,7 @@ class HttpServerRouteTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldNotUpdateSpanName_noMethod() {
|
void shouldUseHttp_noMethod() {
|
||||||
when(getter.getHttpRequestMethod("test")).thenReturn(null);
|
when(getter.getHttpRequestMethod("test")).thenReturn(null);
|
||||||
|
|
||||||
Context context = instrumenter.start(Context.root(), "test");
|
Context context = instrumenter.start(Context.root(), "test");
|
||||||
|
|
@ -169,6 +174,23 @@ class HttpServerRouteTest {
|
||||||
instrumenter.end(context, "test", null, null);
|
instrumenter.end(context, "test", null, null);
|
||||||
|
|
||||||
assertEquals("/get/:id", HttpServerRoute.get(context));
|
assertEquals("/get/:id", HttpServerRoute.get(context));
|
||||||
assertThat(testing.getSpans()).satisfiesExactly(span -> assertThat(span).hasName("test"));
|
assertThat(testing.getSpans())
|
||||||
|
.satisfiesExactly(span -> assertThat(span).hasName("HTTP /get/:id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUseHttp_unknownMethod() {
|
||||||
|
when(getter.getHttpRequestMethod("test")).thenReturn("POST");
|
||||||
|
|
||||||
|
Context context = instrumenter.start(Context.root(), "test");
|
||||||
|
assertNull(HttpServerRoute.get(context));
|
||||||
|
|
||||||
|
HttpServerRoute.update(context, HttpServerRouteSource.SERVER, "/get/:id");
|
||||||
|
|
||||||
|
instrumenter.end(context, "test", null, null);
|
||||||
|
|
||||||
|
assertEquals("/get/:id", HttpServerRoute.get(context));
|
||||||
|
assertThat(testing.getSpans())
|
||||||
|
.satisfiesExactly(span -> assertThat(span).hasName("HTTP /get/:id"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ public final class AkkaHttpServerSingletons {
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
.build())
|
.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get())
|
.addOperationMetrics(HttpServerMetrics.get())
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter));
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build());
|
||||||
if (CommonConfig.get().shouldEmitExperimentalHttpServerMetrics()) {
|
if (CommonConfig.get().shouldEmitExperimentalHttpServerMetrics()) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,5 +35,7 @@ abstract class AbstractHttpServerInstrumentationTest
|
||||||
t != ServerEndpoint.EXCEPTION
|
t != ServerEndpoint.EXCEPTION
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
// instrumentation does not create a span at all
|
||||||
|
options.disableTestNonStandardHttpMethod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,5 +29,6 @@ class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest {
|
||||||
options.setHasResponseCustomizer(
|
options.setHasResponseCustomizer(
|
||||||
endpoint -> ServerEndpoint.NOT_FOUND != endpoint && ServerEndpoint.EXCEPTION != endpoint);
|
endpoint -> ServerEndpoint.NOT_FOUND != endpoint && ServerEndpoint.EXCEPTION != endpoint);
|
||||||
options.setTestHttpPipelining(false);
|
options.setTestHttpPipelining(false);
|
||||||
|
options.setResponseCodeOnNonStandardHttpMethod(405);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -62,6 +63,9 @@ public final class ArmeriaTelemetryBuilder {
|
||||||
private final HttpSpanNameExtractorBuilder<RequestContext> httpServerSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<RequestContext> httpServerSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(ArmeriaHttpServerAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(ArmeriaHttpServerAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
|
private final HttpServerRouteBuilder<RequestContext> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(ArmeriaHttpServerAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
private Function<
|
private Function<
|
||||||
SpanStatusExtractor<RequestContext, RequestLog>,
|
SpanStatusExtractor<RequestContext, RequestLog>,
|
||||||
? extends SpanStatusExtractor<? super RequestContext, ? super RequestLog>>
|
? extends SpanStatusExtractor<? super RequestContext, ? super RequestLog>>
|
||||||
|
|
@ -175,6 +179,7 @@ public final class ArmeriaTelemetryBuilder {
|
||||||
httpServerAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpServerAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpClientSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpClientSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpServerSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpServerSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +238,7 @@ public final class ArmeriaTelemetryBuilder {
|
||||||
HttpSpanStatusExtractor.create(serverAttributesGetter)))
|
HttpSpanStatusExtractor.create(serverAttributesGetter)))
|
||||||
.addAttributesExtractor(httpServerAttributesExtractorBuilder.build())
|
.addAttributesExtractor(httpServerAttributesExtractorBuilder.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get())
|
.addOperationMetrics(HttpServerMetrics.get())
|
||||||
.addContextCustomizer(HttpServerRoute.create(serverAttributesGetter));
|
.addContextCustomizer(httpServerRouteBuilder.build());
|
||||||
|
|
||||||
if (peerService != null) {
|
if (peerService != null) {
|
||||||
clientInstrumenterBuilder.addAttributesExtractor(
|
clientInstrumenterBuilder.addAttributesExtractor(
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import com.linecorp.armeria.server.ServerBuilder;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
|
@ -28,4 +29,11 @@ class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest {
|
||||||
.build()
|
.build()
|
||||||
.newServiceDecorator());
|
.newServiceDecorator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpServerTestOptions options) {
|
||||||
|
super.configure(options);
|
||||||
|
// library instrumentation does not create a span at all
|
||||||
|
options.disableTestNonStandardHttpMethod();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,13 +178,13 @@ public abstract class AbstractArmeriaHttpServerTest extends AbstractHttpServerTe
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpServerTestOptions options) {
|
protected void configure(HttpServerTestOptions options) {
|
||||||
options.setExpectedHttpRoute(
|
options.setExpectedHttpRoute(
|
||||||
endpoint -> {
|
(endpoint, method) -> {
|
||||||
if (endpoint == ServerEndpoint.NOT_FOUND) {
|
if (endpoint == ServerEndpoint.NOT_FOUND) {
|
||||||
// TODO(anuraaga): Revisit this when applying instrumenters to more libraries, Armeria
|
// TODO(anuraaga): Revisit this when applying instrumenters to more libraries, Armeria
|
||||||
// currently reports '/*' which is a fallback route.
|
// currently reports '/*' which is a fallback route.
|
||||||
return "/*";
|
return "/*";
|
||||||
}
|
}
|
||||||
return expectedHttpRoute(endpoint);
|
return expectedHttpRoute(endpoint, method);
|
||||||
});
|
});
|
||||||
|
|
||||||
options.setTestPathParam(true);
|
options.setTestPathParam(true);
|
||||||
|
|
|
||||||
|
|
@ -83,14 +83,14 @@ class DropwizardTest extends HttpServerTest<DropwizardTestSupport> implements Ag
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ class FinatraServerTest extends AbstractHttpServerTest[HttpServer] {
|
||||||
override def test(endpoint: ServerEndpoint): Boolean =
|
override def test(endpoint: ServerEndpoint): Boolean =
|
||||||
endpoint != ServerEndpoint.NOT_FOUND
|
endpoint != ServerEndpoint.NOT_FOUND
|
||||||
})
|
})
|
||||||
|
options.setResponseCodeOnNonStandardHttpMethod(400)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def assertHandlerSpan(
|
override protected def assertHandlerSpan(
|
||||||
|
|
|
||||||
|
|
@ -65,12 +65,16 @@ configurations.testRuntimeClasspath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val latestDepTest = findProperty("testLatestDeps") as Boolean
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
val testStableSemconv by registering(Test::class) {
|
val testStableSemconv by registering(Test::class) {
|
||||||
jvmArgs("-Dotel.semconv-stability.opt-in=http")
|
jvmArgs("-Dotel.semconv-stability.opt-in=http")
|
||||||
}
|
}
|
||||||
|
|
||||||
withType<Test>().configureEach {
|
withType<Test>().configureEach {
|
||||||
|
systemProperty("testLatestDeps", latestDepTest)
|
||||||
|
|
||||||
// required on jdk17
|
// required on jdk17
|
||||||
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
|
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
|
||||||
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
|
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import grails.boot.GrailsApp;
|
||||||
import grails.boot.config.GrailsAutoConfiguration;
|
import grails.boot.config.GrailsAutoConfiguration;
|
||||||
import io.opentelemetry.api.common.Attributes;
|
import io.opentelemetry.api.common.Attributes;
|
||||||
import io.opentelemetry.api.trace.SpanKind;
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
||||||
|
|
@ -42,6 +43,8 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
public class GrailsTest extends AbstractHttpServerTest<ConfigurableApplicationContext> {
|
public class GrailsTest extends AbstractHttpServerTest<ConfigurableApplicationContext> {
|
||||||
|
|
||||||
|
static final boolean testLatestDeps = Boolean.getBoolean("testLatestDeps");
|
||||||
|
|
||||||
@RegisterExtension
|
@RegisterExtension
|
||||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||||
|
|
||||||
|
|
@ -64,6 +67,7 @@ public class GrailsTest extends AbstractHttpServerTest<ConfigurableApplicationCo
|
||||||
options.setHasErrorPageSpans(
|
options.setHasErrorPageSpans(
|
||||||
endpoint -> endpoint == ERROR || endpoint == EXCEPTION || endpoint == NOT_FOUND);
|
endpoint -> endpoint == ERROR || endpoint == EXCEPTION || endpoint == NOT_FOUND);
|
||||||
options.setTestPathParam(true);
|
options.setTestPathParam(true);
|
||||||
|
options.setResponseCodeOnNonStandardHttpMethod(testLatestDeps ? 200 : 501);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
|
@ -106,7 +110,12 @@ public class GrailsTest extends AbstractHttpServerTest<ConfigurableApplicationCo
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String expectedHttpRoute(ServerEndpoint endpoint) {
|
public String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
if (HttpConstants._OTHER.equals(method)) {
|
||||||
|
return testLatestDeps
|
||||||
|
? getContextPath() + "/test" + endpoint.getPath()
|
||||||
|
: getContextPath() + "/*";
|
||||||
|
}
|
||||||
if (PATH_PARAM.equals(endpoint)) {
|
if (PATH_PARAM.equals(endpoint)) {
|
||||||
return getContextPath() + "/test/path";
|
return getContextPath() + "/test/path";
|
||||||
} else if (QUERY_PARAM.equals(endpoint)) {
|
} else if (QUERY_PARAM.equals(endpoint)) {
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,10 @@ public final class GrizzlySingletons {
|
||||||
.init(context))
|
.init(context))
|
||||||
.addContextCustomizer(
|
.addContextCustomizer(
|
||||||
(context, httpRequestPacket, startAttributes) -> GrizzlyErrorHolder.init(context))
|
(context, httpRequestPacket, startAttributes) -> GrizzlyErrorHolder.init(context))
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build())
|
||||||
.buildServerInstrumenter(HttpRequestHeadersGetter.INSTANCE);
|
.buildServerInstrumenter(HttpRequestHeadersGetter.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,6 @@ abstract class AbstractJaxRsHttpServerTest<S> extends HttpServerTest<S> implemen
|
||||||
String traceID = null,
|
String traceID = null,
|
||||||
String parentID = null,
|
String parentID = null,
|
||||||
String method = "GET",
|
String method = "GET",
|
||||||
Long responseContentLength = null,
|
|
||||||
ServerEndpoint endpoint = SUCCESS,
|
ServerEndpoint endpoint = SUCCESS,
|
||||||
String spanID = null) {
|
String spanID = null) {
|
||||||
serverSpan(trace, index, traceID, parentID, spanID, method,
|
serverSpan(trace, index, traceID, parentID, spanID, method,
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ class KtorServerTracing private constructor(
|
||||||
|
|
||||||
internal val httpSpanNameExtractorBuilder = HttpSpanNameExtractor.builder(KtorHttpServerAttributesGetter.INSTANCE)
|
internal val httpSpanNameExtractorBuilder = HttpSpanNameExtractor.builder(KtorHttpServerAttributesGetter.INSTANCE)
|
||||||
|
|
||||||
|
internal val httpServerRouteBuilder = HttpServerRoute.builder(KtorHttpServerAttributesGetter.INSTANCE)
|
||||||
|
|
||||||
internal var statusExtractor:
|
internal var statusExtractor:
|
||||||
(SpanStatusExtractor<ApplicationRequest, ApplicationResponse>) -> SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse> = { a -> a }
|
(SpanStatusExtractor<ApplicationRequest, ApplicationResponse>) -> SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse> = { a -> a }
|
||||||
|
|
||||||
|
|
@ -77,6 +79,7 @@ class KtorServerTracing private constructor(
|
||||||
fun setKnownMethods(knownMethods: Set<String>) {
|
fun setKnownMethods(knownMethods: Set<String>) {
|
||||||
httpAttributesExtractorBuilder.setKnownMethods(knownMethods)
|
httpAttributesExtractorBuilder.setKnownMethods(knownMethods)
|
||||||
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods)
|
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods)
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun isOpenTelemetryInitialized(): Boolean = this::openTelemetry.isInitialized
|
internal fun isOpenTelemetryInitialized(): Boolean = this::openTelemetry.isInitialized
|
||||||
|
|
@ -124,7 +127,7 @@ class KtorServerTracing private constructor(
|
||||||
setSpanStatusExtractor(configuration.statusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter)))
|
setSpanStatusExtractor(configuration.statusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter)))
|
||||||
addAttributesExtractor(configuration.httpAttributesExtractorBuilder.build())
|
addAttributesExtractor(configuration.httpAttributesExtractorBuilder.build())
|
||||||
addOperationMetrics(HttpServerMetrics.get())
|
addOperationMetrics(HttpServerMetrics.get())
|
||||||
addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
addContextCustomizer(configuration.httpServerRouteBuilder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
val instrumenter = InstrumenterUtil.buildUpstreamInstrumenter(
|
val instrumenter = InstrumenterUtil.buildUpstreamInstrumenter(
|
||||||
|
|
|
||||||
|
|
@ -129,10 +129,10 @@ class KtorHttpServerTest : AbstractHttpServerTest<ApplicationEngine>() {
|
||||||
HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES - SemanticAttributes.NET_PEER_PORT
|
HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES - SemanticAttributes.NET_PEER_PORT
|
||||||
}
|
}
|
||||||
|
|
||||||
options.setExpectedHttpRoute {
|
options.setExpectedHttpRoute { endpoint, method ->
|
||||||
when (it) {
|
when (endpoint) {
|
||||||
ServerEndpoint.PATH_PARAM -> "/path/{id}/param"
|
ServerEndpoint.PATH_PARAM -> "/path/{id}/param"
|
||||||
else -> expectedHttpRoute(it)
|
else -> expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ktor does not have a controller lifecycle so the server span ends immediately when the
|
// ktor does not have a controller lifecycle so the server span ends immediately when the
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ class KtorServerTracing private constructor(
|
||||||
|
|
||||||
internal val httpSpanNameExtractorBuilder = HttpSpanNameExtractor.builder(KtorHttpServerAttributesGetter.INSTANCE)
|
internal val httpSpanNameExtractorBuilder = HttpSpanNameExtractor.builder(KtorHttpServerAttributesGetter.INSTANCE)
|
||||||
|
|
||||||
|
internal val httpServerRouteBuilder = HttpServerRoute.builder(KtorHttpServerAttributesGetter.INSTANCE)
|
||||||
|
|
||||||
internal var statusExtractor:
|
internal var statusExtractor:
|
||||||
(SpanStatusExtractor<ApplicationRequest, ApplicationResponse>) -> SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse> = { a -> a }
|
(SpanStatusExtractor<ApplicationRequest, ApplicationResponse>) -> SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse> = { a -> a }
|
||||||
|
|
||||||
|
|
@ -78,6 +80,7 @@ class KtorServerTracing private constructor(
|
||||||
fun setKnownMethods(knownMethods: Set<String>) {
|
fun setKnownMethods(knownMethods: Set<String>) {
|
||||||
httpAttributesExtractorBuilder.setKnownMethods(knownMethods)
|
httpAttributesExtractorBuilder.setKnownMethods(knownMethods)
|
||||||
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods)
|
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods)
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun isOpenTelemetryInitialized(): Boolean = this::openTelemetry.isInitialized
|
internal fun isOpenTelemetryInitialized(): Boolean = this::openTelemetry.isInitialized
|
||||||
|
|
@ -124,7 +127,7 @@ class KtorServerTracing private constructor(
|
||||||
setSpanStatusExtractor(configuration.statusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter)))
|
setSpanStatusExtractor(configuration.statusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter)))
|
||||||
addAttributesExtractor(configuration.httpAttributesExtractorBuilder.build())
|
addAttributesExtractor(configuration.httpAttributesExtractorBuilder.build())
|
||||||
addOperationMetrics(HttpServerMetrics.get())
|
addOperationMetrics(HttpServerMetrics.get())
|
||||||
addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
addContextCustomizer(configuration.httpServerRouteBuilder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
val instrumenter = InstrumenterUtil.buildUpstreamInstrumenter(
|
val instrumenter = InstrumenterUtil.buildUpstreamInstrumenter(
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,10 @@ abstract class AbstractKtorHttpServerTest : AbstractHttpServerTest<ApplicationEn
|
||||||
HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES - SemanticAttributes.NET_PEER_PORT
|
HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES - SemanticAttributes.NET_PEER_PORT
|
||||||
}
|
}
|
||||||
|
|
||||||
options.setExpectedHttpRoute {
|
options.setExpectedHttpRoute { endpoint, method ->
|
||||||
when (it) {
|
when (endpoint) {
|
||||||
ServerEndpoint.PATH_PARAM -> "/path/{id}/param"
|
ServerEndpoint.PATH_PARAM -> "/path/{id}/param"
|
||||||
else -> expectedHttpRoute(it)
|
else -> expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,10 @@ public final class LibertyDispatcherSingletons {
|
||||||
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
.build())
|
.build())
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get());
|
.addOperationMetrics(HttpServerMetrics.get());
|
||||||
if (CommonConfig.get().shouldEmitExperimentalHttpServerMetrics()) {
|
if (CommonConfig.get().shouldEmitExperimentalHttpServerMetrics()) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,10 @@ final class NettyServerSingletons {
|
||||||
builder
|
builder
|
||||||
.addContextCustomizer(
|
.addContextCustomizer(
|
||||||
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context))
|
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context))
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpServerAttributesGetter))
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpServerAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build())
|
||||||
.buildServerInstrumenter(NettyHeadersGetter.INSTANCE);
|
.buildServerInstrumenter(NettyHeadersGetter.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -33,6 +34,7 @@ public final class NettyServerInstrumenterFactory {
|
||||||
Consumer<HttpServerAttributesExtractorBuilder<HttpRequestAndChannel, HttpResponse>>
|
Consumer<HttpServerAttributesExtractorBuilder<HttpRequestAndChannel, HttpResponse>>
|
||||||
extractorConfigurer,
|
extractorConfigurer,
|
||||||
Consumer<HttpSpanNameExtractorBuilder<HttpRequestAndChannel>> spanNameExtractorConfigurer,
|
Consumer<HttpSpanNameExtractorBuilder<HttpRequestAndChannel>> spanNameExtractorConfigurer,
|
||||||
|
Consumer<HttpServerRouteBuilder<HttpRequestAndChannel>> httpServerRouteConfigurer,
|
||||||
boolean emitExperimentalHttpServerMetrics) {
|
boolean emitExperimentalHttpServerMetrics) {
|
||||||
|
|
||||||
NettyHttpServerAttributesGetter httpAttributesGetter = new NettyHttpServerAttributesGetter();
|
NettyHttpServerAttributesGetter httpAttributesGetter = new NettyHttpServerAttributesGetter();
|
||||||
|
|
@ -55,9 +57,13 @@ public final class NettyServerInstrumenterFactory {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HttpServerRouteBuilder<HttpRequestAndChannel> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter);
|
||||||
|
httpServerRouteConfigurer.accept(httpServerRouteBuilder);
|
||||||
|
|
||||||
return builder
|
return builder
|
||||||
.addContextCustomizer((context, request, attributes) -> NettyErrorHolder.init(context))
|
.addContextCustomizer((context, request, attributes) -> NettyErrorHolder.init(context))
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(httpServerRouteBuilder.build())
|
||||||
.buildServerInstrumenter(HttpRequestHeadersGetter.INSTANCE);
|
.buildServerInstrumenter(HttpRequestHeadersGetter.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ public final class NettyServerSingletons {
|
||||||
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
||||||
builder -> builder.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
builder -> builder.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
||||||
|
builder -> builder.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
||||||
CommonConfig.get().shouldEmitExperimentalHttpServerMetrics());
|
CommonConfig.get().shouldEmitExperimentalHttpServerMetrics());
|
||||||
|
|
||||||
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
|
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ public final class NettyServerSingletons {
|
||||||
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
||||||
builder -> builder.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
builder -> builder.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
||||||
|
builder -> builder.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods()),
|
||||||
CommonConfig.get().shouldEmitExperimentalHttpServerMetrics());
|
CommonConfig.get().shouldEmitExperimentalHttpServerMetrics());
|
||||||
|
|
||||||
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
|
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import io.netty.handler.codec.http.HttpResponse;
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractorBuilder;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.netty.v4.common.HttpRequestAndChannel;
|
import io.opentelemetry.instrumentation.netty.v4.common.HttpRequestAndChannel;
|
||||||
import io.opentelemetry.instrumentation.netty.v4.common.internal.server.NettyServerInstrumenterFactory;
|
import io.opentelemetry.instrumentation.netty.v4.common.internal.server.NettyServerInstrumenterFactory;
|
||||||
|
|
@ -25,6 +26,8 @@ public final class NettyServerTelemetryBuilder {
|
||||||
extractorConfigurer = builder -> {};
|
extractorConfigurer = builder -> {};
|
||||||
private Consumer<HttpSpanNameExtractorBuilder<HttpRequestAndChannel>>
|
private Consumer<HttpSpanNameExtractorBuilder<HttpRequestAndChannel>>
|
||||||
spanNameExtractorConfigurer = builder -> {};
|
spanNameExtractorConfigurer = builder -> {};
|
||||||
|
private Consumer<HttpServerRouteBuilder<HttpRequestAndChannel>> httpServerRouteConfigurer =
|
||||||
|
builder -> {};
|
||||||
private boolean emitExperimentalHttpServerMetrics = false;
|
private boolean emitExperimentalHttpServerMetrics = false;
|
||||||
|
|
||||||
NettyServerTelemetryBuilder(OpenTelemetry openTelemetry) {
|
NettyServerTelemetryBuilder(OpenTelemetry openTelemetry) {
|
||||||
|
|
@ -78,6 +81,8 @@ public final class NettyServerTelemetryBuilder {
|
||||||
extractorConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
extractorConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
||||||
spanNameExtractorConfigurer =
|
spanNameExtractorConfigurer =
|
||||||
spanNameExtractorConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
spanNameExtractorConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
||||||
|
httpServerRouteConfigurer =
|
||||||
|
httpServerRouteConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,6 +107,7 @@ public final class NettyServerTelemetryBuilder {
|
||||||
"io.opentelemetry.netty-4.1",
|
"io.opentelemetry.netty-4.1",
|
||||||
extractorConfigurer,
|
extractorConfigurer,
|
||||||
spanNameExtractorConfigurer,
|
spanNameExtractorConfigurer,
|
||||||
|
httpServerRouteConfigurer,
|
||||||
emitExperimentalHttpServerMetrics));
|
emitExperimentalHttpServerMetrics));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,4 +115,9 @@ class PlayServerTest extends HttpServerTest<Server> implements AgentTestTrait {
|
||||||
attributes.remove(SemanticAttributes.HTTP_ROUTE)
|
attributes.remove(SemanticAttributes.HTTP_ROUTE)
|
||||||
attributes
|
attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getResponseCodeOnNonStandardHttpMethod() {
|
||||||
|
404
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,4 +105,10 @@ class PlayServerTest extends HttpServerTest<Server> implements AgentTestTrait {
|
||||||
Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
|
Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
|
||||||
[]
|
[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testNonStandardHttpMethod() {
|
||||||
|
// instrumentation does not create a server span at all
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ abstract class AbstractRatpackHttpServerTest extends HttpServerTest<RatpackServe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
return endpoint.status == 404 ? "/" : endpoint == PATH_PARAM ? "/path/:id/param" : endpoint.path
|
return endpoint.status == 404 ? "/" : endpoint == PATH_PARAM ? "/path/:id/param" : endpoint.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -51,6 +52,9 @@ public final class RatpackTelemetryBuilder {
|
||||||
private final HttpSpanNameExtractorBuilder<Request> httpServerSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<Request> httpServerSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(RatpackHttpAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(RatpackHttpAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
|
private final HttpServerRouteBuilder<Request> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(RatpackHttpAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
private final List<AttributesExtractor<? super RequestSpec, ? super HttpResponse>>
|
private final List<AttributesExtractor<? super RequestSpec, ? super HttpResponse>>
|
||||||
additionalHttpClientExtractors = new ArrayList<>();
|
additionalHttpClientExtractors = new ArrayList<>();
|
||||||
|
|
||||||
|
|
@ -143,6 +147,7 @@ public final class RatpackTelemetryBuilder {
|
||||||
httpServerAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpServerAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpClientSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpClientSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpServerSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpServerSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,7 +192,7 @@ public final class RatpackTelemetryBuilder {
|
||||||
.addAttributesExtractor(httpServerAttributesExtractorBuilder.build())
|
.addAttributesExtractor(httpServerAttributesExtractorBuilder.build())
|
||||||
.addAttributesExtractors(additionalExtractors)
|
.addAttributesExtractors(additionalExtractors)
|
||||||
.addOperationMetrics(HttpServerMetrics.get())
|
.addOperationMetrics(HttpServerMetrics.get())
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributes));
|
.addContextCustomizer(httpServerRouteBuilder.build());
|
||||||
if (emitExperimentalHttpServerMetrics) {
|
if (emitExperimentalHttpServerMetrics) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,12 @@ import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||||
class RestletServerTest extends AbstractRestletServerTest implements AgentTestTrait {
|
class RestletServerTest extends AbstractRestletServerTest implements AgentTestTrait {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/"
|
return getContextPath() + "/"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -37,6 +38,8 @@ public final class RestletTelemetryBuilder {
|
||||||
HttpServerAttributesExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
HttpServerAttributesExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
||||||
private final HttpSpanNameExtractorBuilder<Request> httpSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<Request> httpSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
||||||
|
private final HttpServerRouteBuilder<Request> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(RestletHttpAttributesGetter.INSTANCE);
|
||||||
private boolean emitExperimentalHttpServerMetrics = false;
|
private boolean emitExperimentalHttpServerMetrics = false;
|
||||||
|
|
||||||
RestletTelemetryBuilder(OpenTelemetry openTelemetry) {
|
RestletTelemetryBuilder(OpenTelemetry openTelemetry) {
|
||||||
|
|
@ -93,6 +96,7 @@ public final class RestletTelemetryBuilder {
|
||||||
public RestletTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
public RestletTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
||||||
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +126,7 @@ public final class RestletTelemetryBuilder {
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
||||||
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
|
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
|
||||||
.addAttributesExtractors(additionalExtractors)
|
.addAttributesExtractors(additionalExtractors)
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(httpServerRouteBuilder.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get());
|
.addOperationMetrics(HttpServerMetrics.get());
|
||||||
if (emitExperimentalHttpServerMetrics) {
|
if (emitExperimentalHttpServerMetrics) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
|
|
|
||||||
|
|
@ -168,14 +168,14 @@ abstract class AbstractRestletServerTest extends HttpServerTest<Server> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,14 +63,14 @@ abstract class AbstractServletServerTest extends HttpServerTest<Server> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.restlet.v2_0;
|
||||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteGetter;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteGetter;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletHttpAttributesGetter;
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletHttpAttributesGetter;
|
||||||
|
|
@ -31,6 +32,9 @@ public final class RestletSingletons {
|
||||||
HttpSpanNameExtractor.builder(RestletHttpAttributesGetter.INSTANCE)
|
HttpSpanNameExtractor.builder(RestletHttpAttributesGetter.INSTANCE)
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
.build(),
|
.build(),
|
||||||
|
HttpServerRoute.builder(RestletHttpAttributesGetter.INSTANCE)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build(),
|
||||||
Collections.emptyList(),
|
Collections.emptyList(),
|
||||||
CommonConfig.get().shouldEmitExperimentalHttpServerMetrics());
|
CommonConfig.get().shouldEmitExperimentalHttpServerMetrics());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,12 @@ import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||||
class RestletServerTest extends AbstractRestletServerTest implements AgentTestTrait {
|
class RestletServerTest extends AbstractRestletServerTest implements AgentTestTrait {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/"
|
return getContextPath() + "/"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractorBuilder;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletHttpAttributesGetter;
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletHttpAttributesGetter;
|
||||||
|
|
@ -32,6 +34,9 @@ public final class RestletTelemetryBuilder {
|
||||||
HttpServerAttributesExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
HttpServerAttributesExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
||||||
private final HttpSpanNameExtractorBuilder<Request> httpSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<Request> httpSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(RestletHttpAttributesGetter.INSTANCE);
|
||||||
|
private final HttpServerRouteBuilder<Request> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(RestletHttpAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
private boolean emitExperimentalHttpServerMetrics = false;
|
private boolean emitExperimentalHttpServerMetrics = false;
|
||||||
|
|
||||||
RestletTelemetryBuilder(OpenTelemetry openTelemetry) {
|
RestletTelemetryBuilder(OpenTelemetry openTelemetry) {
|
||||||
|
|
@ -88,6 +93,7 @@ public final class RestletTelemetryBuilder {
|
||||||
public RestletTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
public RestletTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
||||||
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,6 +120,7 @@ public final class RestletTelemetryBuilder {
|
||||||
openTelemetry,
|
openTelemetry,
|
||||||
httpAttributesExtractorBuilder.build(),
|
httpAttributesExtractorBuilder.build(),
|
||||||
httpSpanNameExtractorBuilder.build(),
|
httpSpanNameExtractorBuilder.build(),
|
||||||
|
httpServerRouteBuilder.build(),
|
||||||
additionalExtractors,
|
additionalExtractors,
|
||||||
emitExperimentalHttpServerMetrics);
|
emitExperimentalHttpServerMetrics);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ package io.opentelemetry.instrumentation.restlet.v2_0.internal;
|
||||||
|
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.restlet.Request;
|
import org.restlet.Request;
|
||||||
|
|
@ -30,6 +30,7 @@ public final class RestletInstrumenterFactory {
|
||||||
OpenTelemetry openTelemetry,
|
OpenTelemetry openTelemetry,
|
||||||
AttributesExtractor<Request, Response> httpServerAttributesExtractor,
|
AttributesExtractor<Request, Response> httpServerAttributesExtractor,
|
||||||
SpanNameExtractor<Request> httpServerSpanNameExtractor,
|
SpanNameExtractor<Request> httpServerSpanNameExtractor,
|
||||||
|
ContextCustomizer<Request> httpServerRoute,
|
||||||
List<AttributesExtractor<Request, Response>> additionalExtractors,
|
List<AttributesExtractor<Request, Response>> additionalExtractors,
|
||||||
boolean emitExperimentalHttpServerMetrics) {
|
boolean emitExperimentalHttpServerMetrics) {
|
||||||
|
|
||||||
|
|
@ -41,7 +42,7 @@ public final class RestletInstrumenterFactory {
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
||||||
.addAttributesExtractor(httpServerAttributesExtractor)
|
.addAttributesExtractor(httpServerAttributesExtractor)
|
||||||
.addAttributesExtractors(additionalExtractors)
|
.addAttributesExtractors(additionalExtractors)
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(httpServerRoute)
|
||||||
.addOperationMetrics(HttpServerMetrics.get());
|
.addOperationMetrics(HttpServerMetrics.get());
|
||||||
if (emitExperimentalHttpServerMetrics) {
|
if (emitExperimentalHttpServerMetrics) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
|
|
|
||||||
|
|
@ -176,14 +176,14 @@ abstract class AbstractRestletServerTest extends HttpServerTest<Server> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,16 @@
|
||||||
package io.opentelemetry.javaagent.instrumentation.servlet.v2_2;
|
package io.opentelemetry.javaagent.instrumentation.servlet.v2_2;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||||
|
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
|
||||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletAccessor;
|
import io.opentelemetry.javaagent.instrumentation.servlet.ServletAccessor;
|
||||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletRequestContext;
|
import io.opentelemetry.javaagent.instrumentation.servlet.ServletRequestContext;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class Servlet2SpanNameExtractor<REQUEST, RESPONSE>
|
public class Servlet2SpanNameExtractor<REQUEST, RESPONSE>
|
||||||
implements SpanNameExtractor<ServletRequestContext<REQUEST>> {
|
implements SpanNameExtractor<ServletRequestContext<REQUEST>> {
|
||||||
|
|
||||||
private final ServletAccessor<REQUEST, RESPONSE> accessor;
|
private final ServletAccessor<REQUEST, RESPONSE> accessor;
|
||||||
|
private final Set<String> knownMethods = CommonConfig.get().getKnownHttpRequestMethods();
|
||||||
|
|
||||||
public Servlet2SpanNameExtractor(ServletAccessor<REQUEST, RESPONSE> accessor) {
|
public Servlet2SpanNameExtractor(ServletAccessor<REQUEST, RESPONSE> accessor) {
|
||||||
this.accessor = accessor;
|
this.accessor = accessor;
|
||||||
|
|
@ -22,7 +26,12 @@ public class Servlet2SpanNameExtractor<REQUEST, RESPONSE>
|
||||||
REQUEST request = requestContext.request();
|
REQUEST request = requestContext.request();
|
||||||
String method = accessor.getRequestMethod(request);
|
String method = accessor.getRequestMethod(request);
|
||||||
String servletPath = accessor.getRequestServletPath(request);
|
String servletPath = accessor.getRequestServletPath(request);
|
||||||
if (method != null) {
|
if (method == null) {
|
||||||
|
return "HTTP";
|
||||||
|
}
|
||||||
|
if (!knownMethods.contains(method)) {
|
||||||
|
method = "HTTP";
|
||||||
|
}
|
||||||
if (servletPath.isEmpty()) {
|
if (servletPath.isEmpty()) {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +41,4 @@ public class Servlet2SpanNameExtractor<REQUEST, RESPONSE>
|
||||||
}
|
}
|
||||||
return method + " " + contextPath + servletPath;
|
return method + " " + contextPath + servletPath;
|
||||||
}
|
}
|
||||||
return "HTTP request";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import io.opentelemetry.api.common.AttributeKey
|
import io.opentelemetry.api.common.AttributeKey
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
|
|
@ -83,6 +84,9 @@ class JettyServlet2Test extends HttpServerTest<Server> implements AgentTestTrait
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedServerSpanName(ServerEndpoint endpoint, String method, @Nullable String route) {
|
String expectedServerSpanName(ServerEndpoint endpoint, String method, @Nullable String route) {
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return "HTTP " + endpoint.resolvePath(address).path
|
||||||
|
}
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return method
|
return method
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
import io.opentelemetry.api.trace.SpanKind
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||||
import io.opentelemetry.javaagent.bootstrap.servlet.ExperimentalSnippetHolder
|
import io.opentelemetry.javaagent.bootstrap.servlet.ExperimentalSnippetHolder
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
|
|
||||||
import javax.servlet.Servlet
|
import javax.servlet.Servlet
|
||||||
|
|
||||||
|
|
@ -82,12 +84,19 @@ abstract class AbstractServlet3Test<SERVER, CONTEXT> extends HttpServerTest<SERV
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
// no need to compute route if we're not expecting it
|
||||||
|
if (!httpAttributes(endpoint).contains(SemanticAttributes.HTTP_ROUTE)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return endpoint.resolvePath(address).path
|
||||||
|
}
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +156,7 @@ abstract class AbstractServlet3Test<SERVER, CONTEXT> extends HttpServerTest<SERV
|
||||||
cleanup:
|
cleanup:
|
||||||
ExperimentalSnippetHolder.setSnippet("")
|
ExperimentalSnippetHolder.setSnippet("")
|
||||||
|
|
||||||
def expectedRoute = expectedHttpRoute(HTML_SERVLET_OUTPUT_STREAM)
|
def expectedRoute = expectedHttpRoute(HTML_SERVLET_OUTPUT_STREAM, "GET")
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 2) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
|
@ -190,7 +199,7 @@ abstract class AbstractServlet3Test<SERVER, CONTEXT> extends HttpServerTest<SERV
|
||||||
cleanup:
|
cleanup:
|
||||||
ExperimentalSnippetHolder.setSnippet("")
|
ExperimentalSnippetHolder.setSnippet("")
|
||||||
|
|
||||||
def expectedRoute = expectedHttpRoute(HTML_PRINT_WRITER)
|
def expectedRoute = expectedHttpRoute(HTML_PRINT_WRITER, "GET")
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 2) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test<Tomcat, Context>
|
||||||
|
|
||||||
(0..count - 1).each {
|
(0..count - 1).each {
|
||||||
trace(it, 2) {
|
trace(it, 2) {
|
||||||
serverSpan(it, 0, null, null, "GET", ACCESS_LOG_SUCCESS.body.length(), ACCESS_LOG_SUCCESS)
|
serverSpan(it, 0, null, null, "GET", ACCESS_LOG_SUCCESS)
|
||||||
controllerSpan(it, 1, span(0))
|
controllerSpan(it, 1, span(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ abstract class TomcatServlet3Test extends AbstractServlet3Test<Tomcat, Context>
|
||||||
}
|
}
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, spanCount) {
|
trace(0, spanCount) {
|
||||||
serverSpan(it, 0, null, null, method, response.content().length(), ACCESS_LOG_ERROR)
|
serverSpan(it, 0, null, null, method, ACCESS_LOG_ERROR)
|
||||||
def spanIndex = 1
|
def spanIndex = 1
|
||||||
controllerSpan(it, spanIndex, span(spanIndex - 1))
|
controllerSpan(it, spanIndex, span(spanIndex - 1))
|
||||||
spanIndex++
|
spanIndex++
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
import io.opentelemetry.api.trace.SpanKind
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||||
import io.opentelemetry.javaagent.bootstrap.servlet.ExperimentalSnippetHolder
|
import io.opentelemetry.javaagent.bootstrap.servlet.ExperimentalSnippetHolder
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
import jakarta.servlet.Servlet
|
import jakarta.servlet.Servlet
|
||||||
|
|
||||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED
|
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED
|
||||||
|
|
@ -91,12 +93,19 @@ abstract class AbstractServlet5Test<SERVER, CONTEXT> extends HttpServerTest<SERV
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
// no need to compute route if we're not expecting it
|
||||||
|
if (!httpAttributes(endpoint).contains(SemanticAttributes.HTTP_ROUTE)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return endpoint.resolvePath(address).path
|
||||||
|
}
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +156,7 @@ abstract class AbstractServlet5Test<SERVER, CONTEXT> extends HttpServerTest<SERV
|
||||||
cleanup:
|
cleanup:
|
||||||
ExperimentalSnippetHolder.setSnippet("")
|
ExperimentalSnippetHolder.setSnippet("")
|
||||||
|
|
||||||
def expectedRoute = expectedHttpRoute(HTML_SERVLET_OUTPUT_STREAM)
|
def expectedRoute = expectedHttpRoute(HTML_SERVLET_OUTPUT_STREAM, "GET")
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 2) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
|
@ -190,7 +199,7 @@ abstract class AbstractServlet5Test<SERVER, CONTEXT> extends HttpServerTest<SERV
|
||||||
cleanup:
|
cleanup:
|
||||||
ExperimentalSnippetHolder.setSnippet("")
|
ExperimentalSnippetHolder.setSnippet("")
|
||||||
|
|
||||||
def expectedRoute = expectedHttpRoute(HTML_PRINT_WRITER)
|
def expectedRoute = expectedHttpRoute(HTML_PRINT_WRITER, "GET")
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 2) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test<Tomcat, Context>
|
||||||
|
|
||||||
(0..count - 1).each {
|
(0..count - 1).each {
|
||||||
trace(it, 2) {
|
trace(it, 2) {
|
||||||
serverSpan(it, 0, null, null, "GET", ACCESS_LOG_SUCCESS.body.length(), ACCESS_LOG_SUCCESS)
|
serverSpan(it, 0, null, null, "GET", ACCESS_LOG_SUCCESS)
|
||||||
controllerSpan(it, 1, span(0))
|
controllerSpan(it, 1, span(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ abstract class TomcatServlet5Test extends AbstractServlet5Test<Tomcat, Context>
|
||||||
}
|
}
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, spanCount) {
|
trace(0, spanCount) {
|
||||||
serverSpan(it, 0, null, null, method, response.content().length(), ACCESS_LOG_ERROR)
|
serverSpan(it, 0, null, null, method, ACCESS_LOG_ERROR)
|
||||||
def spanIndex = 1
|
def spanIndex = 1
|
||||||
controllerSpan(it, spanIndex, span(spanIndex - 1))
|
controllerSpan(it, spanIndex, span(spanIndex - 1))
|
||||||
spanIndex++
|
spanIndex++
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,10 @@ public final class ServletInstrumenterBuilder<REQUEST, RESPONSE> {
|
||||||
.build())
|
.build())
|
||||||
.addAttributesExtractor(additionalAttributesExtractor)
|
.addAttributesExtractor(additionalAttributesExtractor)
|
||||||
.addOperationMetrics(HttpServerMetrics.get())
|
.addOperationMetrics(HttpServerMetrics.get())
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter));
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build());
|
||||||
if (ServletRequestParametersExtractor.enabled()) {
|
if (ServletRequestParametersExtractor.enabled()) {
|
||||||
AttributesExtractor<ServletRequestContext<REQUEST>, ServletResponseContext<RESPONSE>>
|
AttributesExtractor<ServletRequestContext<REQUEST>, ServletResponseContext<RESPONSE>>
|
||||||
requestParametersExtractor = new ServletRequestParametersExtractor<>(accessor);
|
requestParametersExtractor = new ServletRequestParametersExtractor<>(accessor);
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,6 @@ public class ImmediateHandlerSpringWebFluxServerTest extends HandlerSpringWebFlu
|
||||||
assertThat(response.contentUtf8()).isEqualTo(NESTED_PATH.getBody());
|
assertThat(response.contentUtf8()).isEqualTo(NESTED_PATH.getBody());
|
||||||
assertResponseHasCustomizedHeaders(response, NESTED_PATH, null);
|
assertResponseHasCustomizedHeaders(response, NESTED_PATH, null);
|
||||||
|
|
||||||
assertTheTraces(1, null, null, null, method, NESTED_PATH, response);
|
assertTheTraces(1, null, null, null, method, NESTED_PATH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ public abstract class SpringWebFluxServerTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String expectedHttpRoute(ServerEndpoint endpoint) {
|
public String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
if (endpoint.equals(PATH_PARAM)) {
|
if (endpoint.equals(PATH_PARAM)) {
|
||||||
return getContextPath() + "/path/{id}/param";
|
return getContextPath() + "/path/{id}/param";
|
||||||
} else if (endpoint.equals(NOT_FOUND)) {
|
} else if (endpoint.equals(NOT_FOUND)) {
|
||||||
|
|
@ -57,7 +57,7 @@ public abstract class SpringWebFluxServerTest
|
||||||
} else if (endpoint.equals(NESTED_PATH)) {
|
} else if (endpoint.equals(NESTED_PATH)) {
|
||||||
return "/nestedPath/hello/world";
|
return "/nestedPath/hello/world";
|
||||||
}
|
}
|
||||||
return super.expectedHttpRoute(endpoint);
|
return super.expectedHttpRoute(endpoint, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -44,6 +45,8 @@ public final class SpringWebfluxTelemetryBuilder {
|
||||||
HttpServerAttributesExtractor.builder(WebfluxServerHttpAttributesGetter.INSTANCE);
|
HttpServerAttributesExtractor.builder(WebfluxServerHttpAttributesGetter.INSTANCE);
|
||||||
private final HttpSpanNameExtractorBuilder<ServerWebExchange> httpServerSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<ServerWebExchange> httpServerSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(WebfluxServerHttpAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(WebfluxServerHttpAttributesGetter.INSTANCE);
|
||||||
|
private final HttpServerRouteBuilder<ServerWebExchange> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(WebfluxServerHttpAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
private Consumer<HttpClientAttributesExtractorBuilder<ClientRequest, ClientResponse>>
|
private Consumer<HttpClientAttributesExtractorBuilder<ClientRequest, ClientResponse>>
|
||||||
clientExtractorConfigurer = builder -> {};
|
clientExtractorConfigurer = builder -> {};
|
||||||
|
|
@ -167,6 +170,7 @@ public final class SpringWebfluxTelemetryBuilder {
|
||||||
clientSpanNameExtractorConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
clientSpanNameExtractorConfigurer.andThen(builder -> builder.setKnownMethods(knownMethods));
|
||||||
httpServerAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpServerAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpServerSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpServerSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,7 +231,7 @@ public final class SpringWebfluxTelemetryBuilder {
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(getter))
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(getter))
|
||||||
.addAttributesExtractor(httpServerAttributesExtractorBuilder.build())
|
.addAttributesExtractor(httpServerAttributesExtractorBuilder.build())
|
||||||
.addAttributesExtractors(serverAdditionalExtractors)
|
.addAttributesExtractors(serverAdditionalExtractors)
|
||||||
.addContextCustomizer(HttpServerRoute.create(getter))
|
.addContextCustomizer(httpServerRouteBuilder.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get());
|
.addOperationMetrics(HttpServerMetrics.get());
|
||||||
if (emitExperimentalHttpServerMetrics) {
|
if (emitExperimentalHttpServerMetrics) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,11 @@ public final class SpringWebfluxServerInstrumentationTest
|
||||||
options.setExpectedException(new RuntimeException(ServerEndpoint.EXCEPTION.getBody()));
|
options.setExpectedException(new RuntimeException(ServerEndpoint.EXCEPTION.getBody()));
|
||||||
|
|
||||||
options.setExpectedHttpRoute(
|
options.setExpectedHttpRoute(
|
||||||
endpoint -> {
|
(endpoint, method) -> {
|
||||||
if (endpoint == ServerEndpoint.PATH_PARAM) {
|
if (endpoint == ServerEndpoint.PATH_PARAM) {
|
||||||
return CONTEXT_PATH + "/path/{id}/param";
|
return CONTEXT_PATH + "/path/{id}/param";
|
||||||
}
|
}
|
||||||
return expectedHttpRoute(endpoint);
|
return expectedHttpRoute(endpoint, method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -40,6 +41,8 @@ public final class SpringWebMvcTelemetryBuilder {
|
||||||
HttpServerAttributesExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
HttpServerAttributesExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
||||||
private final HttpSpanNameExtractorBuilder<HttpServletRequest> httpSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<HttpServletRequest> httpSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
||||||
|
private final HttpServerRouteBuilder<HttpServletRequest> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Function<
|
private Function<
|
||||||
|
|
@ -114,6 +117,7 @@ public final class SpringWebMvcTelemetryBuilder {
|
||||||
public SpringWebMvcTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
public SpringWebMvcTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
||||||
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +155,7 @@ public final class SpringWebMvcTelemetryBuilder {
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
||||||
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
|
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
|
||||||
.addAttributesExtractors(additionalExtractors)
|
.addAttributesExtractors(additionalExtractors)
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(httpServerRouteBuilder.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get());
|
.addOperationMetrics(HttpServerMetrics.get());
|
||||||
if (emitExperimentalHttpServerMetrics) {
|
if (emitExperimentalHttpServerMetrics) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,11 @@ class WebMvcHttpServerTest extends AbstractHttpServerTest<ConfigurableApplicatio
|
||||||
options.setTestException(false);
|
options.setTestException(false);
|
||||||
|
|
||||||
options.setExpectedHttpRoute(
|
options.setExpectedHttpRoute(
|
||||||
endpoint -> {
|
(endpoint, method) -> {
|
||||||
if (endpoint == ServerEndpoint.PATH_PARAM) {
|
if (endpoint == ServerEndpoint.PATH_PARAM) {
|
||||||
return CONTEXT_PATH + "/path/{id}/param";
|
return CONTEXT_PATH + "/path/{id}/param";
|
||||||
}
|
}
|
||||||
return expectedHttpRoute(endpoint);
|
return expectedHttpRoute(endpoint, method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttribut
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerExperimentalMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractorBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
|
@ -40,6 +41,8 @@ public final class SpringWebMvcTelemetryBuilder {
|
||||||
HttpServerAttributesExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
HttpServerAttributesExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
||||||
private final HttpSpanNameExtractorBuilder<HttpServletRequest> httpSpanNameExtractorBuilder =
|
private final HttpSpanNameExtractorBuilder<HttpServletRequest> httpSpanNameExtractorBuilder =
|
||||||
HttpSpanNameExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
HttpSpanNameExtractor.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
||||||
|
private final HttpServerRouteBuilder<HttpServletRequest> httpServerRouteBuilder =
|
||||||
|
HttpServerRoute.builder(SpringWebMvcHttpAttributesGetter.INSTANCE);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Function<
|
private Function<
|
||||||
|
|
@ -114,6 +117,7 @@ public final class SpringWebMvcTelemetryBuilder {
|
||||||
public SpringWebMvcTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
public SpringWebMvcTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
|
||||||
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
httpSpanNameExtractorBuilder.setKnownMethods(knownMethods);
|
||||||
|
httpServerRouteBuilder.setKnownMethods(knownMethods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +155,7 @@ public final class SpringWebMvcTelemetryBuilder {
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
||||||
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
|
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
|
||||||
.addAttributesExtractors(additionalExtractors)
|
.addAttributesExtractors(additionalExtractors)
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(httpServerRouteBuilder.build())
|
||||||
.addOperationMetrics(HttpServerMetrics.get());
|
.addOperationMetrics(HttpServerMetrics.get());
|
||||||
if (emitExperimentalHttpServerMetrics) {
|
if (emitExperimentalHttpServerMetrics) {
|
||||||
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
builder.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,11 @@ class WebMvcHttpServerTest extends AbstractHttpServerTest<ConfigurableApplicatio
|
||||||
options.setTestException(false);
|
options.setTestException(false);
|
||||||
|
|
||||||
options.setExpectedHttpRoute(
|
options.setExpectedHttpRoute(
|
||||||
endpoint -> {
|
(endpoint, method) -> {
|
||||||
if (endpoint == ServerEndpoint.PATH_PARAM) {
|
if (endpoint == ServerEndpoint.PATH_PARAM) {
|
||||||
return CONTEXT_PATH + "/path/{id}/param";
|
return CONTEXT_PATH + "/path/{id}/param";
|
||||||
}
|
}
|
||||||
return expectedHttpRoute(endpoint);
|
return expectedHttpRoute(endpoint, method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ abstract class AbstractSpringBootBasedTest extends HttpServerTest<ConfigurableAp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
|
|
@ -94,7 +94,7 @@ abstract class AbstractSpringBootBasedTest extends HttpServerTest<ConfigurableAp
|
||||||
case LOGIN:
|
case LOGIN:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ abstract class AbstractSpringBootBasedTest extends HttpServerTest<ConfigurableAp
|
||||||
and:
|
and:
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 3) {
|
trace(0, 3) {
|
||||||
serverSpan(it, 0, null, null, "GET", null, AUTH_ERROR)
|
serverSpan(it, 0, null, null, "GET", AUTH_ERROR)
|
||||||
sendErrorSpan(it, 1, span(0))
|
sendErrorSpan(it, 1, span(0))
|
||||||
errorPageSpans(it, 2, null)
|
errorPageSpans(it, 2, null)
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +140,7 @@ abstract class AbstractSpringBootBasedTest extends HttpServerTest<ConfigurableAp
|
||||||
and:
|
and:
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 2) {
|
trace(0, 2) {
|
||||||
serverSpan(it, 0, null, null, "POST", response.contentUtf8().length(), LOGIN)
|
serverSpan(it, 0, null, null, "POST", LOGIN)
|
||||||
redirectSpan(it, 1, span(0))
|
redirectSpan(it, 1, span(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,14 +83,14 @@ abstract class AbstractServletFilterTest extends HttpServerTest<ConfigurableAppl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/**"
|
return getContextPath() + "/**"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,14 +65,14 @@ class Struts2ActionSpanTest extends HttpServerTest<Server> implements AgentTestT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case PATH_PARAM:
|
case PATH_PARAM:
|
||||||
return getContextPath() + "/path/{id}/param"
|
return getContextPath() + "/path/{id}/param"
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v10_0
|
package io.opentelemetry.javaagent.instrumentation.tomcat.v10_0
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
|
|
@ -107,12 +107,15 @@ class TomcatAsyncTest extends HttpServerTest<Tomcat> implements AgentTestTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return getContextPath() + endpoint.path
|
||||||
|
}
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v10_0
|
package io.opentelemetry.javaagent.instrumentation.tomcat.v10_0
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
|
|
@ -55,6 +55,14 @@ class TomcatHandlerTest extends HttpServerTest<Tomcat> implements AgentTestTrait
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return getContextPath() + endpoint.path
|
||||||
|
}
|
||||||
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Tomcat startServer(int port) {
|
Tomcat startServer(int port) {
|
||||||
Tomcat tomcat = new Tomcat()
|
Tomcat tomcat = new Tomcat()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
|
|
@ -107,12 +107,15 @@ class TomcatAsyncTest extends HttpServerTest<Tomcat> implements AgentTestTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return getContextPath() + endpoint.path
|
||||||
|
}
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return getContextPath() + "/*"
|
return getContextPath() + "/*"
|
||||||
default:
|
default:
|
||||||
return super.expectedHttpRoute(endpoint)
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
|
|
@ -54,6 +55,14 @@ class TomcatHandlerTest extends HttpServerTest<Tomcat> implements AgentTestTrait
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return getContextPath() + endpoint.path
|
||||||
|
}
|
||||||
|
return super.expectedHttpRoute(endpoint, method)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Tomcat startServer(int port) {
|
Tomcat startServer(int port) {
|
||||||
Tomcat tomcat = new Tomcat()
|
Tomcat tomcat = new Tomcat()
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,10 @@ public final class TomcatInstrumenterFactory {
|
||||||
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
.build())
|
.build())
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build())
|
||||||
.addContextCustomizer(
|
.addContextCustomizer(
|
||||||
(context, request, attributes) ->
|
(context, request, attributes) ->
|
||||||
new AppServerBridge.Builder()
|
new AppServerBridge.Builder()
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,10 @@ public final class UndertowSingletons {
|
||||||
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
||||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
.build())
|
.build())
|
||||||
.addContextCustomizer(HttpServerRoute.create(httpAttributesGetter))
|
.addContextCustomizer(
|
||||||
|
HttpServerRoute.builder(httpAttributesGetter)
|
||||||
|
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||||
|
.build())
|
||||||
.addContextCustomizer(
|
.addContextCustomizer(
|
||||||
(context, request, attributes) -> {
|
(context, request, attributes) -> {
|
||||||
// span is ended when counter reaches 0, we start from 2 which accounts for the
|
// span is ended when counter reaches 0, we start from 2 which accounts for the
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import io.opentelemetry.api.common.AttributeKey
|
||||||
import io.opentelemetry.api.trace.Span
|
import io.opentelemetry.api.trace.Span
|
||||||
import io.opentelemetry.api.trace.SpanId
|
import io.opentelemetry.api.trace.SpanId
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
import io.opentelemetry.api.trace.SpanKind
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.SemconvStability
|
||||||
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
|
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.instrumentation.testing.GlobalTraceUtil
|
import io.opentelemetry.instrumentation.testing.GlobalTraceUtil
|
||||||
|
|
@ -19,7 +21,6 @@ import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
import io.opentelemetry.sdk.trace.data.SpanData
|
||||||
import io.opentelemetry.semconv.SemanticAttributes
|
import io.opentelemetry.semconv.SemanticAttributes
|
||||||
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpRequest
|
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpRequest
|
||||||
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
|
|
||||||
import io.opentelemetry.testing.internal.armeria.common.HttpMethod
|
import io.opentelemetry.testing.internal.armeria.common.HttpMethod
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
@ -49,15 +50,22 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
}
|
}
|
||||||
|
|
||||||
String expectedServerSpanName(ServerEndpoint endpoint, String method, @Nullable String route) {
|
String expectedServerSpanName(ServerEndpoint endpoint, String method, @Nullable String route) {
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
method = "HTTP"
|
||||||
|
}
|
||||||
return route == null ? method : method + " " + route
|
return route == null ? method : method + " " + route
|
||||||
}
|
}
|
||||||
|
|
||||||
String expectedHttpRoute(ServerEndpoint endpoint) {
|
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
// no need to compute route if we're not expecting it
|
// no need to compute route if we're not expecting it
|
||||||
if (!httpAttributes(endpoint).contains(SemanticAttributes.HTTP_ROUTE)) {
|
if (!httpAttributes(endpoint).contains(SemanticAttributes.HTTP_ROUTE)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (method == HttpConstants._OTHER) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case NOT_FOUND:
|
case NOT_FOUND:
|
||||||
return null
|
return null
|
||||||
|
|
@ -96,6 +104,10 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getResponseCodeOnNonStandardHttpMethod() {
|
||||||
|
SUCCESS.status
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasErrorPageSpans(ServerEndpoint endpoint) {
|
boolean hasErrorPageSpans(ServerEndpoint endpoint) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -148,6 +160,10 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testNonStandardHttpMethod() {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
boolean verifyServerSpanEndTime() {
|
boolean verifyServerSpanEndTime() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -199,8 +215,8 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
options.expectedServerSpanNameMapper = { endpoint, method, route ->
|
options.expectedServerSpanNameMapper = { endpoint, method, route ->
|
||||||
HttpServerTest.this.expectedServerSpanName(endpoint, method, route)
|
HttpServerTest.this.expectedServerSpanName(endpoint, method, route)
|
||||||
}
|
}
|
||||||
options.expectedHttpRoute = { endpoint ->
|
options.expectedHttpRoute = { endpoint, method ->
|
||||||
HttpServerTest.this.expectedHttpRoute(endpoint)
|
HttpServerTest.this.expectedHttpRoute(endpoint, method)
|
||||||
}
|
}
|
||||||
options.contextPath = getContextPath()
|
options.contextPath = getContextPath()
|
||||||
options.httpAttributes = { endpoint ->
|
options.httpAttributes = { endpoint ->
|
||||||
|
|
@ -219,6 +235,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
options.metricsInstrumentationName = {
|
options.metricsInstrumentationName = {
|
||||||
HttpServerTest.this.getMetricsInstrumentationName()
|
HttpServerTest.this.getMetricsInstrumentationName()
|
||||||
}
|
}
|
||||||
|
options.responseCodeOnNonStandardHttpMethod = getResponseCodeOnNonStandardHttpMethod()
|
||||||
|
|
||||||
options.testRedirect = testRedirect()
|
options.testRedirect = testRedirect()
|
||||||
options.testError = testError()
|
options.testError = testError()
|
||||||
|
|
@ -229,6 +246,9 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
options.testCaptureHttpHeaders = testCapturedHttpHeaders()
|
options.testCaptureHttpHeaders = testCapturedHttpHeaders()
|
||||||
options.testCaptureRequestParameters = testCapturedRequestParameters()
|
options.testCaptureRequestParameters = testCapturedRequestParameters()
|
||||||
options.testHttpPipelining = testHttpPipelining()
|
options.testHttpPipelining = testHttpPipelining()
|
||||||
|
if (!testNonStandardHttpMethod()) {
|
||||||
|
options.disableTestNonStandardHttpMethod()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override trace assertion method. We can call java assertions from groovy but not the other
|
// Override trace assertion method. We can call java assertions from groovy but not the other
|
||||||
|
|
@ -241,9 +261,8 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
String parentId,
|
String parentId,
|
||||||
String spanId,
|
String spanId,
|
||||||
String method,
|
String method,
|
||||||
ServerEndpoint endpoint,
|
ServerEndpoint endpoint) {
|
||||||
AggregatedHttpResponse response) {
|
HttpServerTest.this.assertTheTraces(size, traceId, parentId, spanId, method, endpoint)
|
||||||
HttpServerTest.this.assertTheTraces(size, traceId, parentId, spanId, method, endpoint, response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -337,6 +356,13 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
junitTest.httpPipelining()
|
junitTest.httpPipelining()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "non standard http method"() {
|
||||||
|
assumeTrue(SemconvStability.emitStableHttpSemconv())
|
||||||
|
assumeTrue(testNonStandardHttpMethod())
|
||||||
|
expect:
|
||||||
|
junitTest.requestWithNonStandardHttpMethod()
|
||||||
|
}
|
||||||
|
|
||||||
void assertHighConcurrency(int count) {
|
void assertHighConcurrency(int count) {
|
||||||
def endpoint = INDEXED_CHILD
|
def endpoint = INDEXED_CHILD
|
||||||
assertTraces(count) {
|
assertTraces(count) {
|
||||||
|
|
@ -372,7 +398,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
|
|
||||||
//FIXME: add tests for POST with large/chunked data
|
//FIXME: add tests for POST with large/chunked data
|
||||||
|
|
||||||
void assertTheTraces(int size, String traceID = null, String parentID = null, String spanID = null, String method = "GET", ServerEndpoint endpoint = SUCCESS, AggregatedHttpResponse response = null) {
|
void assertTheTraces(int size, String traceID = null, String parentID = null, String spanID = null, String method = "GET", ServerEndpoint endpoint = SUCCESS) {
|
||||||
def spanCount = 1 // server span
|
def spanCount = 1 // server span
|
||||||
if (hasResponseSpan(endpoint)) {
|
if (hasResponseSpan(endpoint)) {
|
||||||
spanCount++
|
spanCount++
|
||||||
|
|
@ -398,7 +424,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
assert it.span(0).endEpochNanos - it.span(index).endEpochNanos >= 0
|
assert it.span(0).endEpochNanos - it.span(index).endEpochNanos >= 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverSpan(it, spanIndex++, traceID, parentID, method, response?.content()?.length(), endpoint, spanID)
|
this.serverSpan(it, spanIndex++, traceID, parentID, method, endpoint, spanID)
|
||||||
if (hasHandlerSpan(endpoint)) {
|
if (hasHandlerSpan(endpoint)) {
|
||||||
handlerSpan(it, spanIndex++, span(0), method, endpoint)
|
handlerSpan(it, spanIndex++, span(0), method, endpoint)
|
||||||
}
|
}
|
||||||
|
|
@ -471,10 +497,10 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serverSpan(TraceAssert trace, int index, String traceID = null, String parentID = null, String method = "GET", Long responseContentLength = null, ServerEndpoint endpoint = SUCCESS, String spanID = null) {
|
void serverSpan(TraceAssert trace, int index, String traceID = null, String parentID = null, String method = "GET", ServerEndpoint endpoint = SUCCESS, String spanID = null) {
|
||||||
trace.assertedIndexes.add(index)
|
trace.assertedIndexes.add(index)
|
||||||
def spanData = trace.span(index)
|
def spanData = trace.span(index)
|
||||||
def assertion = junitTest.assertServerSpan(OpenTelemetryAssertions.assertThat(spanData), method, endpoint)
|
def assertion = junitTest.assertServerSpan(OpenTelemetryAssertions.assertThat(spanData), method, endpoint, endpoint.status)
|
||||||
if (parentID == null) {
|
if (parentID == null) {
|
||||||
assertion.hasParentSpanId(SpanId.invalid)
|
assertion.hasParentSpanId(SpanId.invalid)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,10 @@ import io.opentelemetry.api.trace.SpanKind;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
import io.opentelemetry.context.propagation.TextMapSetter;
|
import io.opentelemetry.context.propagation.TextMapSetter;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes;
|
import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes;
|
import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes;
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||||
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
|
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
|
||||||
import io.opentelemetry.instrumentation.testing.GlobalTraceUtil;
|
import io.opentelemetry.instrumentation.testing.GlobalTraceUtil;
|
||||||
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||||
|
|
@ -139,7 +141,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertResponseHasCustomizedHeaders(response, SUCCESS, null);
|
assertResponseHasCustomizedHeaders(response, SUCCESS, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTheTraces(count, null, null, null, method, SUCCESS, responses.get(0));
|
assertTheTraces(count, null, null, null, method, SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -160,7 +162,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.contentUtf8()).isEqualTo(SUCCESS.getBody());
|
assertThat(response.contentUtf8()).isEqualTo(SUCCESS.getBody());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, SUCCESS, traceId);
|
String spanId = assertResponseHasCustomizedHeaders(response, SUCCESS, traceId);
|
||||||
assertTheTraces(1, traceId, parentId, spanId, "GET", SUCCESS, response);
|
assertTheTraces(1, traceId, parentId, spanId, "GET", SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -179,7 +181,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.contentUtf8()).isEqualTo(SUCCESS.getBody());
|
assertThat(response.contentUtf8()).isEqualTo(SUCCESS.getBody());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, SUCCESS, traceId);
|
String spanId = assertResponseHasCustomizedHeaders(response, SUCCESS, traceId);
|
||||||
assertTheTraces(1, traceId, parentId, spanId, "GET", SUCCESS, response);
|
assertTheTraces(1, traceId, parentId, spanId, "GET", SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
|
@ -193,7 +195,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.contentUtf8()).isEqualTo(endpoint.getBody());
|
assertThat(response.contentUtf8()).isEqualTo(endpoint.getBody());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, endpoint, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, endpoint, null);
|
||||||
assertTheTraces(1, null, null, spanId, method, endpoint, response);
|
assertTheTraces(1, null, null, spanId, method, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<ServerEndpoint> provideServerEndpoints() {
|
private static Stream<ServerEndpoint> provideServerEndpoints() {
|
||||||
|
|
@ -217,7 +219,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
.isEqualTo(address.resolve(REDIRECT.getBody()).toString()));
|
.isEqualTo(address.resolve(REDIRECT.getBody()).toString()));
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, REDIRECT, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, REDIRECT, null);
|
||||||
assertTheTraces(1, null, null, spanId, method, REDIRECT, response);
|
assertTheTraces(1, null, null, spanId, method, REDIRECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -234,7 +236,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
}
|
}
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, ERROR, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, ERROR, null);
|
||||||
assertTheTraces(1, null, null, spanId, method, ERROR, response);
|
assertTheTraces(1, null, null, spanId, method, ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -252,7 +254,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.status().code()).isEqualTo(EXCEPTION.getStatus());
|
assertThat(response.status().code()).isEqualTo(EXCEPTION.getStatus());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, EXCEPTION, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, EXCEPTION, null);
|
||||||
assertTheTraces(1, null, null, spanId, method, EXCEPTION, response);
|
assertTheTraces(1, null, null, spanId, method, EXCEPTION);
|
||||||
} finally {
|
} finally {
|
||||||
Awaitility.reset();
|
Awaitility.reset();
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +271,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.status().code()).isEqualTo(NOT_FOUND.getStatus());
|
assertThat(response.status().code()).isEqualTo(NOT_FOUND.getStatus());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, NOT_FOUND, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, NOT_FOUND, null);
|
||||||
assertTheTraces(1, null, null, spanId, method, NOT_FOUND, response);
|
assertTheTraces(1, null, null, spanId, method, NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -284,7 +286,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.contentUtf8()).isEqualTo(PATH_PARAM.getBody());
|
assertThat(response.contentUtf8()).isEqualTo(PATH_PARAM.getBody());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, PATH_PARAM, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, PATH_PARAM, null);
|
||||||
assertTheTraces(1, null, null, spanId, method, PATH_PARAM, response);
|
assertTheTraces(1, null, null, spanId, method, PATH_PARAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -303,7 +305,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.headers().get("X-Test-Response")).isEqualTo("test");
|
assertThat(response.headers().get("X-Test-Response")).isEqualTo("test");
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, CAPTURE_HEADERS, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, CAPTURE_HEADERS, null);
|
||||||
assertTheTraces(1, null, null, spanId, "GET", CAPTURE_HEADERS, response);
|
assertTheTraces(1, null, null, spanId, "GET", CAPTURE_HEADERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -323,7 +325,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
assertThat(response.contentUtf8()).isEqualTo(CAPTURE_PARAMETERS.getBody());
|
assertThat(response.contentUtf8()).isEqualTo(CAPTURE_PARAMETERS.getBody());
|
||||||
|
|
||||||
String spanId = assertResponseHasCustomizedHeaders(response, CAPTURE_PARAMETERS, null);
|
String spanId = assertResponseHasCustomizedHeaders(response, CAPTURE_PARAMETERS, null);
|
||||||
assertTheTraces(1, null, null, spanId, "POST", CAPTURE_PARAMETERS, response);
|
assertTheTraces(1, null, null, spanId, "POST", CAPTURE_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -339,7 +341,8 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
testing.waitAndAssertTraces(
|
testing.waitAndAssertTraces(
|
||||||
trace -> {
|
trace -> {
|
||||||
instrumentationName.set(trace.getSpan(0).getInstrumentationScopeInfo().getName());
|
instrumentationName.set(trace.getSpan(0).getInstrumentationScopeInfo().getName());
|
||||||
trace.anySatisfy(spanData -> assertServerSpan(assertThat(spanData), method, SUCCESS));
|
trace.anySatisfy(
|
||||||
|
spanData -> assertServerSpan(assertThat(spanData), method, SUCCESS, SUCCESS.status));
|
||||||
});
|
});
|
||||||
|
|
||||||
String durationInstrumentName =
|
String durationInstrumentName =
|
||||||
|
|
@ -478,6 +481,54 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void requestWithNonStandardHttpMethod() throws InterruptedException {
|
||||||
|
assumeTrue(SemconvStability.emitStableHttpSemconv());
|
||||||
|
assumeTrue(options.testNonStandardHttpMethod);
|
||||||
|
|
||||||
|
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
|
||||||
|
try {
|
||||||
|
Bootstrap bootstrap = buildBootstrap(eventLoopGroup);
|
||||||
|
Channel channel = bootstrap.connect(address.getHost(), port).sync().channel();
|
||||||
|
|
||||||
|
String method = "TEST";
|
||||||
|
DefaultFullHttpRequest request =
|
||||||
|
new DefaultFullHttpRequest(
|
||||||
|
HttpVersion.HTTP_1_1,
|
||||||
|
new io.opentelemetry.testing.internal.io.netty.handler.codec.http.HttpMethod(method),
|
||||||
|
SUCCESS.resolvePath(address).getPath(),
|
||||||
|
Unpooled.EMPTY_BUFFER);
|
||||||
|
request.headers().set(HttpHeaderNames.HOST, address.getHost() + ":" + port);
|
||||||
|
request.headers().set(HttpHeaderNames.USER_AGENT, TEST_USER_AGENT);
|
||||||
|
request.headers().set(HttpHeaderNames.X_FORWARDED_FOR, TEST_CLIENT_IP);
|
||||||
|
|
||||||
|
testing
|
||||||
|
.getOpenTelemetry()
|
||||||
|
.getPropagators()
|
||||||
|
.getTextMapPropagator()
|
||||||
|
.inject(
|
||||||
|
Context.current(),
|
||||||
|
request,
|
||||||
|
(carrier, key, value) -> carrier.headers().set(key, value));
|
||||||
|
channel.writeAndFlush(request);
|
||||||
|
|
||||||
|
// TODO: add stricter assertions; could be difficult with the groovy code still in place
|
||||||
|
// though
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.anySatisfy(
|
||||||
|
span ->
|
||||||
|
assertServerSpan(
|
||||||
|
assertThat(span),
|
||||||
|
HttpConstants._OTHER,
|
||||||
|
SUCCESS,
|
||||||
|
options.responseCodeOnNonStandardHttpMethod)
|
||||||
|
.hasAttribute(HttpAttributes.HTTP_REQUEST_METHOD_ORIGINAL, method)));
|
||||||
|
} finally {
|
||||||
|
eventLoopGroup.shutdownGracefully().await(10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Bootstrap buildBootstrap(EventLoopGroup eventLoopGroup) {
|
private static Bootstrap buildBootstrap(EventLoopGroup eventLoopGroup) {
|
||||||
Bootstrap bootstrap = new Bootstrap();
|
Bootstrap bootstrap = new Bootstrap();
|
||||||
bootstrap
|
bootstrap
|
||||||
|
|
@ -566,8 +617,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
String parentId,
|
String parentId,
|
||||||
String spanId,
|
String spanId,
|
||||||
String method,
|
String method,
|
||||||
ServerEndpoint endpoint,
|
ServerEndpoint endpoint) {
|
||||||
AggregatedHttpResponse response) {
|
|
||||||
List<Consumer<TraceAssert>> assertions = new ArrayList<>();
|
List<Consumer<TraceAssert>> assertions = new ArrayList<>();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
assertions.add(
|
assertions.add(
|
||||||
|
|
@ -575,7 +625,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
List<Consumer<SpanDataAssert>> spanAssertions = new ArrayList<>();
|
List<Consumer<SpanDataAssert>> spanAssertions = new ArrayList<>();
|
||||||
spanAssertions.add(
|
spanAssertions.add(
|
||||||
span -> {
|
span -> {
|
||||||
assertServerSpan(span, method, endpoint);
|
assertServerSpan(span, method, endpoint, endpoint.status);
|
||||||
if (traceId != null) {
|
if (traceId != null) {
|
||||||
span.hasTraceId(traceId);
|
span.hasTraceId(traceId);
|
||||||
}
|
}
|
||||||
|
|
@ -674,14 +724,14 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0
|
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0
|
||||||
protected SpanDataAssert assertServerSpan(
|
protected SpanDataAssert assertServerSpan(
|
||||||
SpanDataAssert span, String method, ServerEndpoint endpoint) {
|
SpanDataAssert span, String method, ServerEndpoint endpoint, int statusCode) {
|
||||||
|
|
||||||
Set<AttributeKey<?>> httpAttributes = options.httpAttributes.apply(endpoint);
|
Set<AttributeKey<?>> httpAttributes = options.httpAttributes.apply(endpoint);
|
||||||
String expectedRoute = options.expectedHttpRoute.apply(endpoint);
|
String expectedRoute = options.expectedHttpRoute.apply(endpoint, method);
|
||||||
String name = getString(method, endpoint, expectedRoute);
|
String name = options.expectedServerSpanNameMapper.apply(endpoint, method, expectedRoute);
|
||||||
|
|
||||||
span.hasName(name).hasKind(SpanKind.SERVER);
|
span.hasName(name).hasKind(SpanKind.SERVER);
|
||||||
if (endpoint.status >= 500) {
|
if (statusCode >= 500) {
|
||||||
span.hasStatus(StatusData.error());
|
span.hasStatus(StatusData.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -751,7 +801,7 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
}
|
}
|
||||||
assertThat(attrs).containsEntry(getAttributeKey(SemanticAttributes.HTTP_METHOD), method);
|
assertThat(attrs).containsEntry(getAttributeKey(SemanticAttributes.HTTP_METHOD), method);
|
||||||
assertThat(attrs)
|
assertThat(attrs)
|
||||||
.containsEntry(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), endpoint.status);
|
.containsEntry(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), statusCode);
|
||||||
|
|
||||||
AttributeKey<String> netProtocolKey =
|
AttributeKey<String> netProtocolKey =
|
||||||
getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME);
|
getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME);
|
||||||
|
|
@ -823,17 +873,12 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
return SemconvStabilityUtil.getAttributeKey(oldKey);
|
return SemconvStabilityUtil.getAttributeKey(oldKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getString(String method, ServerEndpoint endpoint, String expectedRoute) {
|
|
||||||
String name = options.expectedServerSpanNameMapper.apply(endpoint, method, expectedRoute);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0
|
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0
|
||||||
protected SpanDataAssert assertIndexedServerSpan(SpanDataAssert span, int requestId) {
|
protected SpanDataAssert assertIndexedServerSpan(SpanDataAssert span, int requestId) {
|
||||||
ServerEndpoint endpoint = INDEXED_CHILD;
|
ServerEndpoint endpoint = INDEXED_CHILD;
|
||||||
String method = "GET";
|
String method = "GET";
|
||||||
assertServerSpan(span, method, endpoint);
|
assertServerSpan(span, method, endpoint, endpoint.status);
|
||||||
|
|
||||||
if (SemconvStability.emitOldHttpSemconv()) {
|
if (SemconvStability.emitOldHttpSemconv()) {
|
||||||
span.hasAttributesSatisfying(
|
span.hasAttributesSatisfying(
|
||||||
|
|
@ -865,12 +910,16 @@ public abstract class AbstractHttpServerTest<SERVER> extends AbstractHttpServerU
|
||||||
endpoint, method, route);
|
endpoint, method, route);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String expectedHttpRoute(ServerEndpoint endpoint) {
|
public String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||||
// no need to compute route if we're not expecting it
|
// no need to compute route if we're not expecting it
|
||||||
if (!options.httpAttributes.apply(endpoint).contains(SemanticAttributes.HTTP_ROUTE)) {
|
if (!options.httpAttributes.apply(endpoint).contains(SemanticAttributes.HTTP_ROUTE)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HttpConstants._OTHER.equals(method)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (NOT_FOUND.equals(endpoint)) {
|
if (NOT_FOUND.equals(endpoint)) {
|
||||||
return null;
|
return null;
|
||||||
} else if (PATH_PARAM.equals(endpoint)) {
|
} else if (PATH_PARAM.equals(endpoint)) {
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||||
|
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import io.opentelemetry.api.common.AttributeKey;
|
import io.opentelemetry.api.common.AttributeKey;
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||||
import io.opentelemetry.semconv.SemanticAttributes;
|
import io.opentelemetry.semconv.SemanticAttributes;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
@ -30,15 +32,22 @@ public final class HttpServerTestOptions {
|
||||||
SemconvStabilityUtil.getAttributeKey(SemanticAttributes.NET_PEER_PORT))));
|
SemconvStabilityUtil.getAttributeKey(SemanticAttributes.NET_PEER_PORT))));
|
||||||
|
|
||||||
public static final SpanNameMapper DEFAULT_EXPECTED_SERVER_SPAN_NAME_MAPPER =
|
public static final SpanNameMapper DEFAULT_EXPECTED_SERVER_SPAN_NAME_MAPPER =
|
||||||
(uri, method, route) -> route == null ? method : method + " " + route;
|
(uri, method, route) -> {
|
||||||
|
if (HttpConstants._OTHER.equals(method)) {
|
||||||
|
method = "HTTP";
|
||||||
|
}
|
||||||
|
return route == null ? method : method + " " + route;
|
||||||
|
};
|
||||||
|
|
||||||
Function<ServerEndpoint, Set<AttributeKey<?>>> httpAttributes = unused -> DEFAULT_HTTP_ATTRIBUTES;
|
Function<ServerEndpoint, Set<AttributeKey<?>>> httpAttributes = unused -> DEFAULT_HTTP_ATTRIBUTES;
|
||||||
SpanNameMapper expectedServerSpanNameMapper = DEFAULT_EXPECTED_SERVER_SPAN_NAME_MAPPER;
|
SpanNameMapper expectedServerSpanNameMapper = DEFAULT_EXPECTED_SERVER_SPAN_NAME_MAPPER;
|
||||||
Function<ServerEndpoint, String> expectedHttpRoute = unused -> null;
|
BiFunction<ServerEndpoint, String, String> expectedHttpRoute = (endpoint, method) -> null;
|
||||||
Function<ServerEndpoint, String> sockPeerAddr = unused -> "127.0.0.1";
|
Function<ServerEndpoint, String> sockPeerAddr = unused -> "127.0.0.1";
|
||||||
String contextPath = "";
|
String contextPath = "";
|
||||||
Throwable expectedException = new Exception(EXCEPTION.body);
|
Throwable expectedException = new Exception(EXCEPTION.body);
|
||||||
Supplier<String> metricsInstrumentationName = () -> null;
|
Supplier<String> metricsInstrumentationName = () -> null;
|
||||||
|
// we're calling /success in the test, and most servers respond with 200 anyway
|
||||||
|
int responseCodeOnNonStandardHttpMethod = ServerEndpoint.SUCCESS.status;
|
||||||
|
|
||||||
Predicate<ServerEndpoint> hasHandlerSpan = unused -> false;
|
Predicate<ServerEndpoint> hasHandlerSpan = unused -> false;
|
||||||
Predicate<ServerEndpoint> hasResponseSpan = unused -> false;
|
Predicate<ServerEndpoint> hasResponseSpan = unused -> false;
|
||||||
|
|
@ -57,6 +66,7 @@ public final class HttpServerTestOptions {
|
||||||
boolean testCaptureHttpHeaders = true;
|
boolean testCaptureHttpHeaders = true;
|
||||||
boolean testCaptureRequestParameters = false;
|
boolean testCaptureRequestParameters = false;
|
||||||
boolean testHttpPipelining = true;
|
boolean testHttpPipelining = true;
|
||||||
|
boolean testNonStandardHttpMethod = true;
|
||||||
boolean verifyServerSpanEndTime = true;
|
boolean verifyServerSpanEndTime = true;
|
||||||
|
|
||||||
HttpServerTestOptions() {}
|
HttpServerTestOptions() {}
|
||||||
|
|
@ -77,7 +87,7 @@ public final class HttpServerTestOptions {
|
||||||
|
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public HttpServerTestOptions setExpectedHttpRoute(
|
public HttpServerTestOptions setExpectedHttpRoute(
|
||||||
Function<ServerEndpoint, String> expectedHttpRoute) {
|
BiFunction<ServerEndpoint, String, String> expectedHttpRoute) {
|
||||||
this.expectedHttpRoute = expectedHttpRoute;
|
this.expectedHttpRoute = expectedHttpRoute;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -107,6 +117,13 @@ public final class HttpServerTestOptions {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public HttpServerTestOptions setResponseCodeOnNonStandardHttpMethod(
|
||||||
|
int responseCodeOnNonStandardHttpMethod) {
|
||||||
|
this.responseCodeOnNonStandardHttpMethod = responseCodeOnNonStandardHttpMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public HttpServerTestOptions setHasHandlerSpan(Predicate<ServerEndpoint> hasHandlerSpan) {
|
public HttpServerTestOptions setHasHandlerSpan(Predicate<ServerEndpoint> hasHandlerSpan) {
|
||||||
this.hasHandlerSpan = hasHandlerSpan;
|
this.hasHandlerSpan = hasHandlerSpan;
|
||||||
|
|
@ -201,6 +218,13 @@ public final class HttpServerTestOptions {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: convert make this class follow the same pattern as HttpClientTestOptions
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public HttpServerTestOptions disableTestNonStandardHttpMethod() {
|
||||||
|
this.testNonStandardHttpMethod = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public HttpServerTestOptions setVerifyServerSpanEndTime(boolean verifyServerSpanEndTime) {
|
public HttpServerTestOptions setVerifyServerSpanEndTime(boolean verifyServerSpanEndTime) {
|
||||||
this.verifyServerSpanEndTime = verifyServerSpanEndTime;
|
this.verifyServerSpanEndTime = verifyServerSpanEndTime;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue