-
-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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.
| 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 |
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.mdThen 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/dbSystem.out.println(context.get("dashboard"));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 |
BugDNA classifies root-cause exception names into:
DATABASENETWORKVALIDATIONSECURITYSERIALIZATIONCONFIGURATIONBUSINESSUNKNOWN
Classification is heuristic and should be treated as operational metadata, not a replacement for domain-specific exception handling.
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 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.
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");
}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
Public generation and comparison methods reject null. FailureContext.of(...)
rejects negative counts.
← Core vs Spring Boot Starter · Wiki home · Failure Tracking →
BugDNA documentation · Home · Getting Started · API Reference · GitHub