Skip to content

Commit 1280fcc

Browse files
amarzialimcculls
andauthored
Use resolved address for peer.hostname when available without hitting the cache (#8915)
* Use resolved address for peer.hostname when available without hitting the cache * Update dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/net/HostNameResolver.java Co-authored-by: Stuart McCulloch <[email protected]> --------- Co-authored-by: Stuart McCulloch <[email protected]>
1 parent c06ee54 commit 1280fcc

File tree

4 files changed

+120
-11
lines changed

4 files changed

+120
-11
lines changed

dd-java-agent/agent-bootstrap/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,11 @@ jmh {
6565
jmhVersion = '1.32'
6666
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
6767
}
68+
69+
project.afterEvaluate {
70+
tasks.withType(Test).configureEach {
71+
if (javaLauncher.get().metadata.languageVersion.asInt() >= 16) {
72+
jvmArgs += ['--add-opens', 'java.base/java.net=ALL-UNNAMED'] // for HostNameResolverForkedTest
73+
}
74+
}
75+
}

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/BaseDecorator.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import static datadog.trace.api.cache.RadixTreeCache.PORTS;
44
import static datadog.trace.api.cache.RadixTreeCache.UNSET_PORT;
5+
import static datadog.trace.bootstrap.instrumentation.java.net.HostNameResolver.hostName;
56

67
import datadog.context.ContextScope;
78
import datadog.trace.api.Config;
89
import datadog.trace.api.DDTags;
910
import datadog.trace.api.Functions;
10-
import datadog.trace.api.cache.DDCache;
11-
import datadog.trace.api.cache.DDCaches;
1211
import datadog.trace.api.cache.QualifiedClassNameCache;
1312
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
1413
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
@@ -40,8 +39,6 @@ public String apply(Class<?> clazz) {
4039
},
4140
Functions.PrefixJoin.of("."));
4241

43-
private static final DDCache<String, String> HOSTNAME_CACHE = DDCaches.newFixedSizeCache(64);
44-
4542
protected final boolean traceAnalyticsEnabled;
4643
protected final Double traceAnalyticsSampleRate;
4744

@@ -200,11 +197,4 @@ public CharSequence className(final Class<?> clazz) {
200197
String simpleName = clazz.getSimpleName();
201198
return simpleName.isEmpty() ? CLASS_NAMES.getClassName(clazz) : simpleName;
202199
}
203-
204-
private static String hostName(InetAddress remoteAddress, String ip) {
205-
if (null != ip) {
206-
return HOSTNAME_CACHE.computeIfAbsent(ip, _ip -> remoteAddress.getHostName());
207-
}
208-
return remoteAddress.getHostName();
209-
}
210200
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package datadog.trace.bootstrap.instrumentation.java.net;
2+
3+
import datadog.trace.api.cache.DDCache;
4+
import datadog.trace.api.cache.DDCaches;
5+
import datadog.trace.util.MethodHandles;
6+
import java.lang.invoke.MethodHandle;
7+
import java.net.InetAddress;
8+
9+
public final class HostNameResolver {
10+
private static final MethodHandle HOLDER_GET;
11+
private static final MethodHandle HOSTNAME_GET;
12+
13+
private static final DDCache<String, String> HOSTNAME_CACHE = DDCaches.newFixedSizeCache(64);
14+
15+
static {
16+
MethodHandle holderTmp = null, hostnameTmp = null;
17+
try {
18+
final ClassLoader cl = HostNameResolver.class.getClassLoader();
19+
final MethodHandles methodHandles = new MethodHandles(cl);
20+
21+
final Class<?> holderClass =
22+
Class.forName("java.net.InetAddress$InetAddressHolder", false, cl);
23+
holderTmp = methodHandles.method(InetAddress.class, "holder");
24+
if (holderTmp != null) {
25+
hostnameTmp = methodHandles.method(holderClass, "getHostName");
26+
}
27+
} catch (Throwable ignored) {
28+
holderTmp = null;
29+
} finally {
30+
if (holderTmp != null && hostnameTmp != null) {
31+
HOLDER_GET = holderTmp;
32+
HOSTNAME_GET = hostnameTmp;
33+
} else {
34+
HOLDER_GET = null;
35+
HOSTNAME_GET = null;
36+
}
37+
}
38+
}
39+
40+
private HostNameResolver() {}
41+
42+
static String getAlreadyResolvedHostName(InetAddress address) {
43+
if (HOLDER_GET == null) {
44+
return null;
45+
}
46+
try {
47+
final Object holder = HOLDER_GET.invoke(address);
48+
return (String) HOSTNAME_GET.invoke(holder);
49+
} catch (final Throwable ignored) {
50+
}
51+
return null;
52+
}
53+
54+
private static String fromCache(InetAddress remoteAddress, String ip) {
55+
if (null != ip) {
56+
return HOSTNAME_CACHE.computeIfAbsent(ip, _ip -> remoteAddress.getHostName());
57+
}
58+
return remoteAddress.getHostName();
59+
}
60+
61+
public static String hostName(InetAddress address, String ip) {
62+
final String alreadyResolved = getAlreadyResolvedHostName(address);
63+
if (alreadyResolved != null) {
64+
return alreadyResolved;
65+
}
66+
return fromCache(address, ip);
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package datadog.trace.bootstrap.instrumentation.java.net
2+
3+
import datadog.trace.test.util.DDSpecification
4+
5+
class HostNameResolverForkedTest extends DDSpecification {
6+
def "should directly get the hostname for already resolved address #address"() {
7+
given:
8+
def host = HostNameResolver.getAlreadyResolvedHostName(address)
9+
expect:
10+
host == expected
11+
where:
12+
address | expected
13+
new Inet4Address("test", InetAddress.getLocalHost().getAddress()) | "test"
14+
new Inet6Address("test", InetAddress.getLocalHost().getAddress()) | "test"
15+
}
16+
17+
def "should return null when directly get the address for unresolved #address"() {
18+
given:
19+
def host = HostNameResolver.getAlreadyResolvedHostName(address)
20+
expect:
21+
host == null
22+
where:
23+
address | _
24+
InetAddress.getByAddress(InetAddress.getLocalHost().getAddress()) | _
25+
new Inet6Address(null, InetAddress.getLocalHost().getAddress()) | _
26+
}
27+
28+
def "should use the cache for unresolved addresses"() {
29+
given:
30+
def inet1 = new Inet4Address(null, InetAddress.getLocalHost().getAddress())
31+
def inet2 = new Inet4Address(null, 0) // this will fail if a resolution will happen
32+
when:
33+
def address = new InetSocketAddress(inet1, 666)
34+
def host = HostNameResolver.hostName(address.getAddress(), "127.0.0.1")
35+
then:
36+
host != null
37+
when:
38+
address = new InetSocketAddress(inet2, 666)
39+
def host2 = HostNameResolver.hostName(address.getAddress(), "127.0.0.1")
40+
then:
41+
host == host2
42+
}
43+
}

0 commit comments

Comments
 (0)