Skip to content

Core Library

Arnab Nandy edited this page Sep 3, 2026 · 1 revision

Core Library

The core module creates deterministic failure identities without Spring, SLF4J, Micrometer, or a database.

See Core vs Spring Boot starter for a feature-by-feature comparison of availability, bean registration, and automatic behavior.

Fingerprint Generation

try {
    userRepository.findById(userId);
} catch (RuntimeException failure) {
    Fingerprint fingerprint = BugDna.generate(failure);
    System.out.println(fingerprint.getId());
    System.out.println(fingerprint.getSignature());
}

BugDNA uses the deepest cause, exception type, and up to five normalized stack frames. Exception messages and line numbers are excluded so changing input values or nearby source lines does not fragment a failure group.

For example, failures containing "user 17" and "user 42" receive the same ID when they have the same exception type and normalized call path. Changing UserService#getUser to UserService#loadUser can produce a new ID.

Fingerprint Data

Method Description
getId() Stable BUGDNA-* identifier
getRootCause() Fully qualified deepest exception type
getSignature() Simple origin in Class#method form
getQualifiedSignature() Fully qualified origin
getFrames() Normalized frames used for grouping
getFailureChain() Simplified application call chain
getCauseChain() Outer-to-inner exception types
getExplanation() Detailed grouping explanation
getStabilityScore() Stability confidence from 0 to 100
getPriority() Impact-based priority
getCategory() Broad failure category
getFamily() Operational root-cause family
explain() Compact multi-line report

Fingerprint Knowledge Base

Use a small YAML file to turn stable fingerprint IDs into operational context:

BUGDNA-001:
  title: Database Pool Exhaustion
  owner: Platform Team
  runbook: runbooks/db-pool.md

Then look it up by ID:

FingerprintKnowledge context = BugDna.lookup("BUGDNA-001");

System.out.println(context.getTitle());
System.out.println(context.getOwner());
System.out.println(context.getRunbook());

BugDna.lookup(...) lazily reads the first available default file from the working directory: bugdna.yml, bugdna.yaml, bugdna-fingerprints.yml, or bugdna-fingerprints.yaml. Set -Dbugdna.knowledge.path=/path/to/file.yml to use a specific file, or call BugDna.loadKnowledgeBase(path) during startup.

Additional scalar fields are preserved:

BUGDNA-001:
  title: Database Pool Exhaustion
  owner: Platform Team
  runbook: runbooks/db-pool.md
  dashboard: https://example.test/dashboards/db
System.out.println(context.get("dashboard"));

Priority Context

Without operational context, priority is UNKNOWN.

FailureContext context = FailureContext.of(
        125,
        18,
        false
);

Fingerprint fingerprint = BugDna.generate(exception, context);
System.out.println(fingerprint.getPriority());

The example prints HIGH: 125 occurrences or 18 affected users independently meet the high-priority threshold.

Priority thresholds:

Priority Condition
CRITICAL Fatal, at least 100 affected users, or at least 1000 occurrences
HIGH At least 10 affected users or at least 100 occurrences
MEDIUM At least one affected user or at least 10 occurrences
LOW Context supplied below the medium thresholds
UNKNOWN No context supplied

Categories

BugDNA classifies root-cause exception names into:

  • DATABASE
  • NETWORK
  • VALIDATION
  • SECURITY
  • SERIALIZATION
  • CONFIGURATION
  • BUSINESS
  • UNKNOWN

Classification is heuristic and should be treated as operational metadata, not a replacement for domain-specific exception handling.

Root-Cause Families

Families cluster different fingerprint IDs that point to the same operational problem. For example, database connection refusal, socket timeout, and connection pool exhaustion can all be classified as DATABASE_CONNECTIVITY.

Fingerprint fingerprint = BugDna.generate(failure);
System.out.println(fingerprint.getFamily());

Family classification can use exception types, cause names, normalized frames, and message keywords. Messages remain excluded from the fingerprint hash, so family classification does not change BUGDNA-* identity.

Similarity

Similarity result = BugSimilarity.compare(first, second);

System.out.println(result.getPercentage());
System.out.println(result.isLikelyRelated());
System.out.println(result.getExplanation());

isLikelyRelated() returns true at 80 percent or higher.

Deployment Regression Detection

Compare the unique fingerprints observed in two deployed versions:

DeploymentSnapshot previous = new DeploymentSnapshot(
        "1.2.0",
        previousFingerprints
);
DeploymentSnapshot current = new DeploymentSnapshot(
        "1.3.0",
        currentFingerprints
);

DeploymentComparison comparison = RegressionDetector.compare(previous, current);
System.out.println(comparison.report());
Version 1.2.0 -> Version 1.3.0

New fingerprints: 4
Resolved fingerprints: 12
Recurring fingerprints: 8

Snapshots deduplicate fingerprints by ID. A fingerprint is:

  • New when it appears only in the newer deployment
  • Resolved when it appears only in the older deployment
  • Recurring when it appears in both deployments

Occurrence-count changes do not change these classifications.

Use similarity when IDs differ but a refactor may have moved or renamed the same failure:

if (result.isLikelyRelated()) {
    System.out.println("Review as one failure family");
}

Diffs

FingerprintDiff diff = BugDiff.compare(oldException, newException);

System.out.println(diff.getSummary());
System.out.println(diff.explain());

Diffs highlight changes such as origin class, method, root cause, repository layer, or normalized call path.

Example:

Method Changed

Old:
getUser

New:
loadUser

Error Handling

Public generation and comparison methods reject null. FailureContext.of(...) rejects negative counts.


Core vs Spring Boot Starter · Wiki home · Failure Tracking

Clone this wiki locally