Recording an application

Requirements

Your application or test case running under an OpenJDK-based or Oracle JRE on a supported Linux distribution.

  • JRE and its debug symbols installed:

    RHEL/CentOS/SuSE-supplied JRE:

    java-<N>-openjdk-headless package, where <N> is 1.8.0, 11 or 17.

    Debian/Ubuntu-supplied JRE:

    openjdk-<N>-jre-headless and openjdk-<N>-dbg packages, where <N> is 8, 11 or 17.

    Oracle, Azul Zulu, or other OpenJDK-based JRE:

    Debug symbols are included with the JRE download.

  • The ability to copy the Recording software into this 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 (e.g. in the service/ant/mvn/gradle/Jenkins configuration) to add the following arguments to the start of 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 a systemd service, or to recording test runs under Recording test failures.

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.

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. For example 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.

When to start recording

By default LiveRecorder starts recording as soon as the JVM starts. You can reduce your application startup time by telling LiveRecorder to delay starting recording until your application’s initialisation is complete. To assist with this there are two options:

  • verbose=true : Output the names of classes as they are loaded.
  • start_after_classload=classname : Only start recording once the named class has been loaded.
    The name should be a fully qualified class name such as org.springframework.boot.StartupInfoLogger.

Unless you already have a class name in mind, first run with verbose=true and wait until the application has completed initialisation. Pick a suitable class name and supply it to start_after_classload in subsequent runs. LiveRecorder will only start recording once the named class is loaded.

Alternatively, use the LiveRecorder API in your application to give you full programmatic control over when to start recording.

When to save a recording file

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 your application’s control using the LiveRecorder API.

The LiveRecorder API

The LiveRecorder API allows you to start and stop recording and save recording file(s) under your application’s control. This is useful if you want to record only those parts of your application’s execution or tests cases that are failing.

The API is provided by lr4j_api.jar and is supplied in LR4J-Record-*.zip. Include lr4j_api.jar in your project and add calls in your application code to the 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();

Refer to the Hands-on Undo GitHub project for an example of using the API in a Jakarta EE based microservice.

Refer to Recording test failures for examples of using the API in test.

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)

It will take a few seconds for systemd to stop the service and for LiveRecorder to write out the recording.