- C++ 11
- Java 8
- make
- maven
- Navigate to recordagent folder
- Run
make all
command
- Navigate to replayagent folder
- Run
make all
command
- Run
mvn clean install
Once the build is completed you need to configure the record agent, this can be done through config.json file and the file should be in the same place the agent is. Below is a sample configuration.
{
"logFileName": "record.log",
"logFileMaxSize": 100000,
"maxLogFiles": 2,
"recordDumpLocation":"",
"delayedStart":5000,
"recordCallerSnapshot": true,
"blacklistPackages":["java/lang","sun/reflect","java/util", "java/io"],
"rules": [
{
"method": "com/example/Test::MethodHasBug(IILjava/lang/String;)Ljava/lang/String;",
"exception": "java.lang.NullPointerException",
"additivity": false,
"exitOnException": true,
"threadsToMonitor" :1,
"depth":2,
"history":10,
"threadsToRecord":10
}
]
}
Configurations    | Usage                                                                                                                                                                                                     |
---|---|
logFileName      | Name of the log file which will be generated by record agent.                                                                                                                                                                        |
logFileMaxSize    | Maximum log file size in bytes                                                                                                                                                                                         |
maxLogFiles      | Maximum log files                                                                                                                                                                                               |
recordDumpLocation  | Record dump location, if empty dump will be generated in the same location agent is present.                                                                                                                                                        |
delayedStart     | Delay start the record value in milliseconds                                                                                                                                                                                  |
recordCallerSnapshot | True if you want to record 'this' object also, This is useful when method execution updating instance variables. Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
blacklistPackages   | List of packages you want to blacklist                                                                                                                                                                                     |
rules         | Limited feature, currently only one rule is executed.                                                                                                                                                                             |
method        | Method name you want to record. Type : className::methodName(args)returnType Note '.' (dot) should be replaced with '/' (slash). More info refer : https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html                                                                                    |
exception       | Exception if you are looking for, useful when the issue is intermittent. Exception should be given in fully qualified java name, ex: java.lang.NullPointerException                                                                                                                     |
additivity      | Not Implemented                                                                                                                                                                                              |
exitOnException    | True if you want to exit immediately after the exception is caught. Else false.                                                                                                                                                                |
threadsToMonitor   | Default is 1 Don't change the value                                                                                                                                                                                    |
depth         | Maximum depth you want to record. methodA() is at depth 1 and methodB() is at depth 2, methodC() is not recorded its return value will be impersonated. This is useful if you don't bother about a particular function at certain depth. Ex: DB call, Network Call. You are only interested in the return value.         |
history        | 1. '0' only records one iteration which satisfies the rule 2. positive value, ex 10, 20, etc. Records the number of iteration provided. 3. A negative value, ex -10. This is like a sliding window where new records are added and previous records are discarded. This is useful when you are looking for an exception. exitOnException must be set to true else the recording process will never be completed.  |
threadsToRecord    | A Total number of threads to record in a multi-threaded environment. Suppose if the system has 10 threads and the value provided is 3, Only first 3 threads that execute the method will be allowed now and also in the future.                                                                                             |
Consider a simple java code, where I want to record a methodA(long time) execution. I will configure my record agent to record 3 iterations with below config values.
"method": "Dummy::methodA(J)I",
"exception": "",
"additivity": false,
"exitOnException": false,
"threadsToMonitor" :1,
"depth":2,
"history":3,
"threadsToRecord":1
class Dummy
{
int methodA(long time)
{
String sTime = String.valueOf(time);
int val = methodB(sTime);
return val-1;
}
int methodB(String s)
{
int x = methodC().length();
return s.length()-x;
}
String methodC()
{
String x = "hello world";
return x;
}
}
public class TestClass
{
public static void main(String[] args)
{
Dummy d = new Dummy();
for(int i=0; i<30; i++)
{
try {Thread.sleep(1000);} catch(Exception ex) {}
d.methodA(System.currentTimeMillis());
}
}
}
Once done, Start a program with the below command.
export LD_LIBRARY_PATH=<path/to/record/agent/so/file>
java -cp recordreplay-0.0.1-SNAPSHOT-jar-with-dependencies.jar:**TestClass class file path** -agentlib:recordagent TestClass
Post this you will see a dump file generated with the name recordDump-.dmp which can be passed as input during replay mode.
Run the following command to start the tool in replay mode.
export LD_LIBRARY_PATH=<path/to/replay/agent/so/file>
java -agentlib:replayagent -cp recordreplay-0.0.1-SNAPSHOT-jar-with-dependencies.jar:**TestClass class file path** com.rr4j.replay.Replay --dumpFile recordDump.dmp
You will see an interactor, you can also add -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
to start the debugger and attach an IDE.
To list all records use '-a' command
You can add a breakpoint in IDE and use '-rs recordIndex' to replay the particular record.
- Record thread state to provide a detailed breakdown, mimic race conditions.
- Lamda function support.
- Dynamic class support generated on the fly by ASM and other libraries.
- Support controlling execution flow, recording only the particular path through line numbers.