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);
}
UnsafeAttributes attributesBuilder = new UnsafeAttributes();
UnsafeAttributes attributes = new UnsafeAttributes();
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);
Instant endTime = null;

View File

@ -19,22 +19,36 @@ import javax.annotation.Nullable;
public final class HttpSpanStatusExtractor<REQUEST, RESPONSE>
implements SpanStatusExtractor<REQUEST, RESPONSE> {
private final HttpStatusConverter statusConverter;
/**
* 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(
HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) {
return new HttpSpanStatusExtractor<>(attributesExtractor);
HttpClientAttributesExtractor<? super REQUEST, ? super RESPONSE> 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>
attributesExtractor;
private HttpSpanStatusExtractor(
HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor) {
HttpCommonAttributesExtractor<? super REQUEST, ? super RESPONSE> attributesExtractor,
HttpStatusConverter statusConverter) {
this.attributesExtractor = attributesExtractor;
this.statusConverter = statusConverter;
}
@Override
@ -42,7 +56,7 @@ public final class HttpSpanStatusExtractor<REQUEST, RESPONSE>
if (response != null) {
Integer statusCode = attributesExtractor.statusCode(request, response);
if (statusCode != null) {
StatusCode statusCodeObj = HttpStatusConverter.statusFromHttpStatus(statusCode);
StatusCode statusCodeObj = statusConverter.statusFromHttpStatus(statusCode);
if (statusCodeObj == StatusCode.ERROR) {
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);
if (status != null) {
span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, (long) status);
StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(status);
StatusCode statusCode = HttpStatusConverter.CLIENT.statusFromHttpStatus(status);
if (statusCode != StatusCode.UNSET) {
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) {
span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, (long) status);
StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(status);
StatusCode statusCode = HttpStatusConverter.SERVER.statusFromHttpStatus(status);
if (statusCode != StatusCode.UNSET) {
span.setStatus(statusCode);
}

View File

@ -7,16 +7,10 @@ package io.opentelemetry.instrumentation.api.tracer;
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
public static StatusCode statusFromHttpStatus(int httpStatus) {
if (httpStatus >= 100 && httpStatus < 400) {
return StatusCode.UNSET;
}
HttpStatusConverter SERVER = HttpServerStatusConverter.INSTANCE;
HttpStatusConverter CLIENT = HttpClientStatusConverter.INSTANCE;
return StatusCode.ERROR;
}
private HttpStatusConverter() {}
StatusCode statusFromHttpStatus(int httpStatus);
}

View File

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

View File

@ -111,7 +111,7 @@ class HttpClientTracerTest extends BaseTracerTest {
def "test onResponse"() {
setup:
def tracer = newTracer()
def statusCode = status != null ? HttpStatusConverter.statusFromHttpStatus(status) : null
def statusCode = status != null ? HttpStatusConverter.CLIENT.statusFromHttpStatus(status) : null
when:
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)
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
@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);
@ValueSource(ints = {1, 100, 101, 200, 201, 300, 301, 500, 501, 600, 601})
void hasServerStatus(int statusCode) {
when(serverExtractor.statusCode(anyMap(), anyMap())).thenReturn(statusCode);
assertThat(
HttpSpanStatusExtractor.create(extractor)
HttpSpanStatusExtractor.create(serverExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), null))
.isEqualTo(HttpStatusConverter.statusFromHttpStatus(statusCode));
.isEqualTo(HttpStatusConverter.SERVER.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);
void hasClientStatus(int 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.
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(
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException()))
.isEqualTo(StatusCode.ERROR);
@ -50,22 +76,32 @@ class HttpSpanStatusExtractorTest {
@Test
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(
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))
.isEqualTo(StatusCode.UNSET);
}
@Test
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(
HttpSpanStatusExtractor.create(extractor)
.extract(
Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException()))
.isEqualTo(StatusCode.ERROR);
StatusCode serverStatusCode =
HttpSpanStatusExtractor.create(serverExtractor)
.extract(Collections.emptyMap(), Collections.emptyMap(), new IllegalStateException());
assertThat(serverStatusCode).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) {
Span span = Java8BytecodeBridge.spanFromContext(httpUrlState.context);
span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, returnValue);
StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(returnValue);
StatusCode statusCode = HttpStatusConverter.CLIENT.statusFromHttpStatus(returnValue);
if (statusCode != StatusCode.UNSET) {
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.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
@Unroll
@ -77,7 +77,7 @@ abstract class JaxRsFilterTest extends AgentInstrumentationSpecification {
name parentSpanName != null ? parentSpanName : "test.span"
kind SERVER
if (runsOnServer() && abortNormal) {
status ERROR
status UNSET
}
}
span(1) {

View File

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

View File

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

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.StatusCode.ERROR
import static io.opentelemetry.api.trace.StatusCode.UNSET
class JspInstrumentationForwardTests extends AgentInstrumentationSpecification {
@ -425,7 +426,7 @@ class JspInstrumentationForwardTests extends AgentInstrumentationSpecification {
hasNoParent()
name "/$jspWebappContext/forwards/forwardToNonExistent.jsp"
kind SERVER
status ERROR
status UNSET
attributes {
"${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1"
"${SemanticAttributes.NET_PEER_PORT.key}" Long

View File

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

View File

@ -47,7 +47,7 @@ abstract class AbstractServlet5MappingTest<SERVER, CONTEXT> extends AgentInstrum
span(0) {
name getContextPath() + spanName
kind SpanKind.SERVER
if (!success) {
if (!success && response.status().code() >= 500) {
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.SERVER
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])
class SpringWebfluxTest extends AgentInstrumentationSpecification {
@ -286,7 +287,7 @@ class SpringWebfluxTest extends AgentInstrumentationSpecification {
name "/**"
kind SERVER
hasNoParent()
status ERROR
status UNSET
attributes {
"${SemanticAttributes.NET_PEER_NAME}" { it == null || it == "localhost" }
"${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 int status
final String body
final Boolean errored
ServerEndpoint(String uri, int status, String body) {
this.uriObj = URI.create(uri)
@ -180,7 +179,6 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
this.fragment = uriObj.fragment
this.status = status
this.body = body
this.errored = status >= 400
}
String getPath() {
@ -594,7 +592,7 @@ abstract class HttpServerTest<SERVER> extends InstrumentationSpecification imple
trace.span(index) {
name expectedServerSpanName(endpoint)
kind SpanKind.SERVER // can't use static import because of SERVER type parameter
if (endpoint.errored) {
if (endpoint.status >= 500) {
status StatusCode.ERROR
}
if (parentID != null) {