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