Skip to content

Commit ce90a0e

Browse files
traskotelbot[bot]laurit
authored
Peer service testing (#14963)
Co-authored-by: otelbot <197425009+otelbot@users.noreply.github.com> Co-authored-by: Lauri Tulmin <ltulmin@splunk.com>
1 parent 38a26d6 commit ce90a0e

File tree

57 files changed

+386
-92
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+386
-92
lines changed

conventions/src/main/kotlin/io.opentelemetry.instrumentation.javaagent-testing.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ class JavaagentTestArgumentsProvider(
9494
"-Dio.opentelemetry.javaagent.slf4j.simpleLogger.log.io.grpc.internal.ManagedChannelImplBuilder=INFO",
9595
"-Dio.opentelemetry.javaagent.slf4j.simpleLogger.log.io.perfmark.PerfMark=INFO",
9696
"-Dio.opentelemetry.javaagent.slf4j.simpleLogger.log.io.grpc.Context=INFO",
97-
"-Dotel.java.experimental.span-attributes.copy-from-baggage.include=test-baggage-key-1,test-baggage-key-2"
97+
"-Dotel.java.experimental.span-attributes.copy-from-baggage.include=test-baggage-key-1,test-baggage-key-2",
98+
"-Dotel.instrumentation.common.peer-service-mapping=127.0.0.1=test-peer-service,localhost=test-peer-service,192.0.2.1=test-peer-service"
9899
)
99100
}
100101

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientPeerServiceAttributesExtractor.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
import io.opentelemetry.instrumentation.api.incubator.semconv.net.internal.UrlParser;
1313
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
1414
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter;
15+
import io.opentelemetry.instrumentation.api.semconv.http.internal.HostAddressAndPortExtractor;
16+
import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPort;
17+
import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPortExtractor;
18+
import io.opentelemetry.instrumentation.api.semconv.network.internal.ServerAddressAndPortExtractor;
1519
import java.util.function.Supplier;
1620
import javax.annotation.Nullable;
1721

@@ -26,26 +30,33 @@ public final class HttpClientPeerServiceAttributesExtractor<REQUEST, RESPONSE>
2630
// copied from PeerIncubatingAttributes
2731
private static final AttributeKey<String> PEER_SERVICE = AttributeKey.stringKey("peer.service");
2832

33+
private final AddressAndPortExtractor<REQUEST> addressAndPortExtractor;
2934
private final HttpClientAttributesGetter<REQUEST, RESPONSE> attributesGetter;
3035
private final PeerServiceResolver peerServiceResolver;
3136

3237
// visible for tests
3338
HttpClientPeerServiceAttributesExtractor(
39+
AddressAndPortExtractor<REQUEST> addressAndPortExtractor,
3440
HttpClientAttributesGetter<REQUEST, RESPONSE> attributesGetter,
3541
PeerServiceResolver peerServiceResolver) {
42+
this.addressAndPortExtractor = addressAndPortExtractor;
3643
this.attributesGetter = attributesGetter;
3744
this.peerServiceResolver = peerServiceResolver;
3845
}
3946

4047
/**
4148
* Returns a new {@link HttpClientPeerServiceAttributesExtractor} that will use the passed {@code
42-
* attributesGetter} instance to determine the value of the {@code peer.service} attribute.
49+
* attributesGetter} to extract server address and port (with fallback to the HTTP Host header).
4350
*/
4451
public static <REQUEST, RESPONSE>
4552
HttpClientPeerServiceAttributesExtractor<REQUEST, RESPONSE> create(
4653
HttpClientAttributesGetter<REQUEST, RESPONSE> attributesGetter,
4754
PeerServiceResolver peerServiceResolver) {
48-
return new HttpClientPeerServiceAttributesExtractor<>(attributesGetter, peerServiceResolver);
55+
AddressAndPortExtractor<REQUEST> addressAndPortExtractor =
56+
new ServerAddressAndPortExtractor<>(
57+
attributesGetter, new HostAddressAndPortExtractor<>(attributesGetter));
58+
return new HttpClientPeerServiceAttributesExtractor<>(
59+
addressAndPortExtractor, attributesGetter, peerServiceResolver);
4960
}
5061

5162
@Override
@@ -65,10 +76,11 @@ public void onEnd(
6576
return;
6677
}
6778

