Don't report 400 level as error for SERVER spans (#4403)

* don't report 400 level as error for server spans

* fix HttpServerTest base class

* fix JspInstrumentationForward test

* split HttpStatusConverter into client and server implementations, and create two HttpSpanStatusExtractor.create methods, one for server and one for client.

* rebase

* fix test

* spotless

* fix test

* remove unused

* use strongly typed attributes converters and rename to overloaded create()

* fix tests

* remove redundant assert

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
jason plumb 2021-10-20 13:39:35 -07:00 committed by GitHub
parent 5d7c0dd95b
commit a50c13382f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 316 additions and 64 deletions

View File

@ -183,11 +183,10 @@ public class Instrumenter<REQUEST, RESPONSE> {
span.recordException(error); span.recordException(error);
} }
UnsafeAttributes attributesBuilder = new UnsafeAttributes(); UnsafeAttributes attributes = new UnsafeAttributes();
for (AttributesExtractor<? super REQUEST, ? super RESPONSE> extractor : attributesExtractors) { for (AttributesExtractor<? super REQUEST, ? super RESPONSE> extractor : attributesExtractors) {
extractor.onEnd(attributesBuilder, request, response, error); extractor.onEnd(attributes, request, response, error);
} }
Attributes attributes = attributesBuilder;
span.setAllAttributes(attributes); span.setAllAttributes(attributes);
Instant endTime = null; Instant endTime = null;

View File

