Class StackTraceNormalizer

java.lang.Object
com.tnsai.observability.errors.StackTraceNormalizer

public final class StackTraceNormalizer extends Object
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_FRAMES relevant frames for the digest. Full trace still goes in the fullStackTrace field of ErrorReport.
Since:
0.5.0 (issue #86)
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    Maximum number of normalized frames included in the digest input.
  • Method Summary

    Modifier and Type
    Method
    Description
    static String
    Compute a SHA-256 digest of the normalized stack trace, truncated to 16 hex chars (64 bits).
    static String
    digestOf(String normalizedStack)
    Digest of an already-normalized stack string.
    static String
    Normalize a throwable's stack trace into a stable string form.

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • MAX_FRAMES

      public static final int MAX_FRAMES
      Maximum number of normalized frames included in the digest input.
      See Also:
  • Method Details

    • normalize

      public static String normalize(Throwable t)
      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 at MAX_FRAMES frames
    • digest

      public static String digest(Throwable t)
      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

      public static String digestOf(String normalizedStack)
      Digest of an already-normalized stack string. Exposed so callers can cache the normalize(Throwable) result and fingerprint cheaply.