4 Categories

With the @Category annotation, you can assign any number of categories to an event. Categories enable you to identify similar events that should be displayed together, for example, in a graph or a tree. Although you can assign any category to an event (a category is just a string), it's best to first determine your categories.

If there's a chance that two or more events can happen at the same time and in the same thread, even if their start and end times might be different, then they should belong to different categories to prevent overlap when they're represented in a graphical user interface.

For example, suppose that you want to monitor image uploads to a web server. You create an event named File Upload that begins when a user uploads a file and ends when an upload completes. For advanced diagnostics about image uploads, you create more detailed events named Image Read, Image Resize, and Image Write. During these detailed events, other low-level events occur, for example, Socket Read during Image Read and File Write during Image Write. In this example, the event File Upload would overlap the events Image Read, Image Resize, and Image Write, which means that the File Upload event might hide the detailed events in some event visualizers. The same issue might happen for Image Read and Socket Read, and Image Write and File Write.

To prevent event overlap, make sure that events that might overlap belong to different categories. The following diagram illustrates one categorization scheme that prevents event overlaps and how an event visualizer could display them:

Figure 4-1 Categorizing Concurrent Events to Prevent Overlaps

The surrounding text describes this image.

File Upload belongs to the category Upload. Image Read, Image Resize, and Image Write belong to the category Image Upload. Socket Read and File Write belong to the category Java Application.

The example CategoriesSample.java implements this categorization scheme and simulates the creation of events as illustrated in the figure:

import jdk.jfr.Category;
import jdk.jfr.DataAmount;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.Percentage;

public class CategoriesSample {

    public static final String PROGRAMMERS_GUIDE_SAMPLES =
        "Programmer's Guide Samples";
    public static final String UPLOAD = "Upload";
    public static final String IMAGE_UPLOAD = "Image Upload";
    public static final String JAVA_APPLICATION = "Java Application";

    @Name("com.oracle.FileUpload")
    @Label("File Upload")
    @Category({PROGRAMMERS_GUIDE_SAMPLES, UPLOAD})
    private static class FileUpload extends Event { }

    @Name("com.oracle.ImageRead")
    @Label("Image Read")
    @Category({PROGRAMMERS_GUIDE_SAMPLES, IMAGE_UPLOAD})
    private static class ImageRead extends Event {
        @DataAmount(DataAmount.BYTES)
        long bytesUploaded;
    }

    @Name("com.oracle.ImageResize")
    @Label("Image Resize")
    @Category({PROGRAMMERS_GUIDE_SAMPLES, IMAGE_UPLOAD})
    private static class ImageResize extends Event {
        @Percentage
        double scale;
    }

    @Name("com.oracle.ImageWrite")
    @Label("Image Write")
    @Category({PROGRAMMERS_GUIDE_SAMPLES, IMAGE_UPLOAD})
    private static class ImageWrite extends Event {
        @DataAmount(DataAmount.BYTES)
        long bytesWritten;
    }
    
    @Name("com.oracle.SocketRead")
    @Label("Socket Read")
    @Category({PROGRAMMERS_GUIDE_SAMPLES, JAVA_APPLICATION})
    private static class SocketRead extends Event {
        @DataAmount(DataAmount.BYTES)
        long bytesRead;
    }  
    
    @Name("com.oracle.FileWrite")
    @Label("File Write")
    @Category({PROGRAMMERS_GUIDE_SAMPLES, JAVA_APPLICATION})
    private static class FileWrite extends Event {
        @DataAmount(DataAmount.BYTES)
        long bytesWritten;
    }        

    public static void main(String... args) {
        FileUpload fu = new FileUpload();
        fu.begin();
        
        ImageRead ir = new ImageRead();
        ir.begin();
        ir.bytesUploaded = 2048;
        
        SocketRead sr1 = new SocketRead();
        sr1.begin();
        sr1.bytesRead = 1024;
        sr1.commit();
        
        SocketRead sr2 = new SocketRead();
        sr2.begin();
        sr2.bytesRead = 1024;
        sr2.commit();
        
        ir.commit();
        
        ImageResize irs = new ImageResize();
        irs.begin();
        irs.scale = 0.5;
        irs.commit();
        
        ImageWrite iw = new ImageWrite();
        iw.begin();
        iw.bytesWritten = 1024;
        
        FileWrite fw = new FileWrite();
        fw.begin();
        fw.bytesWritten = 1024;
        fw.commit();
        
        iw.commit();
        fu.commit();
    }
}

Run CategoriesSample with the following command:

java -XX:StartFlightRecording:filename=categoriessample.jfr CategoriesSample.java

Then, open categoriessample.jfr in JDK Mission Control. From the Event Types Tree in the Event Browser, find the events created by this sample in the category Programmer's Guide Samples:

Figure 4-2 JDK Mission Control Browser Displaying Events from CategoriesSample

Events generated by CategoriesSample displayed in the JDK Mission Control Event Browser

JDK Mission Control categorizes events based on their @Category attribute and lists them by their @Label attribute.