@ -19,22 +19,36 @@ import javax.annotation.Nullable;
public final class HttpSpanStatusExtractor<REQUEST, RESPONSE> public final class HttpSpanStatusExtractor<REQUEST, RESPONSE>
implements SpanStatusExtractor<REQUEST, RESPONSE> { implements SpanStatusExtractor<REQUEST, RESPONSE> {
private final HttpStatusConverter statusConverter;
/** /**
* Returns the {@link SpanStatusExtractor} for HTTP requests, which will use the HTTP status code * Returns the {@link SpanStatusExtractor} for HTTP requests, which will use the HTTP status code
* to determine the {@link StatusCode} if available or fallback to {@linkplain #getDefault() the * to determine the {@link StatusCode} if available or fallback to {@linkplain #getDefault() the
* default status} otherwise. * default status} otherwise.
*/ */
public static <REQUEST, RESPONSE> SpanStatusExtractor<REQUEST, RESPONSE> create( public static <REQUEST, RESPONSE> SpanStatusExtractor<REQUEST, RESPONSE> create(
HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) { HttpClientAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) {
return new HttpSpanStatusExtractor<>(attributesExtractor); return new HttpSpanStatusExtractor<>(attributesExtractor, HttpStatusConverter.CLIENT);
}
/**
* Returns the {@link SpanStatusExtractor} for HTTP requests, which will use the HTTP status code
* to determine the {@link StatusCode} if available or fallback to {@linkplain #getDefault() the
* default status} otherwise.
*/
public static <REQUEST, RESPONSE> SpanStatusExtractor<REQUEST, RESPONSE> create(
HttpServerAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) {
return new HttpSpanStatusExtractor<>(attributesExtractor, HttpStatusConverter.SERVER);
} }
private final HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> private final HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE>
attributesExtractor; attributesExtractor;
private HttpSpanStatusExtractor( private HttpSpanStatusExtractor(
HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) { HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor,
HttpStatusConverter statusConverter) {
this.attributesExtractor = attributesExtractor; this.attributesExtractor = attributesExtractor;
this.statusConverter = statusConverter;
} }
@Override @Override
@ -42,7 +56,7 @@ public final class HttpSpanStatusExtractor<REQUEST, RESPONSE>
if (response != null) { if (response != null) {
Integer statusCode = attributesExtractor.statusCode(request, response); Integer statusCode = attributesExtractor.statusCode(request, response);
if (statusCode != null) { if (statusCode != null) {
StatusCode statusCodeObj = HttpStatusConverter.statusFromHttpStatus(statusCode); StatusCode statusCodeObj = statusConverter.statusFromHttpStatus(statusCode);
if (statusCodeObj == StatusCode.ERROR) { if (statusCodeObj == StatusCode.ERROR) {
return statusCodeObj; return statusCodeObj;
} }

View File

@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.tracer;
import io.opentelemetry.api.trace.StatusCode;
final class HttpClientStatusConverter implements HttpStatusConverter {
static final HttpStatusConverter INSTANCE = new HttpClientStatusConverter();
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#status
@Override
public StatusCode statusFromHttpStatus(int httpStatus) {
if (httpStatus >= 100 && httpStatus < 400) {
return StatusCode.UNSET;
}
return StatusCode.ERROR;
}
private HttpClientStatusConverter() {}
}

View File

@ -211,7 +211,7 @@ public abstract class HttpClientTracer<REQUEST, CARRIER, RESPONSE> extends BaseT
Integer status = status(response); Integer status = status(response);
if (status != null) { if (status != null) {
span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, (long) status); span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, (long) status);
StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(status); StatusCode statusCode = HttpStatusConverter.CLIENT.statusFromHttpStatus(status);
if (statusCode != StatusCode.UNSET) { if (statusCode != StatusCode.UNSET) {
span.setStatus(statusCode); span.setStatus(statusCode);
} }

View File

@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.tracer;
import io.opentelemetry.api.trace.StatusCode;
final class HttpServerStatusConverter implements HttpStatusConverter {
static final HttpStatusConverter INSTANCE = new HttpServerStatusConverter();
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#status
@Override
public StatusCode statusFromHttpStatus(int httpStatus) {
if (httpStatus >= 100 && httpStatus < 500) {
return StatusCode.UNSET;
}
return StatusCode.ERROR;
}
private HttpServerStatusConverter() {}
}

View File

@ -276,7 +276,7 @@ public abstract class HttpServerTracer<REQUEST, RESPONSE, CONNECTION, STORAGE> e
private static void setStatus(Span span, int status) { private static void setStatus(Span span, int status) {
span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, (long) status); span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, (long) status);
StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(status); StatusCode statusCode = HttpStatusConverter.SERVER.statusFromHttpStatus(status);
if (statusCode != StatusCode.UNSET) { if (statusCode != StatusCode.UNSET) {
span.setStatus(statusCode); span.setStatus(statusCode);
} }

View File

@ -7,16 +7,10 @@ package io.opentelemetry.instrumentation.api.tracer;
import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.StatusCode;
public final class HttpStatusConverter { public interface HttpStatusConverter {
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#status HttpStatusConverter SERVER = HttpServerStatusConverter.INSTANCE;
public static StatusCode statusFromHttpStatus(int httpStatus) { HttpStatusConverter CLIENT = HttpClientStatusConverter.INSTANCE;
if (httpStatus >= 100 && httpStatus < 400) {
return StatusCode.UNSET;
}
return StatusCode.ERROR; StatusCode statusFromHttpStatus(int httpStatus);
}
private HttpStatusConverter() {}
} }

View File

@ -8,11 +8,11 @@ package io.opentelemetry.instrumentation.api.tracer
import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.api.trace.StatusCode
import spock.lang.Specification import spock.lang.Specification
class HttpStatusConverterTest extends Specification { class HttpClientStatusConverterTest extends Specification {
def "test HTTP #httpStatus to OTel #expectedStatus"() { def "test HTTP #httpStatus to OTel #expectedStatus"() {
when: when:
def status = HttpStatusConverter.statusFromHttpStatus(httpStatus) def status = HttpStatusConverter.CLIENT.statusFromHttpStatus(httpStatus)
then: then:
status == expectedStatus status == expectedStatus

View File

@ -111,7 +111,7 @@ class HttpClientTracerTest extends BaseTracerTest {
def "test onResponse"() { def "test onResponse"() {
setup: setup:
def tracer = newTracer() def tracer = newTracer()
def statusCode = status != null ? HttpStatusConverter.statusFromHttpStatus(status) : null def statusCode = status != null ? HttpStatusConverter.CLIENT.statusFromHttpStatus(status) : null
when: when:
tracer.onResponse(span, resp) tracer.onResponse(span, resp)

View File

@ -0,0 +1,94 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.tracer
import io.opentelemetry.api.trace.StatusCode
import spock.lang.Specification
class HttpServerStatusConverterTest extends Specification {
def "test HTTP #httpStatus to OTel #expectedStatus"() {
when:
def status = HttpStatusConverter.SERVER.statusFromHttpStatus(httpStatus)
then:
status == expectedStatus
// https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
where:
httpStatus | expectedStatus
100 | StatusCode.UNSET
101 | StatusCode.UNSET
102 | StatusCode.UNSET
103 | StatusCode.UNSET
200 | StatusCode.UNSET
201 | StatusCode.UNSET
202 | StatusCode.UNSET
203 | StatusCode.UNSET
204 | StatusCode.UNSET
205 | StatusCode.UNSET
206 | StatusCode.UNSET
207 | StatusCode.UNSET
208 | StatusCode.UNSET
226 | StatusCode.UNSET
300 | StatusCode.UNSET
301 | StatusCode.UNSET
302 | StatusCode.UNSET
303 | StatusCode.UNSET
304 | StatusCode.UNSET
305 | StatusCode.UNSET
306 | StatusCode.UNSET
307 | StatusCode.UNSET
308 | StatusCode.UNSET
400 | StatusCode.UNSET
401 | StatusCode.UNSET
403 | StatusCode.UNSET
404 | StatusCode.UNSET
405 | StatusCode.UNSET
406 | StatusCode.UNSET
407 | StatusCode.UNSET
408 | StatusCode.UNSET
409 | StatusCode.UNSET
410 | StatusCode.UNSET
411 | StatusCode.UNSET
412 | StatusCode.UNSET
413 | StatusCode.UNSET
414 | StatusCode.UNSET
415 | StatusCode.UNSET
416 | StatusCode.UNSET
417 | StatusCode.UNSET
418 | StatusCode.UNSET
421 | StatusCode.UNSET
422 | StatusCode.UNSET
423 | StatusCode.UNSET
424 | StatusCode.UNSET
425 | StatusCode.UNSET
426 | StatusCode.UNSET
428 | StatusCode.UNSET
429 | StatusCode.UNSET
431 | StatusCode.UNSET
451 | StatusCode.UNSET
500 | StatusCode.ERROR
501 | StatusCode.ERROR
502 | StatusCode.ERROR
503 | StatusCode.ERROR
504 | StatusCode.ERROR
505 | StatusCode.ERROR
506 | StatusCode.ERROR
507 | StatusCode.ERROR
508 | StatusCode.ERROR
510 | StatusCode.ERROR
511 | StatusCode.ERROR
// Don't exist
99 | StatusCode.ERROR
600 | StatusCode.ERROR
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.instrumenter.http;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.when;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.instrumentation.api.tracer.HttpStatusConverter;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class HttpClientSpanStatusExtractorTest {
@Mock private HttpClientAttributesExtractor<Map<String, String>, Map<String, String>> extractor;
@ParameterizedTest
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601})
void hasStatus(int statusCode) {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
assertThat(
HttpSpanStatusExtractor.create(extractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(HttpStatusConverter.CLIENT.statusFromHttpStatus(statusCode));
}
@ParameterizedTest
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601})
void hasStatusAndException(int statusCode) {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
// Presence of exception has no effect.
assertThat(
HttpSpanStatusExtractor.create(extractor)
.extract(
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException()))
.isEqualTo(StatusCode.ERROR);
}
@Test
void hasNoStatus_fallsBackToDefault_unset() {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(null);
assertThat(
HttpSpanStatusExtractor.create(extractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(StatusCode.UNSET);
}
@Test
void hasNoStatus_fallsBackToDefault_error() {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(null);
assertThat(
HttpSpanStatusExtractor.create(extractor)
.extract(
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException()))
.isEqualTo(StatusCode.ERROR);
}
}

View File

@ -22,27 +22,53 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class HttpSpanStatusExtractorTest { class HttpSpanStatusExtractorTest {
@Mock private HttpCommonAttributesExtractor<Map<String, String>, Map<String, String>> extractor; @Mock
private HttpServerAttributesExtractor<Map<String, String>, Map<String, String>> serverExtractor;
@Mock
private HttpClientAttributesExtractor<Map<String, String>, Map<String, String>> clientExtractor;
@ParameterizedTest @ParameterizedTest
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601}) @ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 500, 501, 600, 601})
void hasStatus(int statusCode) { void hasServerStatus(int statusCode) {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode); when(serverExtractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
assertThat( assertThat(
HttpSpanStatusExtractor.create(extractor) HttpSpanStatusExtractor.create(serverExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null)) .extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(HttpStatusConverter.statusFromHttpStatus(statusCode)); .isEqualTo(HttpStatusConverter.SERVER.statusFromHttpStatus(statusCode));
} }
@ParameterizedTest @ParameterizedTest
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601}) @ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601})
void hasStatusAndException(int statusCode) { void hasClientStatus(int statusCode) {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode); when(clientExtractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
assertThat(
HttpSpanStatusExtractor.create(clientExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(HttpStatusConverter.CLIENT.statusFromHttpStatus(statusCode));
}
@ParameterizedTest
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601})
void hasServerStatusAndException(int statusCode) {
when(serverExtractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
// Presence of exception has no effect. // Presence of exception has no effect.
assertThat( assertThat(
HttpSpanStatusExtractor.create(extractor) HttpSpanStatusExtractor.create(serverExtractor)
.extract(
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException()))
.isEqualTo(StatusCode.ERROR);
}
@ParameterizedTest
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 400, 401, 500, 501, 600, 601})
void hasClientStatusAndException(int statusCode) {
when(clientExtractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
// Presence of exception has no effect.
assertThat(
HttpSpanStatusExtractor.create(clientExtractor)
.extract( .extract(
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException())) Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException()))
.isEqualTo(StatusCode.ERROR); .isEqualTo(StatusCode.ERROR);
@ -50,22 +76,32 @@ class HttpSpanStatusExtractorTest {
@Test @Test
void hasNoStatus_fallsBackToDefault_unset() { void hasNoStatus_fallsBackToDefault_unset() {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(null); when(clientExtractor.statusCode(anyMap(), anyMap())).thenReturn(null);
when(serverExtractor.statusCode(anyMap(), anyMap())).thenReturn(null);
assertThat( assertThat(
HttpSpanStatusExtractor.create(extractor) HttpSpanStatusExtractor.create(serverExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(StatusCode.UNSET);
assertThat(
HttpSpanStatusExtractor.create(clientExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null)) .extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(StatusCode.UNSET); .isEqualTo(StatusCode.UNSET);
} }
@Test @Test
void hasNoStatus_fallsBackToDefault_error() { void hasNoStatus_fallsBackToDefault_error() {
when(extractor.statusCode(anyMap(), anyMap())).thenReturn(null); when(clientExtractor.statusCode(anyMap(), anyMap())).thenReturn(null);
when(serverExtractor.statusCode(anyMap(), anyMap())).thenReturn(null);
assertThat( StatusCode serverStatusCode =
HttpSpanStatusExtractor.create(extractor) HttpSpanStatusExtractor.create(serverExtractor)
.extract( .extract(Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException());
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException())) assertThat(serverStatusCode).isEqualTo(StatusCode.ERROR);
.isEqualTo(StatusCode.ERROR);
StatusCode clientStatusCode =
HttpSpanStatusExtractor.create(clientExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException());
assertThat(clientStatusCode).isEqualTo(StatusCode.ERROR);
} }
} }

View File

@ -169,7 +169,7 @@ public class HttpUrlConnectionInstrumentation implements TypeInstrumentation {
if (httpUrlState != null) { if (httpUrlState != null) {
Span span = Java8BytecodeBridge.spanFromContext(httpUrlState.context); Span span = Java8BytecodeBridge.spanFromContext(httpUrlState.context);
span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, returnValue); span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, returnValue);
StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(returnValue); StatusCode statusCode = HttpStatusConverter.CLIENT.statusFromHttpStatus(returnValue);
if (statusCode != StatusCode.UNSET) { if (statusCode != StatusCode.UNSET) {
span.setStatus(statusCode); span.setStatus(statusCode);
} }

View File

@ -18,7 +18,7 @@ import javax.ws.rs.ext.Provider
import static io.opentelemetry.api.trace.SpanKind.INTERNAL import static io.opentelemetry.api.trace.SpanKind.INTERNAL
import static io.opentelemetry.api.trace.SpanKind.SERVER import static io.opentelemetry.api.trace.SpanKind.SERVER
import static io.opentelemetry.api.trace.StatusCode.ERROR import static io.opentelemetry.api.trace.StatusCode.UNSET
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace
@Unroll @Unroll
@ -77,7 +77,7 @@ abstract class JaxRsFilterTest extends AgentInstrumentationSpecification {
name parentSpanName != null ? parentSpanName : "test.span" name parentSpanName != null ? parentSpanName : "test.span"
kind SERVER kind SERVER
if (runsOnServer() && abortNormal) { if (runsOnServer() && abortNormal) {
status ERROR status UNSET
} }
} }
span(1) { span(1) {

View File

@ -241,7 +241,6 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
serverSpan(trace, index, traceID, parentID, method, serverSpan(trace, index, traceID, parentID, method,
endpoint == PATH_PARAM ? getContextPath() + "/path/{id}/param" : endpoint.resolvePath(address).path, endpoint == PATH_PARAM ? getContextPath() + "/path/{id}/param" : endpoint.resolvePath(address).path,
endpoint.resolve(address), endpoint.resolve(address),
endpoint.errored,
endpoint.status, endpoint.status,
endpoint.query) endpoint.query)
} }
@ -254,7 +253,6 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
serverSpan(trace, index, null, null, "GET", serverSpan(trace, index, null, null, "GET",
rawUrl.path, rawUrl.path,
rawUrl.toURI(), rawUrl.toURI(),
statusCode >= 500,
statusCode, statusCode,
null) null)
} }
@ -266,13 +264,12 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
String method, String method,
String path, String path,
URI fullUrl, URI fullUrl,
boolean isError,
int statusCode, int statusCode,
String query) { String query) {
trace.span(index) { trace.span(index) {
name path name path
kind SERVER kind SERVER
if (isError) { if (statusCode >= 500) {
status ERROR status ERROR
} }
if (parentID != null) { if (parentID != null) {

View File

@ -57,8 +57,7 @@ public final class JettyClientInstrumenterBuilder {
JettyHttpClientNetAttributesExtractor netAttributesExtractor = JettyHttpClientNetAttributesExtractor netAttributesExtractor =
new JettyHttpClientNetAttributesExtractor(); new JettyHttpClientNetAttributesExtractor();
Instrumenter<Request, Response> instrumenter = return Instrumenter.<Request, Response>newBuilder(
Instrumenter.<Request, Response>newBuilder(
this.openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor) this.openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
.setSpanStatusExtractor(spanStatusExtractor) .setSpanStatusExtractor(spanStatusExtractor)
.addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(httpAttributesExtractor)
@ -66,6 +65,5 @@ public final class JettyClientInstrumenterBuilder {
.addAttributesExtractors(additionalExtractors) .addAttributesExtractors(additionalExtractors)
.addRequestMetrics(HttpClientMetrics.get()) .addRequestMetrics(HttpClientMetrics.get())
.newClientInstrumenter(new HttpHeaderSetter()); .newClientInstrumenter(new HttpHeaderSetter());
return instrumenter;
} }
} }

View File

@ -20,6 +20,7 @@ import java.nio.file.Files
import static io.opentelemetry.api.trace.SpanKind.SERVER import static io.opentelemetry.api.trace.SpanKind.SERVER
import static io.opentelemetry.api.trace.StatusCode.ERROR import static io.opentelemetry.api.trace.StatusCode.ERROR
import static io.opentelemetry.api.trace.StatusCode.UNSET
class JspInstrumentationForwardTests extends AgentInstrumentationSpecification { class JspInstrumentationForwardTests extends AgentInstrumentationSpecification {
@ -425,7 +426,7 @@ class JspInstrumentationForwardTests extends AgentInstrumentationSpecification {
hasNoParent() hasNoParent()
name "/$jspWebappContext/forwards/forwardToNonExistent.jsp" name "/$jspWebappContext/forwards/forwardToNonExistent.jsp"
kind SERVER kind SERVER
status ERROR status UNSET
attributes { attributes {
"${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1" "${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1"
"${SemanticAttributes.NET_PEER_PORT.key}" Long "${SemanticAttributes.NET_PEER_PORT.key}" Long

View File

@ -48,7 +48,7 @@ abstract class AbstractServlet3MappingTest<SERVER, CONTEXT> extends AgentInstrum
span(0) { span(0) {
name getContextPath() + spanName name getContextPath() + spanName
kind SpanKind.SERVER kind SpanKind.SERVER
if (!success) { if (!success && response.status().code() >= 500) {
status ERROR status ERROR
} }
} }

View File

@ -47,7 +47,7 @@ abstract class AbstractServlet5MappingTest<SERVER, CONTEXT> extends AgentInstrum
span(0) { span(0) {
name getContextPath() + spanName name getContextPath() + spanName
kind SpanKind.SERVER kind SpanKind.SERVER
if (!success) { if (!success && response.status().code() >= 500) {
status ERROR status ERROR
} }
} }

View File

@ -27,6 +27,7 @@ import spock.lang.Unroll
import static io.opentelemetry.api.trace.SpanKind.INTERNAL import static io.opentelemetry.api.trace.SpanKind.INTERNAL
import static io.opentelemetry.api.trace.SpanKind.SERVER import static io.opentelemetry.api.trace.SpanKind.SERVER
import static io.opentelemetry.api.trace.StatusCode.ERROR import static io.opentelemetry.api.trace.StatusCode.ERROR
import static io.opentelemetry.api.trace.StatusCode.UNSET
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = [SpringWebFluxTestApplication, ForceNettyAutoConfiguration]) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = [SpringWebFluxTestApplication, ForceNettyAutoConfiguration])
class SpringWebfluxTest extends AgentInstrumentationSpecification { class SpringWebfluxTest extends AgentInstrumentationSpecification {
@ -286,7 +287,7 @@ class SpringWebfluxTest extends AgentInstrumentationSpecification {
name "/**" name "/**"
kind SERVER kind SERVER
hasNoParent() hasNoParent()
status ERROR status UNSET
attributes { attributes {
"${SemanticAttributes.NET_PEER_NAME}" { it == null || it == "localhost" } "${SemanticAttributes.NET_PEER_NAME}" { it == null || it == "localhost" }
"${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1" "${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1"

View File

@ -171,7 +171,6 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
final String fragment final String fragment
final int status final int status
final String body final String body
final Boolean errored
ServerEndpoint(String uri, int status, String body) { ServerEndpoint(String uri, int status, String body) {
this.uriObj = URI.create(uri) this.uriObj = URI.create(uri)
@ -180,7 +179,6 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
this.fragment = uriObj.fragment this.fragment = uriObj.fragment
this.status = status this.status = status
this.body = body this.body = body
this.errored = status >= 400
} }
String getPath() { String getPath() {
@ -594,7 +592,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
trace.span(index) { trace.span(index) {
name expectedServerSpanName(endpoint) name expectedServerSpanName(endpoint)
kind SpanKind.SERVER // can't use static import because of SERVER type parameter kind SpanKind.SERVER // can't use static import because of SERVER type parameter
if (endpoint.errored) { if (endpoint.status >= 500) {
status StatusCode.ERROR status StatusCode.ERROR
} }
if (parentID != null) { if (parentID != null) {