A JFR recording captures enabled events during a defined interval, allowing an incident review to correlate operation outcomes with runtime observations.
Java JFR incident evidence: outcome events and failure counts
Java 11+. The program uses JDK classes and requires no preview flags.
Record the operation boundary
A file-import operation should report success or failure at the boundary where that result becomes known. Recording only successful imports hides failed work from the incident timeline. The custom event below records an outcome in finally, including the rejected branch.
Keep event fields small and intentional. Counts and phase labels can be useful without storing full input lines, credentials or user payloads. Stack traces and event thresholds also affect what the recording contains; a missing event does not prove that no operation was attempted.
The program owns a short recording, commits two operation events, dumps the recording and reads it back. It counts successful and failed outcomes independently. That checks the capture and consumption path instead of merely printing a recording file name.
Compare a defined interval
For an incident, write down which JVM, workload and recording interval produced the artifact. CPU sampling, allocations, lock contention and application events answer different questions. A short synthetic fixture can validate event plumbing, but its counts and durations are not a production latency distribution.
Working program
import jdk.jfr.*;
import jdk.jfr.consumer.*;
import java.nio.file.*;
@Name("in.aitrove.ImportOutcome")
class ImportOutcome extends Event {boolean success;int rows;}
public class ImportOutcomeRecording {
static void importRows(int rows,boolean reject){
ImportOutcome event=new ImportOutcome();event.begin();
try{if(reject)throw new IllegalArgumentException("Rejected rows");event.rows=rows;event.success=true;}
catch(IllegalArgumentException failed){event.success=false;}
finally{event.end();event.commit();}
}
public static void main(String[] args)throws Exception{
Path file=Files.createTempFile("aitrove-outcomes-",".jfr");
try(Recording recording=new Recording()){
recording.enable(ImportOutcome.class).withStackTrace();recording.start();importRows(4,false);importRows(0,true);recording.stop();recording.dump(file);
int accepted=0,rejected=0;
try(RecordingFile events=new RecordingFile(file)){
while(events.hasMoreEvents()){RecordedEvent event=events.readEvent();if(event.getEventType().getName().equals("in.aitrove.ImportOutcome")){if(event.getBoolean("success"))accepted++;else rejected++;}}
}System.out.println("accepted="+accepted+", rejected="+rejected);
}finally{Files.deleteIfExists(file);}
}
}Output
accepted=1, rejected=1Costs and boundaries
Recorded volume grows with the enabled event rate and fields. Stack traces and event settings have their own cost. This fixture checks two events, not JFR overhead under production load, and the finally block cleans its own temporary file.
Common Mistakes
- Success-only events omit the failure side of an incident.
- Thresholds and settings can suppress observations.
- A synthetic recording is not a production performance conclusion.
