14 Filter Events with SettingDefinition

The example FilteringSample.java (along with RegExpControl.java) uses a SettingDefinition to filter which events Flight Recorder records. In this example, it records Hello events that have a value that starts with g in its message field.

import java.io.IOException;

import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.Recording;
import jdk.jfr.SettingDefinition;

public class FilteringSample {

    @Name("com.oracle.FilteredHello")
    @Label("Hello With Message Filter")
    static class FilteredHello extends Event {
        @Label("Message")
        String message;

        @Label("Message Filter")
        @Description("Filters messages with regular expressions")
        @SettingDefinition
        protected boolean messageFilter(RegExpControl control) {
            return control.matches(message);
        }
    }

    public static void main(String[] args) throws IOException {

        try (Recording r = new Recording()) {
            r.enable(FilteredHello.class).with("messageFilter", "g.*");
            r.start();
            FilteredHello greenEvent = new FilteredHello();
            FilteredHello yellowEvent = new FilteredHello();
            FilteredHello redEvent = new FilteredHello();
            greenEvent.message = "green";
            yellowEvent.message = "yellow";
            redEvent.message = "red";
            greenEvent.commit();
            yellowEvent.commit();
            redEvent.commit();
        }
    }
}

The example FilteringSample requires RegExpControl.java:

import java.util.Set;
import java.util.regex.Pattern;

import jdk.jfr.SettingControl;

public class RegExpControl extends SettingControl {

    private Pattern pattern = Pattern.compile(".*");

    @Override
    public void setValue(String value) {
        this.pattern = Pattern.compile(value);
    }

    @Override
    public String combine(Set<String> values) {
        return String.join("|", values);
    }

    @Override
    public String getValue() {
        return pattern.toString();
    }

    public boolean matches(String s) {
        return pattern.matcher(s).find();
    }
}

Compile FilteringSample.java and RegExpControl.java, then run FilteringSample with the following commands:

java -XX:StartFlightRecording:filename=filteringsample.jfr FilteringSample
jfr print --events FilteredHello filteringsample.jfr

The last command prints output similar to the following:

com.oracle.FilteredHello {
  startTime = 23:38:28.364
  message = "green"
  ...
}

The annotation @SettingDefinition specifies which method Flight Recorder calls to determine whether it records a particular event. In this example, it calls messageFilter(RegExpControl):

@SettingDefinition
protected boolean messageFilter(RegExpControl control) {
    return control.matches(message);
} 

This method's parameter, RegExpControl, extends the class SettingControl. In this example, RegExpControl.java implements a regular expression setting control; the method matches(String) returns true when its string matches the field pattern (which an application can change with the setValue(String) method).

The methods setValue(), getValue() and combine(Set<String>) methods are invoked when a setting value changes, which typically happens when a recording is started or stopped. The combine(Set<String>) method is invoked to resolve what value to use when multiple recordings are running at the same time.