Recording an application with LR4J

Record environment

A Linux test or staging environment with your application and test case set up, running under OpenJDK 8, 11 or 12 on RHEL, CentOS, Debian, Ubuntu, SuSE or Fedora.

  • JDK and its debug symbols installed. If using distro-supplied versions of JDK:

    • RHEL/CentOS: java-1.8.0-openjdk-headless java-1.8.0-openjdk-devel packages and $ sudo dnf debuginfo-install java-1.8.0-openjdk-headless or java-11-openjdk-headless java-11-openjdk-devel packages, and $ sudo dnf debuginfo-install java-11-openjdk-headless.
    • Debian/Ubuntu: openjdk-8-jdk-headless openjdk-8-dbg or openjdk-11-jdk-headless openjdk-11-dbg packages.
  • The ability to copy the LiveRecorder software into that environment.

  • If the environment is a container:
    You have access to the container build environment to modify the java command-line arguments that launch the application.
    The container needs to have a VOLUME bind mount set up so the recording can be saved or copied out of the container.

Generating a recording

Unzip the file lr4j-record-*.zip. This contains the LiveRecorder recording agent lr4j-record-1.0.so.

Edit the command-line used to launch Java (either in the service/ant/mvn/gradle/Jenkins config or, if running an application direct from the IDE on Linux, in the IDE Run/Debug configuration) to add the following arguments to the java command-line.

-XX:-Inline -XX:TieredStopAtLevel=1 -XX:UseAVX=2 -Dsun.zip.disableMemoryMapping=true -agentpath:/path/to/lr4j-record-1.0.so=save_on=always

See below for advice specific to recording Recording a systemd service services or test runs under Integration with Test Frameworks.

Recording filename

The recording file is saved out to disk at application exit. By default the recording file is saved in the application’s current working directory and named after the main Java class plus the current date/time. To set the filename explicitly choose one of the following:

  • Add an output parameter on the Java command-line. e.g.:

    -agentpath:/path/to/lr4j-record-1.0.so=save_on=always,output=/path/to/recording.undo
    

This is useful when recording an application/service and you want the recording file saved to a specific directory.

  • In your application code set the Java system property io.undo.output at any point prior to application exit. e.g.:

    System.setProperty("io.undo.output", "/path/to/recording.undo");
    

If both the output command-line parameter and io.undo.output system property are specified the command-line argument wins. The output directory must already exist and be writable by the application’s UID/GID. If you don’t specify a fully qualified file name the recording file will be saved relative to the application’s current working directory.

When to save a recording

Adjust the save_on parameter to control the conditions under which a recording is generated:

  • save_on=always : Generate a recording at application exit.
    To force the application to exit and generate a recording use ^C, kill <application_PID> (note: not kill -9)
    or, if the application is running as a Systemd service, sudo systemctl stop <service>.
  • save_on=failure : Generate a recording at application exit only if the application/test exits with a non-zero status from System.exit().
    This is useful for recording failing tests within a CI system.
  • save_on=success : Generate a recording at application exit only if the application/test exits with a zero status from System.exit().

  • save_on omitted : Generate a recording under application control.
    Include lr4j_api.jar and add calls in your application code to the LiveRecorder API to start recording, save out a recording file, and stop recording:
    import io.undo.lr.UndoLR;
    UndoLR.start();
    UndoLR.save(String filename);
    UndoLR.stop();
    

Recording size

By default, LiveRecorder uses 1GB of system RAM while capturing the recording for an “event log”. You can increase this with the max_event_log_size parameter. e.g. to set the “event log” to 2GB:

-agentpath:/path/to/lr4j-record-1.0.so=save_on=always,max_event_log_size=2G

The larger the “event log” size, the further back in time from the end of the recording that you will be able to replay.

Generating a recording - examples

Recording a systemd service

In the [Service] section of the .service configuration file:

  • Modify ExecStart to add the following arguments to the java command-line:

    ExecStart=/usr/bin/java -XX:-Inline -XX:TieredStopAtLevel=1 -XX:UseAVX=2
    -Dsun.zip.disableMemoryMapping=true -agentpath:/path/to/lr4j-record-1.0.so=save_on=always,
    output=/path/to/recording.undo <application_arguments>
    
  • Add a KillMode=process option to prevent systemd prematurely killing LiveRecorder on service shutdown.

  • For very large applications it may be necessary to increase TimeoutStopSec beyond its default of 60 or 90 seconds to allow time for LiveRecorder to write the recording out to disk.

If the [Service] section contains a User option specifying that the service is to run as a user other than root, check that the path to the recording file is writable by that user. e.g:

sudo -u <user> touch /path/to/recording.tmp
To stop the service and write out the recording, use either of these two commands:
  • sudo systemctl stop <service>
  • kill <application_PID> (note: not kill -9)