This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch backport/28867-to-camel-4.18.x in repository https://gitbox.apache.org/repos/asf/camel.git
commit 77aa3d2c7925009874bf7f675306de8be72104be Author: Guillaume Nodet <[email protected]> AuthorDate: Mon Nov 2 22:13:19 2026 +0000 [backport camel-4.18.x] CAMEL-26490: camel-telemetry, camel-tracing - present the http.url, url.path and server.address span attributes like camel.uri --- .../decorators/AbstractHttpSpanDecorator.java | 41 ++++++++-- .../decorators/AbstractSpanDecorator.java | 21 ++++- .../decorators/AbstractHttpSpanDecoratorTest.java | 95 ++++++++++++++++++++-- .../decorators/AbstractSpanDecoratorTest.java | 56 +++++++++++++ .../decorators/AbstractHttpSpanDecorator.java | 41 ++++++++-- .../tracing/decorators/AbstractSpanDecorator.java | 21 ++++- .../decorators/AbstractHttpSpanDecoratorTest.java | 95 ++++++++++++++++++++-- .../decorators/AbstractSpanDecoratorTest.java | 56 +++++++++++++ .../ROOT/pages/camel-4x-upgrade-guide-4_18.adoc | 17 ++++ 9 files changed, 411 insertions(+), 32 deletions(-) diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java index 24a1216e796c..0e3029674ab5 100644 --- a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java +++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java @@ -19,9 +19,12 @@ package org.apache.camel.telemetry.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; +import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.telemetry.Op; import org.apache.camel.telemetry.Span; import org.apache.camel.telemetry.TagConstants; +import org.apache.camel.util.StringHelper; +import org.apache.camel.util.URISupport; public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { @@ -76,22 +79,46 @@ public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { } protected String getHttpURL(Exchange exchange, Endpoint endpoint) { + // the url is presented the same way as the camel.uri tag Object url = exchange.getIn().getHeader(Exchange.HTTP_URL); if (url instanceof String str) { - return str; + return URISupport.sanitizeUri(str); } else { Object uri = exchange.getIn().getHeader(Exchange.HTTP_URI); if (uri instanceof String str) { - return str; + return URISupport.sanitizeUri(str); } else { // Try to obtain from endpoint - int index = endpoint.getEndpointUri().lastIndexOf("http:"); - if (index != -1) { - return endpoint.getEndpointUri().substring(index); - } + return URISupport.sanitizeUri(getHttpAddress(endpoint)); + } + } + } + + /** + * The HTTP address the endpoint sends to, without the endpoint options. + */ + private static String getHttpAddress(Endpoint endpoint) { + // the service url of an HTTP endpoint is its HTTP address with the query parameters that are sent + if (endpoint instanceof EndpointServiceLocation esl) { + String url = esl.getServiceUrl(); + if (isHttpAddress(url)) { + return url; } } - return null; + // otherwise take the endpoint uri, without the component scheme in front of the HTTP address + // (such as netty-http:http://host or vertx-http://https://host) and without the endpoint options + String uri = endpoint.getEndpointUri(); + if (!isHttpAddress(uri)) { + uri = StringHelper.after(uri, ":"); + if (uri != null && uri.startsWith("//")) { + uri = uri.substring(2); + } + } + return isHttpAddress(uri) ? URISupport.stripQuery(uri) : null; + } + + private static boolean isHttpAddress(String uri) { + return uri != null && (uri.startsWith("http://") || uri.startsWith("https://")); } @Override diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractSpanDecorator.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractSpanDecorator.java index 352b3974fd4c..4cba91594b27 100644 --- a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractSpanDecorator.java +++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractSpanDecorator.java @@ -89,6 +89,22 @@ public abstract class AbstractSpanDecorator implements SpanDecorator { return Collections.emptyMap(); } + /** + * The path of the endpoint URI without the scheme, the user info in front of the host and the options. + */ + private static String getUrlPath(Endpoint endpoint) { + String path = stripSchemeAndOptions(endpoint); + // the user info ends at the last @ before the first / + int colon = path.indexOf(':'); + int slash = path.indexOf('/'); + int at = slash == -1 ? path.lastIndexOf('@') : path.lastIndexOf('@', slash); + if (colon != -1 && colon < at) { + path = path.substring(at + 1); + } + // presented the same way as the camel.uri tag, for a path that is another uri (such as netty-http:http://host) + return URISupport.sanitizeUri(path); + } + private static String getComponentName(Endpoint endpoint) { String answer = endpoint.getComponent() != null ? endpoint.getComponent().getDefaultName() : null; if (answer == null) { @@ -123,7 +139,7 @@ public abstract class AbstractSpanDecorator implements SpanDecorator { // have been provided, for subsequent analysis String uri = endpoint.toString(); // toString will sanitize span.setTag("camel.uri", uri); - span.setTag(TagConstants.URL_PATH, stripSchemeAndOptions(endpoint)); + span.setTag(TagConstants.URL_PATH, getUrlPath(endpoint)); String query = URISupport.extractQuery(uri); if (query != null) { span.setTag(TagConstants.URL_QUERY, query); @@ -133,7 +149,8 @@ public abstract class AbstractSpanDecorator implements SpanDecorator { if (endpoint instanceof EndpointServiceLocation ela) { String adr = ela.getServiceUrl(); if (adr != null) { - span.setTag(TagConstants.SERVER_ADDRESS, adr); + // the address is presented the same way as the camel.uri tag + span.setTag(TagConstants.SERVER_ADDRESS, URISupport.sanitizeUri(adr)); } String ap = ela.getServiceProtocol(); if (ap != null) { diff --git a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java index 9e7314b4e255..6b05fed0994c 100644 --- a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java +++ b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java @@ -19,6 +19,7 @@ package org.apache.camel.telemetry.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; +import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.telemetry.TagConstants; import org.apache.camel.telemetry.mock.MockSpanAdapter; import org.junit.jupiter.api.BeforeEach; @@ -150,9 +151,9 @@ public class AbstractHttpSpanDecoratorTest { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); - Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); + Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn(TEST_URI); MockSpanAdapter span = new MockSpanAdapter(); @@ -168,10 +169,10 @@ public class AbstractHttpSpanDecoratorTest { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); - Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn("Another URL"); - Mockito.when(message.getHeader(Exchange.HTTP_URL, String.class)).thenReturn(TEST_URI); + Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn("Another URL"); + Mockito.when(message.getHeader(Exchange.HTTP_URL)).thenReturn(TEST_URI); assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -182,13 +183,26 @@ public class AbstractHttpSpanDecoratorTest { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); - Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); + Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn(TEST_URI); assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } + @Test + public void testGetHttpURLFromHeaderUrlPresentedLikeCamelUri() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URL)).thenReturn("http://scott:tiger@localhost:8080/test"); + + assertEquals("http://scott:xxxxxx@localhost:8080/test", decorator.getHttpURL(exchange, endpoint)); + } + @Test public void testGetHttpURLFromEndpointUri() { Endpoint endpoint = Mockito.mock(Endpoint.class); @@ -213,6 +227,73 @@ public class AbstractHttpSpanDecoratorTest { assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } + @Test + public void testGetHttpURLFromEndpointUriWithoutEndpointOptions() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI + "?connectTimeout=5000&throwExceptionOnFailure=false"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testGetHttpURLFromEndpointUriWithComponentSchemeAndHttpsAddress() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("vertx-http://https://localhost:8443/test?connectTimeout=5000"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals("https://localhost:8443/test", decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testGetHttpURLFromServiceUrl() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("https://localhost:8443/test?q=1&connectTimeout=5000"); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("https://localhost:8443/test?q=1"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals("https://localhost:8443/test?q=1", decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testGetHttpURLFromEndpointUriWhenServiceUrlIsNotHttpAddress() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("netty-http:" + TEST_URI); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("http:localhost:8080"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testPreHttpsEndpoint() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("https://localhost:8443/test?connectTimeout=5000"); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("https://localhost:8443/test"); + Mockito.when(exchange.getIn()).thenReturn(message); + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.beforeTracingEvent(span, exchange, endpoint); + + assertEquals("https://localhost:8443/test", span.tags().get(TagConstants.HTTP_URL)); + } + @Test public void testPostResponseCode() { Exchange exchange = Mockito.mock(Exchange.class); diff --git a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractSpanDecoratorTest.java b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractSpanDecoratorTest.java index 5bcf53a26b91..5fb9154abbc5 100644 --- a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractSpanDecoratorTest.java +++ b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractSpanDecoratorTest.java @@ -18,6 +18,7 @@ package org.apache.camel.telemetry.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.telemetry.SpanDecorator; import org.apache.camel.telemetry.TagConstants; import org.apache.camel.telemetry.mock.MockSpanAdapter; @@ -85,6 +86,61 @@ public class AbstractSpanDecoratorTest { assertEquals("myRouteId", span.tags().get(TagConstants.ROUTE_ID)); } + @Test + public void testPreUrlPathWithoutUserInfo() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("ftp://scott:tiger@localhost:2121/inbox?binary=true"); + Mockito.when(endpoint.toString()).thenReturn("ftp://scott:xxxxxx@localhost:2121/inbox?binary=true"); + + SpanDecorator decorator = new AbstractSpanDecorator() { + @Override + public String getComponent() { + return null; + } + + @Override + public String getComponentClassName() { + return null; + } + }; + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.beforeTracingEvent(span, exchange, endpoint); + + assertEquals("localhost:2121/inbox", span.tags().get(TagConstants.URL_PATH)); + assertEquals("binary=true", span.tags().get(TagConstants.URL_QUERY)); + } + + @Test + public void testPreServerAddressPresentedLikeCamelUri() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("amqp:queue:foo"); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("amqp://scott:tiger@localhost:5672"); + + SpanDecorator decorator = new AbstractSpanDecorator() { + @Override + public String getComponent() { + return null; + } + + @Override + public String getComponentClassName() { + return null; + } + }; + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.beforeTracingEvent(span, exchange, endpoint); + + assertEquals("amqp://scott:xxxxxx@localhost:5672", span.tags().get(TagConstants.SERVER_ADDRESS)); + } + @Test public void testPostExchangeFailed() { Exchange exchange = Mockito.mock(Exchange.class); diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java index 058c4e660b69..b56f669b15db 100644 --- a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java @@ -19,8 +19,11 @@ package org.apache.camel.tracing.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; +import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.tracing.SpanAdapter; import org.apache.camel.tracing.TagConstants; +import org.apache.camel.util.StringHelper; +import org.apache.camel.util.URISupport; public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { @@ -75,22 +78,46 @@ public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { } protected String getHttpURL(Exchange exchange, Endpoint endpoint) { + // the url is presented the same way as the camel.uri tag Object url = exchange.getIn().getHeader(Exchange.HTTP_URL); if (url instanceof String) { - return (String) url; + return URISupport.sanitizeUri((String) url); } else { Object uri = exchange.getIn().getHeader(Exchange.HTTP_URI); if (uri instanceof String) { - return (String) uri; + return URISupport.sanitizeUri((String) uri); } else { // Try to obtain from endpoint - int index = endpoint.getEndpointUri().lastIndexOf("http:"); - if (index != -1) { - return endpoint.getEndpointUri().substring(index); - } + return URISupport.sanitizeUri(getHttpAddress(endpoint)); } } - return null; + } + + /** + * The HTTP address the endpoint sends to, without the endpoint options. + */ + private static String getHttpAddress(Endpoint endpoint) { + // the service url of an HTTP endpoint is its HTTP address with the query parameters that are sent + if (endpoint instanceof EndpointServiceLocation esl) { + String url = esl.getServiceUrl(); + if (isHttpAddress(url)) { + return url; + } + } + // otherwise take the endpoint uri, without the component scheme in front of the HTTP address + // (such as netty-http:http://host or vertx-http://https://host) and without the endpoint options + String uri = endpoint.getEndpointUri(); + if (!isHttpAddress(uri)) { + uri = StringHelper.after(uri, ":"); + if (uri != null && uri.startsWith("//")) { + uri = uri.substring(2); + } + } + return isHttpAddress(uri) ? URISupport.stripQuery(uri) : null; + } + + private static boolean isHttpAddress(String uri) { + return uri != null && (uri.startsWith("http://") || uri.startsWith("https://")); } @Override diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractSpanDecorator.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractSpanDecorator.java index cefb3445f8d8..f3670c375490 100644 --- a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractSpanDecorator.java +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractSpanDecorator.java @@ -87,6 +87,22 @@ public abstract class AbstractSpanDecorator implements SpanDecorator { return Collections.emptyMap(); } + /** + * The path of the endpoint URI without the scheme, the user info in front of the host and the options. + */ + private static String getUrlPath(Endpoint endpoint) { + String path = stripSchemeAndOptions(endpoint); + // the user info ends at the last @ before the first / + int colon = path.indexOf(':'); + int slash = path.indexOf('/'); + int at = slash == -1 ? path.lastIndexOf('@') : path.lastIndexOf('@', slash); + if (colon != -1 && colon < at) { + path = path.substring(at + 1); + } + // presented the same way as the camel.uri tag, for a path that is another uri (such as netty-http:http://host) + return URISupport.sanitizeUri(path); + } + private static String getComponentName(Endpoint endpoint) { String answer = endpoint.getComponent() != null ? endpoint.getComponent().getDefaultName() : null; if (answer == null) { @@ -128,7 +144,7 @@ public abstract class AbstractSpanDecorator implements SpanDecorator { // have been provided, for subsequent analysis String uri = endpoint.toString(); // toString will sanitize span.setTag("camel.uri", uri); - span.setTag(TagConstants.URL_PATH, stripSchemeAndOptions(endpoint)); + span.setTag(TagConstants.URL_PATH, getUrlPath(endpoint)); String query = URISupport.extractQuery(uri); if (query != null) { span.setTag(TagConstants.URL_QUERY, query); @@ -138,7 +154,8 @@ public abstract class AbstractSpanDecorator implements SpanDecorator { if (endpoint instanceof EndpointServiceLocation ela) { String adr = ela.getServiceUrl(); if (adr != null) { - span.setTag(TagConstants.SERVER_ADDRESS, adr); + // the address is presented the same way as the camel.uri tag + span.setTag(TagConstants.SERVER_ADDRESS, URISupport.sanitizeUri(adr)); } String ap = ela.getServiceProtocol(); if (ap != null) { diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java index c48d8751f28f..fe97b5f8affa 100644 --- a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java @@ -19,6 +19,7 @@ package org.apache.camel.tracing.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; +import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.tracing.MockSpanAdapter; import org.apache.camel.tracing.TagConstants; import org.junit.jupiter.api.BeforeEach; @@ -152,9 +153,9 @@ public class AbstractHttpSpanDecoratorTest { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); - Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); + Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn(TEST_URI); MockSpanAdapter span = new MockSpanAdapter(); @@ -170,10 +171,10 @@ public class AbstractHttpSpanDecoratorTest { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); - Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn("Another URL"); - Mockito.when(message.getHeader(Exchange.HTTP_URL, String.class)).thenReturn(TEST_URI); + Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn("Another URL"); + Mockito.when(message.getHeader(Exchange.HTTP_URL)).thenReturn(TEST_URI); assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -184,13 +185,26 @@ public class AbstractHttpSpanDecoratorTest { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); - Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); + Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn(TEST_URI); assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } + @Test + public void testGetHttpURLFromHeaderUrlPresentedLikeCamelUri() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URL)).thenReturn("http://scott:tiger@localhost:8080/test"); + + assertEquals("http://scott:xxxxxx@localhost:8080/test", decorator.getHttpURL(exchange, endpoint)); + } + @Test public void testGetHttpURLFromEndpointUri() { Endpoint endpoint = Mockito.mock(Endpoint.class); @@ -215,6 +229,73 @@ public class AbstractHttpSpanDecoratorTest { assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } + @Test + public void testGetHttpURLFromEndpointUriWithoutEndpointOptions() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI + "?connectTimeout=5000&throwExceptionOnFailure=false"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testGetHttpURLFromEndpointUriWithComponentSchemeAndHttpsAddress() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("vertx-http://https://localhost:8443/test?connectTimeout=5000"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals("https://localhost:8443/test", decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testGetHttpURLFromServiceUrl() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("https://localhost:8443/test?q=1&connectTimeout=5000"); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("https://localhost:8443/test?q=1"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals("https://localhost:8443/test?q=1", decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testGetHttpURLFromEndpointUriWhenServiceUrlIsNotHttpAddress() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("netty-http:" + TEST_URI); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("http:localhost:8080"); + Mockito.when(exchange.getIn()).thenReturn(message); + + assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); + } + + @Test + public void testPreHttpsEndpoint() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("https://localhost:8443/test?connectTimeout=5000"); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("https://localhost:8443/test"); + Mockito.when(exchange.getIn()).thenReturn(message); + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.pre(span, exchange, endpoint); + + assertEquals("https://localhost:8443/test", span.tags().get(TagConstants.HTTP_URL)); + } + @Test public void testPostResponseCode() { Exchange exchange = Mockito.mock(Exchange.class); diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractSpanDecoratorTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractSpanDecoratorTest.java index 616ad491b23e..06f923418ac3 100644 --- a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractSpanDecoratorTest.java +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractSpanDecoratorTest.java @@ -18,6 +18,7 @@ package org.apache.camel.tracing.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.tracing.MockSpanAdapter; import org.apache.camel.tracing.SpanDecorator; import org.apache.camel.tracing.TagConstants; @@ -86,6 +87,61 @@ public class AbstractSpanDecoratorTest { assertEquals("myRouteId", span.tags().get(TagConstants.ROUTE_ID)); } + @Test + public void testPreUrlPathWithoutUserInfo() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("ftp://scott:tiger@localhost:2121/inbox?binary=true"); + Mockito.when(endpoint.toString()).thenReturn("ftp://scott:xxxxxx@localhost:2121/inbox?binary=true"); + + SpanDecorator decorator = new AbstractSpanDecorator() { + @Override + public String getComponent() { + return null; + } + + @Override + public String getComponentClassName() { + return null; + } + }; + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.pre(span, exchange, endpoint); + + assertEquals("localhost:2121/inbox", span.tags().get(TagConstants.URL_PATH)); + assertEquals("binary=true", span.tags().get(TagConstants.URL_QUERY)); + } + + @Test + public void testPreServerAddressPresentedLikeCamelUri() { + Endpoint endpoint = Mockito.mock(Endpoint.class, Mockito.withSettings().extraInterfaces(EndpointServiceLocation.class)); + Exchange exchange = Mockito.mock(Exchange.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("amqp:queue:foo"); + Mockito.when(((EndpointServiceLocation) endpoint).getServiceUrl()).thenReturn("amqp://scott:tiger@localhost:5672"); + + SpanDecorator decorator = new AbstractSpanDecorator() { + @Override + public String getComponent() { + return null; + } + + @Override + public String getComponentClassName() { + return null; + } + }; + + MockSpanAdapter span = new MockSpanAdapter(); + + decorator.pre(span, exchange, endpoint); + + assertEquals("amqp://scott:xxxxxx@localhost:5672", span.tags().get(TagConstants.SERVER_ADDRESS)); + } + @Test public void testPostExchangeFailed() { Exchange exchange = Mockito.mock(Exchange.class); diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index ae0e79663274..a9727cfadb38 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -2012,3 +2012,20 @@ The producer now discards that session, so the next exchange opens a fresh one. The default behaviour is unchanged: `disconnectOnNoReply` defaults to `true`, which already closed the session on a timeout. Setting `disconnectOnNoReply=false` no longer keeps the producer session open after a timeout. + +=== camel-telemetry, camel-tracing - the http.url, url.path and server.address span attributes are presented like camel.uri + +This applies to `camel-opentelemetry2`, `camel-micrometer-observability`, `camel-telemetry-dev`, `camel-opentelemetry` +and `camel-observation`. The `http.url`, `url.path` and `server.address` attributes of a span are now presented the same +way as the `camel.uri` attribute, which shows the endpoint URI as `Endpoint.toString()` does: + +* `http.url`, when the message has neither a `CamelHttpUrl` nor a `CamelHttpUri` header, is now the HTTP address the + endpoint sends to, with the query parameters it sends but without the Camel endpoint options. Before, it was the + endpoint URI from the last `http:` onwards, with all the endpoint options. A `camel-http` endpoint with an `https` + address now sets the attribute as well, and for a `camel-vertx-http` endpoint with an `https` address the value no + longer starts with `http://https://`. +* `url.path` no longer includes the user info in front of the host of the endpoint URI. +* `server.address`, and `http.url` taken from the `CamelHttpUrl` or `CamelHttpUri` header, are presented as `camel.uri` + is. + +Dashboards or queries that use the old values may need a change.
