Package com.tnsai.observability.errors
Class StackTraceNormalizer
java.lang.Object
com.tnsai.observability.errors.StackTraceNormalizer
Stack-trace normalization for stable error fingerprinting.
The goal: two errors that share the same code path should get the same digest, even across JVM restarts and across instances of dynamic artifacts (lambdas, generated proxies). Conversely, two errors hitting different code paths should get different digests.
Normalization rules
- Keep: class names, method names, file names, line numbers. Line numbers are intentionally part of the digest — a code change that shifts a line is a meaningful signal that the bug surface changed; alerts re-fire as a new fingerprint.
- Strip: lambda capturing-class hashes
(
Foo$$Lambda$42/0x0000000800abc123→Foo$$Lambda). These hashes change every JVM restart and would otherwise prevent any lambda-containing trace from ever matching itself. - Strip: generated proxy class numeric suffixes
(
$Proxy42→$Proxy). - Collapse: framework noise frames (java.base, jdk., sun.,
Jackson, OkHttp internals) — keep at most the top
MAX_FRAMESrelevant frames for the digest. Full trace still goes in thefullStackTracefield ofErrorReport.
- Since:
- 0.5.0 (issue #86)
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intMaximum number of normalized frames included in the digest input. -
Method Summary
-
Field Details
-
MAX_FRAMES
public static final int MAX_FRAMESMaximum number of normalized frames included in the digest input.- See Also:
-
-
Method Details
-
normalize
Normalize a throwable's stack trace into a stable string form. The output is suitable for hashing and is human-readable.- Parameters:
t- the throwable; must not be null- Returns:
- one frame per line in the form
"Class.method(File.java:42)"; lambda hashes / proxy suffixes stripped; noise frames omitted; capped atMAX_FRAMESframes
-
digest
Compute a SHA-256 digest of the normalized stack trace, truncated to 16 hex chars (64 bits). Truncation is fine — collision risk for an error tracker corpus of even 10^8 distinct fingerprints is negligible (~5 × 10⁻⁵ via the birthday bound) and the short form fits in Prometheus labels and dashboard URLs. -
digestOf
Digest of an already-normalized stack string. Exposed so callers can cache thenormalize(Throwable)result and fingerprint cheaply.
-