123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
- import io.opentelemetry.api.common.AttributeKey
- import io.opentelemetry.api.trace.Span
- import io.opentelemetry.api.trace.SpanKind
- import io.opentelemetry.api.trace.StatusCode
- import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes
- import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes
- import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes
- import io.opentelemetry.instrumentation.api.internal.SemconvStability
- import io.opentelemetry.instrumentation.test.AgentTestTrait
- import io.opentelemetry.instrumentation.test.base.HttpServerTest
- import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
- import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
- import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
- import io.undertow.Handlers
- import io.undertow.Undertow
- import io.undertow.util.Headers
- import io.undertow.util.HttpString
- import io.undertow.util.StatusCodes
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
- import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
- //TODO make test which mixes handlers and servlets
- class UndertowServerTest extends HttpServerTest<Undertow> implements AgentTestTrait {
- @Override
- Undertow startServer(int port) {
- Undertow server = Undertow.builder()
- .addHttpListener(port, "localhost")
- .setHandler(Handlers.path()
- .addExactPath(SUCCESS.rawPath()) { exchange ->
- controller(SUCCESS) {
- exchange.getResponseSender().send(SUCCESS.body)
- }
- }
- .addExactPath(QUERY_PARAM.rawPath()) { exchange ->
- controller(QUERY_PARAM) {
- exchange.getResponseSender().send(exchange.getQueryString())
- }
- }
- .addExactPath(REDIRECT.rawPath()) { exchange ->
- controller(REDIRECT) {
- exchange.setStatusCode(StatusCodes.FOUND)
- exchange.getResponseHeaders().put(Headers.LOCATION, REDIRECT.body)
- exchange.endExchange()
- }
- }
- .addExactPath(CAPTURE_HEADERS.rawPath()) { exchange ->
- controller(CAPTURE_HEADERS) {
- exchange.setStatusCode(StatusCodes.OK)
- exchange.getResponseHeaders().put(new HttpString("X-Test-Response"), exchange.getRequestHeaders().getFirst("X-Test-Request"))
- exchange.getResponseSender().send(CAPTURE_HEADERS.body)
- }
- }
- .addExactPath(ERROR.rawPath()) { exchange ->
- controller(ERROR) {
- exchange.setStatusCode(ERROR.status)
- exchange.getResponseSender().send(ERROR.body)
- }
- }
- .addExactPath(EXCEPTION.rawPath()) { exchange ->
- controller(EXCEPTION) {
- throw new Exception(EXCEPTION.body)
- }
- }
- .addExactPath(INDEXED_CHILD.rawPath()) { exchange ->
- controller(INDEXED_CHILD) {
- INDEXED_CHILD.collectSpanAttributes { name -> exchange.getQueryParameters().get(name).peekFirst() }
- exchange.getResponseSender().send(INDEXED_CHILD.body)
- }
- }
- .addExactPath("sendResponse") { exchange ->
- Span.current().addEvent("before-event")
- runWithSpan("sendResponse") {
- exchange.setStatusCode(StatusCodes.OK)
- exchange.getResponseSender().send("sendResponse")
- }
- // event is added only when server span has not been ended
- // we need to make sure that sending response does not end server span
- Span.current().addEvent("after-event")
- }
- .addExactPath("sendResponseWithException") { exchange ->
- Span.current().addEvent("before-event")
- runWithSpan("sendResponseWithException") {
- exchange.setStatusCode(StatusCodes.OK)
- exchange.getResponseSender().send("sendResponseWithException")
- }
- // event is added only when server span has not been ended
- // we need to make sure that sending response does not end server span
- Span.current().addEvent("after-event")
- throw new Exception("exception after sending response")
- }
- ).build()
- server.start()
- return server
- }
- @Override
- void stopServer(Undertow undertow) {
- undertow.stop()
- }
- @Override
- Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
- def attributes = super.httpAttributes(endpoint)
- attributes.remove(SemanticAttributes.HTTP_ROUTE)
- attributes
- }
- @Override
- boolean hasResponseCustomizer(ServerEndpoint endpoint) {
- true
- }
- def "test send response"() {
- setup:
- def uri = address.resolve("sendResponse")
- AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join()
- expect:
- response.status().code() == 200
- response.contentUtf8().trim() == "sendResponse"
- and:
- assertTraces(1) {
- trace(0, 2) {
- it.span(0) {
- hasNoParent()
- name "GET"
- kind SpanKind.SERVER
- event(0) {
- eventName "before-event"
- }
- event(1) {
- eventName "after-event"
- }
- if (SemconvStability.emitOldHttpSemconv()) {
- attributes {
- "$SemanticAttributes.HTTP_CLIENT_IP" TEST_CLIENT_IP
- "$SemanticAttributes.HTTP_SCHEME" uri.getScheme()
- "$SemanticAttributes.HTTP_TARGET" uri.getPath()
- "$SemanticAttributes.HTTP_METHOD" "GET"
- "$SemanticAttributes.HTTP_STATUS_CODE" 200
- "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
- "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
- "$SemanticAttributes.NET_PROTOCOL_NAME" "http"
- "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
- "$SemanticAttributes.NET_HOST_NAME" uri.host
- "$SemanticAttributes.NET_HOST_PORT" uri.port
- "$SemanticAttributes.NET_SOCK_PEER_ADDR" "127.0.0.1"
- "$SemanticAttributes.NET_SOCK_PEER_PORT" Long
- "$SemanticAttributes.NET_SOCK_HOST_ADDR" "127.0.0.1"
- }
- }
- if (SemconvStability.emitStableHttpSemconv()) {
- attributes {
- "$NetworkAttributes.CLIENT_ADDRESS" TEST_CLIENT_IP
- "$UrlAttributes.URL_SCHEME" uri.getScheme()
- "$UrlAttributes.URL_PATH" uri.getPath()
- "$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
- "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
- "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
- "$HttpAttributes.HTTP_RESPONSE_BODY_SIZE" Long
- "$NetworkAttributes.NETWORK_PROTOCOL_NAME" "http"
- "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
- "$NetworkAttributes.NETWORK_TYPE" "ipv4"
- "$NetworkAttributes.SERVER_ADDRESS" uri.host
- "$NetworkAttributes.SERVER_PORT" uri.port
- "$NetworkAttributes.CLIENT_SOCKET_ADDRESS" "127.0.0.1"
- "$NetworkAttributes.CLIENT_SOCKET_PORT" Long
- }
- }
- }
- span(1) {
- name "sendResponse"
- kind SpanKind.INTERNAL
- childOf span(0)
- }
- }
- }
- }
- def "test send response with exception"() {
- setup:
- def uri = address.resolve("sendResponseWithException")
- AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join()
- expect:
- response.status().code() == 200
- response.contentUtf8().trim() == "sendResponseWithException"
- and:
- assertTraces(1) {
- trace(0, 2) {
- it.span(0) {
- hasNoParent()
- name "GET"
- kind SpanKind.SERVER
- status StatusCode.ERROR
- event(0) {
- eventName "before-event"
- }
- event(1) {
- eventName "after-event"
- }
- errorEvent(Exception, "exception after sending response", 2)
- if (SemconvStability.emitOldHttpSemconv()) {
- attributes {
- "$SemanticAttributes.HTTP_CLIENT_IP" TEST_CLIENT_IP
- "$SemanticAttributes.HTTP_SCHEME" uri.getScheme()
- "$SemanticAttributes.HTTP_TARGET" uri.getPath()
- "$SemanticAttributes.HTTP_METHOD" "GET"
- "$SemanticAttributes.HTTP_STATUS_CODE" 200
- "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
- "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
- "$SemanticAttributes.NET_PROTOCOL_NAME" "http"
- "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
- "$SemanticAttributes.NET_HOST_NAME" uri.host
- "$SemanticAttributes.NET_HOST_PORT" uri.port
- "$SemanticAttributes.NET_SOCK_PEER_ADDR" "127.0.0.1"
- "$SemanticAttributes.NET_SOCK_PEER_PORT" Long
- "$SemanticAttributes.NET_SOCK_HOST_ADDR" "127.0.0.1"
- }
- }
- if (SemconvStability.emitStableHttpSemconv()) {
- attributes {
- "$NetworkAttributes.CLIENT_ADDRESS" TEST_CLIENT_IP
- "$UrlAttributes.URL_SCHEME" uri.getScheme()
- "$UrlAttributes.URL_PATH" uri.getPath()
- "$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
- "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
- "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
- "$HttpAttributes.HTTP_RESPONSE_BODY_SIZE" Long
- "$NetworkAttributes.NETWORK_PROTOCOL_NAME" "http"
- "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
- "$NetworkAttributes.NETWORK_TYPE" "ipv4"
- "$NetworkAttributes.SERVER_ADDRESS" uri.host
- "$NetworkAttributes.SERVER_PORT" uri.port
- "$NetworkAttributes.CLIENT_SOCKET_ADDRESS" "127.0.0.1"
- "$NetworkAttributes.CLIENT_SOCKET_PORT" Long
- }
- }
- }
- span(1) {
- name "sendResponseWithException"
- kind SpanKind.INTERNAL
- childOf span(0)
- }
- }
- }
- }
- }
|