Skip to content

Commit 43465be

Browse files
committed
Fix Fingerprinter thread safety
Create MessageDigest instance each time we are fingerprinting
1 parent 4c58087 commit 43465be

1 file changed

Lines changed: 98 additions & 15 deletions

File tree

  • dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/Fingerprinter.java

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,31 @@
44

55
import com.datadog.debugger.util.ClassNameFiltering;
66
import java.security.MessageDigest;
7+
import java.security.NoSuchAlgorithmException;
78
import org.slf4j.Logger;
89
import org.slf4j.LoggerFactory;
910

1011
/** Computes a fingerprint of an exception based on its stacktrace and exception type. */
1112
public class Fingerprinter {
1213
private static final Logger LOGGER = LoggerFactory.getLogger(Fingerprinter.class);
13-
private static MessageDigest digest;
14-
15-
static {
16-
try {
17-
digest = MessageDigest.getInstance("SHA-256");
18-
} catch (Throwable e) {
19-
LOGGER.debug("Unable to find digest algorithm SHA-256", e);
20-
}
21-
}
2214

2315
// compute fingerprint of the Throwable based on the stacktrace and exception type
2416
public static String fingerprint(Throwable t, ClassNameFiltering classNameFiltering) {
25-
if (digest == null) {
26-
return null;
27-
}
2817
t = getInnerMostThrowable(t);
2918
if (t == null) {
3019
LOGGER.debug("Unable to find root cause of exception");
3120
return null;
3221
}
3322
Class<? extends Throwable> clazz = t.getClass();
23+
MessageDigest digest;
24+
try {
25+
// need to create a new instance each time to make it thread safe
26+
// Regarding performance, see the results of micro-benchmarks at the end of the file
27+
digest = MessageDigest.getInstance("SHA-256");
28+
} catch (NoSuchAlgorithmException e) {
29+
LOGGER.debug("Unable to find digest algorithm SHA-256", e);
30+
return null;
31+
}
3432
String typeName = clazz.getTypeName();
3533
digest.update(typeName.getBytes());
3634
StackTraceElement[] stackTrace = t.getStackTrace();
@@ -45,11 +43,14 @@ public static String fingerprint(Throwable t, ClassNameFiltering classNameFilter
4543
}
4644

4745
public static String fingerprint(StackTraceElement element) {
48-
if (digest == null) {
46+
try {
47+
MessageDigest digest = MessageDigest.getInstance("SHA-256");
48+
digest.update(element.toString().getBytes());
49+
return bytesToHex(digest.digest());
50+
} catch (NoSuchAlgorithmException e) {
51+
LOGGER.debug("Unable to find digest algorithm SHA-256", e);
4952
return null;
5053
}
51-
digest.update(element.toString().getBytes());
52-
return bytesToHex(digest.digest());
5354
}
5455

5556
// convert byte[] to hex string
@@ -61,3 +62,85 @@ private static String bytesToHex(byte[] bytes) {
6162
return result.toString();
6263
}
6364
}
65+
66+
/*
67+
Micro benchmark results:
68+
jdk8 arm64:
69+
Benchmark Mode Cnt Score Error Units
70+
MessageDigestBenchmark.md5NewInstance avgt 5 4.974 ± 0.069 us/op
71+
MessageDigestBenchmark.md5ReuseInstance avgt 5 4.787 ± 0.137 us/op
72+
MessageDigestBenchmark.sha1NewInstance avgt 5 6.131 ± 0.038 us/op
73+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 6.088 ± 0.016 us/op
74+
MessageDigestBenchmark.sha256NewInstance avgt 5 7.090 ± 0.091 us/op
75+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 7.048 ± 0.132 us/op
76+
77+
jdk11 arm64:
78+
Benchmark Mode Cnt Score Error Units
79+
MessageDigestBenchmark.md5NewInstance avgt 5 5.258 ± 0.166 us/op
80+
MessageDigestBenchmark.md5ReuseInstance avgt 5 5.196 ± 0.053 us/op
81+
MessageDigestBenchmark.sha1NewInstance avgt 5 6.639 ± 0.136 us/op
82+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 6.522 ± 0.096 us/op
83+
MessageDigestBenchmark.sha256NewInstance avgt 5 7.600 ± 0.130 us/op
84+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 7.605 ± 0.115 us/op
85+
86+
jdk17 arm64:
87+
Benchmark Mode Cnt Score Error Units
88+
MessageDigestBenchmark.md5NewInstance avgt 5 3.749 ± 0.054 us/op
89+
MessageDigestBenchmark.md5ReuseInstance avgt 5 3.713 ± 0.061 us/op
90+
MessageDigestBenchmark.sha1NewInstance avgt 5 5.708 ± 0.079 us/op
91+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 5.646 ± 0.070 us/op
92+
MessageDigestBenchmark.sha256NewInstance avgt 5 8.668 ± 0.073 us/op
93+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 8.651 ± 0.131 us/op
94+
95+
jdk21 arm64:
96+
Benchmark Mode Cnt Score Error Units
97+
MessageDigestBenchmark.md5NewInstance avgt 5 2.702 ± 0.023 us/op
98+
MessageDigestBenchmark.md5ReuseInstance avgt 5 2.675 ± 0.018 us/op
99+
MessageDigestBenchmark.sha1NewInstance avgt 5 0.818 ± 0.005 us/op
100+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 0.798 ± 0.035 us/op
101+
MessageDigestBenchmark.sha256NewInstance avgt 5 0.814 ± 0.018 us/op
102+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 0.792 ± 0.017 us/op
103+
104+
jdk21 arm64 -XX:+UnlockDiagnosticVMOptions -XX:-UseSHA1Intrinsics -XX:-UseSHA256Intrinsics
105+
Benchmark Mode Cnt Score Error Units
106+
MessageDigestBenchmark.sha1NewInstance avgt 5 5.030 ± 0.041 us/op
107+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 5.121 ± 0.090 us/op
108+
MessageDigestBenchmark.sha256NewInstance avgt 5 7.677 ± 0.089 us/op
109+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 7.627 ± 0.065 us/op
110+
111+
jdk8 x86_64:
112+
Benchmark Mode Cnt Score Error Units
113+
MessageDigestBenchmark.md5NewInstance avgt 5 4.435 ± 0.166 us/op
114+
MessageDigestBenchmark.md5ReuseInstance avgt 5 4.364 ± 0.206 us/op
115+
MessageDigestBenchmark.sha1NewInstance avgt 5 5.966 ± 0.224 us/op
116+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 5.901 ± 0.349 us/op
117+
MessageDigestBenchmark.sha256NewInstance avgt 5 9.220 ± 0.667 us/op
118+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 9.162 ± 0.860 us/op
119+
120+
jdk11 x86_64:
121+
Benchmark Mode Cnt Score Error Units
122+
MessageDigestBenchmark.md5NewInstance avgt 5 4.716 ± 0.233 us/op
123+
MessageDigestBenchmark.md5ReuseInstance avgt 5 4.662 ± 0.258 us/op
124+
MessageDigestBenchmark.sha1NewInstance avgt 5 1.444 ± 0.066 us/op
125+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 1.396 ± 0.060 us/op
126+
MessageDigestBenchmark.sha256NewInstance avgt 5 1.533 ± 0.054 us/op
127+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 1.494 ± 0.052 us/op
128+
129+
jdk17 x86_64:
130+
Benchmark Mode Cnt Score Error Units
131+
MessageDigestBenchmark.md5NewInstance avgt 5 2.852 ± 0.191 us/op
132+
MessageDigestBenchmark.md5ReuseInstance avgt 5 2.816 ± 0.086 us/op
133+
MessageDigestBenchmark.sha1NewInstance avgt 5 1.329 ± 0.051 us/op
134+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 1.363 ± 0.238 us/op
135+
MessageDigestBenchmark.sha256NewInstance avgt 5 1.397 ± 0.133 us/op
136+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 1.391 ± 0.047 us/op
137+
138+
jdk22 x86_64:
139+
Benchmark Mode Cnt Score Error Units
140+
MessageDigestBenchmark.md5NewInstance avgt 5 4.757 ± 0.179 us/op
141+
MessageDigestBenchmark.md5ReuseInstance avgt 5 4.689 ± 0.300 us/op
142+
MessageDigestBenchmark.sha1NewInstance avgt 5 1.460 ± 0.049 us/op
143+
MessageDigestBenchmark.sha1ReuseInstance avgt 5 1.423 ± 0.066 us/op
144+
MessageDigestBenchmark.sha256NewInstance avgt 5 1.567 ± 0.123 us/op
145+
MessageDigestBenchmark.sha256ReuseInstance avgt 5 1.521 ± 0.084 us/op
146+
*/

0 commit comments

Comments
 (0)