68-
String serverAddress = attributesGetter.getServerAddress(request);
69-
Integer serverPort = attributesGetter.getServerPort(request);
79+
AddressAndPort addressAndPort = addressAndPortExtractor.extract(request);
80+
7081
Supplier<String> pathSupplier = () -> getUrlPath(attributesGetter, request);
71-
String peerService = mapToPeerService(serverAddress, serverPort, pathSupplier);
82+
String peerService =
83+
mapToPeerService(addressAndPort.getAddress(), addressAndPort.getPort(), pathSupplier);
7284
if (peerService != null) {
7385
attributes.put(PEER_SERVICE, peerService);
7486
}

instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientPeerServiceAttributesExtractorTest.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
package io.opentelemetry.instrumentation.api.incubator.semconv.http;
77

88
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
9+
import static java.util.Collections.singletonList;
910
import static java.util.Collections.singletonMap;
1011
import static org.assertj.core.api.Assertions.entry;
1112
import static org.junit.jupiter.api.Assertions.assertTrue;
1213
import static org.mockito.ArgumentMatchers.any;
14+
import static org.mockito.ArgumentMatchers.eq;
1315
import static org.mockito.Mockito.when;
1416

1517
import io.opentelemetry.api.common.Attributes;
@@ -36,7 +38,7 @@ void shouldNotSetAnyValueIfNetExtractorReturnsNulls() {
3638
PeerServiceResolver.create(singletonMap("1.2.3.4", "myService"));
3739

3840
HttpClientPeerServiceAttributesExtractor<String, String> underTest =
39-
new HttpClientPeerServiceAttributesExtractor<>(
41+
HttpClientPeerServiceAttributesExtractor.create(
4042
httpAttributesExtractor, peerServiceResolver);
4143

4244
Context context = Context.root();
@@ -57,7 +59,7 @@ void shouldNotSetAnyValueIfPeerNameDoesNotMatch() {
5759
PeerServiceResolver.create(singletonMap("example.com", "myService"));
5860

5961
HttpClientPeerServiceAttributesExtractor<String, String> underTest =
60-
new HttpClientPeerServiceAttributesExtractor<>(
62+
HttpClientPeerServiceAttributesExtractor.create(
6163
httpAttributesExtractor, peerServiceResolver);
6264

6365
when(httpAttributesExtractor.getServerAddress(any())).thenReturn("example2.com");
@@ -85,7 +87,7 @@ void shouldSetPeerNameIfItMatches() {
8587
PeerServiceResolver peerServiceResolver = PeerServiceResolver.create(peerServiceMapping);
8688

8789
HttpClientPeerServiceAttributesExtractor<String, String> underTest =
88-
new HttpClientPeerServiceAttributesExtractor<>(
90+
HttpClientPeerServiceAttributesExtractor.create(
8991
httpAttributesExtractor, peerServiceResolver);
9092

9193
when(httpAttributesExtractor.getServerAddress(any())).thenReturn("example.com");
@@ -103,4 +105,34 @@ void shouldSetPeerNameIfItMatches() {
103105
assertThat(endAttributes.build())
104106
.containsOnly(entry(PeerIncubatingAttributes.PEER_SERVICE, "myService"));
105107
}
108+
109+
@Test
110+
void shouldFallbackToHostHeaderWhenServerAddressIsNull() {
111+
// given
112+
PeerServiceResolver peerServiceResolver =
113+
PeerServiceResolver.create(singletonMap("example.com", "myService"));
114+
115+
HttpClientPeerServiceAttributesExtractor<String, String> underTest =
116+
HttpClientPeerServiceAttributesExtractor.create(
117+
httpAttributesExtractor, peerServiceResolver);
118+
119+
// server address is null, should fallback to Host header
120+
when(httpAttributesExtractor.getServerAddress(any())).thenReturn(null);
121+
when(httpAttributesExtractor.getServerPort(any())).thenReturn(null);
122+
when(httpAttributesExtractor.getHttpRequestHeader(any(), eq("host")))
123+
.thenReturn(singletonList("example.com:8080"));
124+
125+
Context context = Context.root();
126+
127+
// when
128+
AttributesBuilder startAttributes = Attributes.builder();
129+
underTest.onStart(startAttributes, context, "request");
130+
AttributesBuilder endAttributes = Attributes.builder();
131+
underTest.onEnd(endAttributes, context, "request", "response", null);
132+
133+
// then
134+
assertThat(startAttributes.build()).isEmpty();
135+
assertThat(endAttributes.build())
136+
.containsOnly(entry(PeerIncubatingAttributes.PEER_SERVICE, "myService"));
137+
}
106138
}

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HostAddressAndPortExtractor.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
1414
import io.opentelemetry.instrumentation.api.internal.Experimental;
1515
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
16+
import io.opentelemetry.instrumentation.api.semconv.http.internal.HostAddressAndPortExtractor;
1617
import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPortExtractor;
1718
import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalNetworkAttributesExtractor;
1819
import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalServerAttributesExtractor;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.semconv.http.internal;
7+
8+
import io.opentelemetry.instrumentation.api.semconv.http.HttpCommonAttributesGetter;
9+
import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPortExtractor;
10+
import java.util.List;
11+
import javax.annotation.Nullable;
12+
13+
/**
14+
* Extracts server address and port from the HTTP Host header.
15+
*
16+
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
17+
* at any time.
18+
*/
19+
public final class HostAddressAndPortExtractor<REQUEST>
20+
implements AddressAndPortExtractor<REQUEST> {
21+
22+
private final HttpCommonAttributesGetter<REQUEST, ?> getter;
23+
24+
public HostAddressAndPortExtractor(HttpCommonAttributesGetter<REQUEST, ?> getter) {
25+
this.getter = getter;
26+
}
27+
28+
@Override
29+
public void extract(AddressPortSink sink, REQUEST request) {
30+
String host = firstHeaderValue(getter.getHttpRequestHeader(request, "host"));
31+
if (host == null) {
32+
return;
33+
}
34+
35+
int hostHeaderSeparator = host.indexOf(':');
36+
if (hostHeaderSeparator == -1) {
37+
sink.setAddress(host);
38+
} else {
39+
sink.setAddress(host.substring(0, hostHeaderSeparator));
40+
setPort(sink, host, hostHeaderSeparator + 1, host.length());
41+
}
42+
}
43+
44+
@Nullable
45+
private static String firstHeaderValue(List<String> values) {
46+
return values.isEmpty() ? null : values.get(0);
47+
}
48+
49+
private static void setPort(AddressPortSink sink, String header, int start, int end) {
50+
if (start == end) {
51+
return;
52+
}
53+
try {
54+
sink.setPort(Integer.parseInt(header.substring(start, end)));
55+
} catch (NumberFormatException ignored) {
56+
// malformed port, ignoring
57+
}
58+
}
59+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.instrumentation.api.semconv.http;
6+
package io.opentelemetry.instrumentation.api.semconv.http.internal;
77

88
import static java.util.Collections.emptyList;
99
import static java.util.Collections.singletonList;
@@ -12,6 +12,7 @@
1212
import static org.mockito.Mockito.verifyNoMoreInteractions;
1313
import static org.mockito.Mockito.when;
1414

15+
import io.opentelemetry.instrumentation.api.semconv.http.HttpCommonAttributesGetter;
1516
import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPortExtractor;
1617
import org.junit.jupiter.api.Test;
1718
import org.junit.jupiter.api.extension.ExtendWith;

instrumentation/apache-dubbo-2.7/javaagent/src/testDubbo/java/io/opentelemetry/javaagent/instrumentation/apachedubbo/v2_7/DubboAgentTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,9 @@ class DubboAgentTest extends AbstractDubboTest {
1919
protected InstrumentationExtension testing() {
2020
return testing;
2121
}
22+
23+
@Override
24+
protected boolean hasPeerService() {
25+
return true;
26+
}
2227
}

instrumentation/apache-dubbo-2.7/javaagent/src/testDubbo/java/io/opentelemetry/javaagent/instrumentation/apachedubbo/v2_7/DubboAgentTraceChainTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,9 @@ class DubboAgentTraceChainTest extends AbstractDubboTraceChainTest {
1919
protected InstrumentationExtension testing() {
2020
return testing;
2121
}
22+
23+
@Override
24+
protected boolean hasPeerService() {
25+
return true;
26+
}
2227
}

instrumentation/apache-dubbo-2.7/library-autoconfigure/src/test/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@ class DubboTest extends AbstractDubboTest {
1818
protected InstrumentationExtension testing() {
1919
return testing;
2020
}
21+
22+
@Override
23+
protected boolean hasPeerService() {
24+
return false;
25+
}
2126
}

0 commit comments

Comments
 (0)