Skip to content

Commit 2b66505

Browse files
committed
Use resolved address for peer.hostname when available without hitting the cache
1 parent d8d6af0 commit 2b66505

File tree

3 files changed

+118
-11
lines changed

3 files changed

+118
-11
lines changed

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
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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+
final String alreadyResolved = HostNameResolver.getAlreadyResolvedHostName(remoteAddress);
56+
if (alreadyResolved != null) {
57+
return alreadyResolved;
58+
}
59+
if (null != ip) {
60+
return HOSTNAME_CACHE.computeIfAbsent(ip, _ip -> remoteAddress.getHostName());
61+
}
62+
return remoteAddress.getHostName();
63+
}
64+
65+
public static String hostName(InetAddress address, String ip) {
66+
final String alreadyResolved = getAlreadyResolvedHostName(address);
67+
if (alreadyResolved != null) {
68+
return alreadyResolved;
69+
}
70+
return fromCache(address, ip);
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package datadog.trace.bootstrap.instrumentation.java.net
2+
3+
import datadog.trace.test.util.DDSpecification
4+
5+
class HostNameResolverTest 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+
setup:
30+
def inet1 = Mock(InetAddress)
31+
def inet2 = Mock(InetAddress)
32+
when:
33+
def address = new InetSocketAddress(inet1, 666)
34+
def host = HostNameResolver.hostName(address.getAddress(), "127.0.0.1")
35+
then:
36+
host == "somehost"
37+
1 * inet1.getHostName() >> "somehost"
38+
when:
39+
address = new InetSocketAddress(inet2, 666)
40+
host = HostNameResolver.hostName(address.getAddress(), "127.0.0.1")
41+
then:
42+
0 * inet2.getHostName()
43+
host == "somehost"
44+
}
45+
}

0 commit comments

Comments
 (0)