To access the latest features keep your code editor plug-in up to date.
appmap-agent is a Java agent JAR for recording AppMap Data of your code.
The AppMap Data Format includes code structure (packages, modules, classes, and methods), trace events (function calls, web services, RPC calls, SQL, parameters, return values, exceptions, etc), and code metadata (repo URL, commit SHA, etc). It’s more granular than a performance profile, but it’s less granular than a full debug trace. It’s designed to be optimal for understanding the design intent and structure of code and key data flows.
Supported JDK versions:
Supported Languages:
Other languages may work as well.
Supported frameworks:
If you find a problem, or use a framework or language we don't yet support, let us know in Slack!
If you’re using JetBrains IntelliJ IDEA, we recommend using run configurations to create AppMap Data.
Alternatively, you may record your tests with the AppMap Maven plugin.
Alternatively, you may record your tests with the AppMap Gradle plugin.
You can download the latest release of appmap-agent-<version>.jar from https://mvnrepository.com/artifact/com.appland/appmap-agent/latest.
Both the AppMap plugin for IntelliJ and the AppMap extension for VS Code automatically download
the latest the AppMap Java agent, and store it locally in $HOME/.appmap/lib/java/appmap.jar.
The recorder is run as a Java agent. Currently, it must be started along with
the JVM. This is done by passing the -javaagent argument to your
JVM when recording tests. For example:
$ java -javaagent:$HOME/.appmap/lib/java/appmap.jar -jar myapp.jar
Note that, when using the -jar option as described above, the -javaagent argument must come first. Otherwise, the agent will not be loaded.
appmap-java can automatically record and save an AppMap for each HTTP server request which it processes. This functionality is currently supported for applications built using Spring Boot, Servlet-stack web applications built using Spring Framework, and Spark Framework.
For Spring Boot and Spring Web Framework applications, appmap-java installs a ServletListener during initialization that will create recordings. The listener starts the recording before the servlet’s service method is called, and ends the recording once service returns.
For Spring Boot, appmap-java adds the listener when the Spring Application is initialized.
For Spring Web Framework, appmap-java adds the listener when Spring’s servlet container is initialized.
For Spark Framework, appmap-java wraps Sparks’ Handler with a HandlerWrapper that manages recording.
appmap-java supports the AppMap remote recording API.
This functionality is provided by the AppMap agent. It will hook into the Java servlets API, injecting the remote recording routes into the servlet chain.
Note Your application must be running in a servlet container (e.g. Tomcat, Jetty, etc.) for remote recording to work.
javaagent JVM argument:$ java -javaagent:$HOME/.appmap/lib/java/appmap.jar -jar target/*.jar
appmap-java can record an entire Java process from start to finish.
Set the Java system property appmap.recording.auto=true. You must set this system property as a JVM argument.
If you are using a graphical run configuration, add the option -Dappmap.recording.auto=true to the “VM options” field.
If you are running on the command line, add the option -Dappmap.recording.auto=true to the JVM CLI arguments.
Start your application with the AppMap agent enabled using one of these approaches:
javaagent JVM argument:$ java -javaagent:$HOME/.appmap/lib/java/appmap.jar -jar target/*.jar
Other related options such as appmap.recording.file and appmap.recording.name are also available. Consult the Configuration section for details.
You can use the Java function com.appland.appmap.record.Recording#record to record a specific span of code. With this method, you can control exactly what code is recorded, and where the recording is saved.
This code snippet illustrates how to use the record() function to record a block of code, and then write the AppMap Data to a file:
final Recorder recorder = Recorder.getInstance();
final MyClass myClass = new MyClass();
Recording recording = recorder.record(() -> {
for (int i = 0; i < 10; i++) {
myClass.myMethod();
}
});
StringWriter sw = new StringWriter();
recording.readFully(true, sw);
// Now write the recorded AppMap Data to a file. The file name should end in ".appmap.json".
try (PrintWriter out = new PrintWriter("runnable-recording.appmap.json")) {
out.println(sw.toString());
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
System.exit(1);
}
When you run your program, the agent reads configuration settings from
appmap.yml. Here’s a sample configuration file for a typical Java project:
# 'name' should generally be the same as the code repo name.
name: MyProject
language: java
appmap_dir: tmp/appmap
packages:
- path: com.mycorp.myproject
exclude: [ com.mycorp.myproject.MyClass#MyMethod ]
- path: org.springframework.web
shallow: true
exclude:
- org.springframework.web.util
- path: java.util.logging
methods:
- class: Logger
name: log
methods property to specify which methods to instrument.packages
Each entry in the packages list is a YAML object which has the following keys:
exclude A list of fully-qualified sub-packages, sub-classes
and sub-methods that will be ignored. The exclude list only applies to the
path specified in the same package entry.
shallow When set to true, only the first function call entry into a
package will be recorded. Subsequent function calls within the same package
are not recorded unless code execution leaves the package and re-enters it.
Default: false.
Each of the class and name regular expressions is a
java.util.regex.Pattern
. They
will be surrounded with \A( )\z to match whole symbols. This means, in the
example above, log will match exactly that method of Logger, but not the
logp or logrb methods. To match all three methods, use log(|p|rb) or
log.*. To include the literal symbols . or $ in the patterns, they must be
properly escaped: \. or \$.
If the methods attribute is specified for a package, each element in the list will be matched in the order specified, and only the matching methods will be instrumented. When the methods attribute is set, the exclude attribute is ignored.
The appmap-java annotations are provided in the package com.appland:appmap-annotation, available on Maven Central. To use them, add that package as a dependency in your build configuration file (pom.xml, build.gradle).
appmap-java supports the addition of code labels through the com.appland.appmap.annotation.Labels annotation.
Once the Labels annotation is available, you can apply it to methods in your application. For example:
import com.appland.appmap.annotation.Labels;
public class ExampleClass {
...
@Labels({"label1", "label2"})
public void labeledFunction() {
...
}
}
When labeledFunction appears in an AppMap, it will have the labels label1 and label2.
The NoAppMap annotation can be used to disable recording of JUnit test methods. If applied to a specific method, that method will not generate an AppMap. Alternatively, it can be applied to a test class to disable generation of AppMap Data for all test methods in the class.
Example of annotating a test method:
import com.appland.appmap.annotation.NoAppMap;
...
public class TestClass {
@Test
public void testMethod1() {
...
}
@NoAppMap
@Test
public void testMethod2() {
...
}
}
testMethod1 will generate an AppMap, and testMethod2 will not.
Example of annotating a test class:
import com.appland.appmap.annotation.NoAppMap;
...
@NoAppMap
public class UnrecordedTestClass {
@Test
public void testMethod1() {
...
}
@Test
public void testMethod2() {
...
}
}
No AppMap Data will be generated for the tests in UnrecordedTestClass.
appmap.config.file Path to the appmap.yml config file. Default:
appmap.yml
appmap.output.directory Output directory for .appmap.json files. Default:
./tmp/appmap
appmap.debug Enable debug logging. Default: null (disabled)appmap.event.valueSize Specifies the length of a value string before
truncation occurs. If set to 0, truncation is disabled. Default: 1024
appmap.record.private Record private methods, as well as methods with
package and protected access. Default: false (no private methods will be
recorded).appmap.recording.auto Automatically begin recording at boot time. Default:
false
appmap.recording.file The file name of the automatic recording to be
emitted. Note that the file name will still be prefixed byappmap.recording.requests If true, create a recording for each HTTP server request (for
supported frameworks). Default: true.
appmap.output.directory. Default: $TIMESTAMP.appmap.json
appmap.recording.name Populates the metadata.name field of the AppMap.
Default: $TIMESTAMP
java.lang.NoClassDefFoundError: com/appland/appmap/runtime/HookFunctions
In environments using Java application servers with modular class loading (such as WildFly, Tomcat, WebSphere, WebLogic, or GlassFish), you may encounter class visibility issues when using Java agents for instrumentation. The AppMap agent’s classes, loaded by the bootstrap class loader, may not be accessible to applications due to class loader isolation.
To resolve this, adjust your application server’s class loading configuration to expose the com.appland.appmap.runtime package to your applications. This typically involves adding the package name to a server-specific system property or placing the AppMap agent’s classes in a shared library directory.
For instance, in WildFly, you can add the com.appland.appmap.runtime package to the jboss.modules.system.pkgs system property:
-Djboss.modules.system.pkgs=org.jboss.byteman,com.appland.appmap.runtime
https://github.com/getappmap/appmap-java