No. FailureTracker and BugDnaFingerprintRepository keep data in application
memory only. BugDNA does not configure a database or write exception messages to
one.
To retain history, export the Micrometer gauges to a monitoring backend:
management.endpoints.web.exposure.include=health,prometheusThen scrape:
bugdna_failures_total
bugdna_unique_failures
The monitoring backend stores the time series; BugDNA itself still resets on restart.
No. All tracker counts, recent Actuator records, and BugDNA metrics restart from zero with the application.
For durable history, use one of these patterns:
String report = tracker.report();
auditLog.info("Daily BugDNA report:\n{}", report);or export the Micrometer metrics to Prometheus, Datadog, CloudWatch, or another monitoring system.
Record each exception in the same tracker:
FailureTracker tracker = new FailureTracker();
for (Throwable failure : failures) {
tracker.capture(failure);
}
System.out.println(tracker.report());Example result:
3 unique failure signatures
BUGDNA-001
Count: 421
BUGDNA-002
Count: 53
BUGDNA-003
Count: 26
Grouping uses the fingerprint ID, not the exception message.
Yes. Create one application-scoped instance and reuse it:
public final class FailureRegistry {
private static final FailureTracker TRACKER = new FailureTracker();
public static void record(Throwable failure) {
TRACKER.capture(failure);
}
public static String report() {
return TRACKER.report();
}
}A new tracker per exception will not aggregate counts.
Yes. Inject the starter-managed singleton:
@Component
class FailureSummary {
private final FailureTracker tracker;
FailureSummary(FailureTracker tracker) {
this.tracker = tracker;
}
String currentReport() {
return tracker.report();
}
}Automatic MVC captures and BugDnaSpringService.fingerprint(...) both update this
tracker.
Automatic capture covers unhandled MVC and WebFlux web exceptions only. Catch
background failures and pass them to BugDnaSpringService:
@Component
class InvoiceJob {
private final BugDnaSpringService bugDna;
InvoiceJob(BugDnaSpringService bugDna) {
this.bugDna = bugDna;
}
@Scheduled(fixedDelayString = "PT5M")
void run() {
try {
generateInvoices();
} catch (RuntimeException failure) {
Fingerprint fingerprint = bugDna.fingerprint(failure);
log.error("Invoice job failed [{}]", fingerprint.getId(), failure);
}
}
}The service updates both recent Actuator records and grouped tracker counts.
No. BugDna.generate(...) has no logging dependency and does not touch MDC.
The Spring starter adds MDC values only around its automatic exception log. To show the ID:
logging.pattern.console=%-5level [%X{bugdna}] %logger{36} - %msg%nNo. The MVC resolver records the exception and returns control to Spring. Existing
@ControllerAdvice, @ExceptionHandler, and default error responses continue to
work.
For example, this handler still owns the HTTP response:
@RestControllerAdvice
class ApiErrors {
@ExceptionHandler(OrderNotFoundException.class)
ResponseEntity<String> notFound(OrderNotFoundException failure) {
return ResponseEntity.status(404).body(failure.getMessage());
}
}No. Different messages group together when exception type and normalized frames are the same:
Fingerprint first = BugDna.generate(new IllegalArgumentException("user 17"));
Fingerprint second = BugDna.generate(new IllegalArgumentException("user 42"));
boolean sameGroup = first.getId().equals(second.getId());In real code, sameGroup is true only when the two exceptions also originate from
the same normalized call path.
No. Line numbers and file names are excluded. Moving the same method from line 20 to line 40 does not change its ID.
Changing the exception type, class, method, or normalized call path can create a new ID. Use this to explain a change:
FingerprintDiff diff = BugDiff.compare(previousFailure, currentFailure);
System.out.println(diff.explain());No. Adding the starter dependency is enough for Spring Boot auto-configuration:
<dependency>
<groupId>io.github.arnabnandy7</groupId>
<artifactId>bugdna-spring-boot-starter</artifactId>
<version>1.1.2</version>
</dependency>Use @EnableBugDna only when explicit imports are preferred.
Yes. The starter installs a reactive WebExceptionHandler when the application is
a WebFlux web application. Unhandled reactive errors are fingerprinted and logged,
then re-emitted so Spring continues normal error handling.
Scheduled jobs, message listeners, and errors handled inside the reactive chain still require explicit capture:
return operation()
.doOnError(bugDna::fingerprint)
.onErrorResume(this::recover);Use explicit capture when application code consumes the error before it reaches the global WebFlux exception chain.
System.out.println(tracker.topFailureReport());To request a smaller report:
System.out.println(tracker.topFailureReport(3));tracker.clear();This clears the core tracker only. It does not clear exported monitoring history or the starter's separate recent-record repository.